<commit_before>package main

import (
	"encoding/hex"
	"net/http"
	"strconv"
	"strings"
	"text/template"

	"github.com/acityinohio/baduk"
	"github.com/blockcypher/gobcy"
)

type Gob struct {
	multi     string
	blackPK   string
	whitePK   string
	blackMove bool
	wager     int
	txskel    gobcy.TXSkel
	state     baduk.Board
}

const FEES = 9999

var templates = template.Must(template.ParseGlob("templates/*"))

//Keeping it all in memory
var boards map[string]*Gob
var bcy gobcy.API

func init() {
	boards = make(map[string]*Gob)
	bcy = gobcy.API{"TESTTOKEN", "bcy", "test"}
}

func main() {
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/games/", gameHandler)
	http.HandleFunc("/sign/", signHandler)
	http.HandleFunc("/new/", newGameHandler)
	http.ListenAndServe(":80", nil)
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	err := templates.ExecuteTemplate(w, "index.html", "")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func gameHandler(w http.ResponseWriter, r *http.Request) {
	multi := r.URL.Path[len("/games/"):]
	board, ok := boards[multi]
	if !ok {
		http.Error(w, "Game does not exist at that address", http.StatusInternalServerError)
		return
	}
	if r.Method == "POST" {
		moveHandler(w, r, board)
		return
	}
	type gameTemp struct {
		Multi     string
		PrettySVG string
		BlackMove bool
	}
	necessary := gameTemp{board.multi, board.state.PrettySVG(), board.blackMove}
	err := templates.ExecuteTemplate(w, "game.html", necessary)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func moveHandler(w http.ResponseWriter, r *http.Request, board *Gob) {
	//Get move, send transaction
	f := r.FormValue
	raw := f("orig-message")
	rawmove := strings.Split(raw, "-")
	if board.blackMove && rawmove[0] != "black" {
		http.Error(w, "Not black's turn", http.StatusInternalServerError)
		return
	}
	if !board.blackMove && rawmove[0] != "white" {
		http.Error(w, "Not white's turn", http.StatusInternalServerError)
		return
	}
	sendTXHandler(w, r, board, raw)
	return
}

func newGameHandler(w http.ResponseWriter, r *http.Request) {
	f := r.FormValue
	var board Gob
	var err error
	//Initialize Board
	sz, err := strconv.Atoi(f("size"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	wager, err := strconv.Atoi(f("wager"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	board.state.Init(sz)
	board.blackPK = f("blackPK")
	board.whitePK = f("whitePK")
	board.wager = wager
	board.blackMove = true
	//Generate Multisig Address for this board
	keychain, err := bcy.GenAddrMultisig(gobcy.AddrKeychain{PubKeys: []string{board.blackPK, board.whitePK}, ScriptType: "multisig-2-of-2"})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	board.multi = keychain.Address
	//Fund Multisig with Faucet (this can be improved!)
	//Put Multisig Address in Memory
	_, err = bcy.Faucet(gobcy.AddrKeychain{Address: board.multi}, wager)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	boards[board.multi] = &board
	//Setup Multisig Transaction with OP_RETURN(bitduckSIZE)
	sendTXHandler(w, r, &board, "bitduck"+f("size"))
	return
}

func sendTXHandler(w http.ResponseWriter, r *http.Request, board *Gob, raw string) {
	//Send MultiTX TX
	//note that api protections mean that OP_RETURN needs to burn at least 1 satoshi
	temptx, err := gobcy.TempMultiTX("", board.multi, board.wager-FEES-1, 2, []string{board.blackPK, board.whitePK})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	opreturn := buildNullData(raw)
	temptx.Outputs = append(temptx.Outputs, opreturn)
	temptx.Fees = FEES
	txskel, err := bcy.NewTX(temptx, false)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	board.txskel = txskel
	//Redirect to Sign Handler
	http.Redirect(w, r, "/sign/"+board.multi, http.StatusFound)
	return
}

func buildNullData(data string) (opreturn gobcy.TXOutput) {
	//set value to one
	opreturn.Value = 1
	//set script type
	opreturn.ScriptType = "null-data"
	//manually craft OP_RETURN byte array with ugly one-liner
	raw := append([]byte{106, byte(len([]byte(data)))}, []byte(data)...)
	opreturn.Script = hex.EncodeToString(raw)
	return
}

func signHandler(w http.ResponseWriter, r *http.Request) {
	multi := r.URL.Path[len("/sign/"):]
	board, ok := boards[multi]
	if !ok {
		http.Error(w, "Game does not exist at that address", http.StatusInternalServerError)
		return
	}
	if r.Method == "POST" {
		signPostHandler(w, r, board)
		return
	}
	type signTemp struct {
		Multi  string
		ToSign string
	}
	err := templates.ExecuteTemplate(w, "sign.html", signTemp{board.multi, board.txskel.ToSign[0]})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func signPostHandler(w http.ResponseWriter, r *http.Request, board *Gob) {
	f := r.FormValue
	board.txskel.Signatures = append(board.txskel.Signatures, f("blackSig"), f("whiteSig"))
	board.txskel.PubKeys = append(board.txskel.PubKeys, board.blackPK, board.whitePK)
	finTX, err := bcy.SendTX(board.txskel)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	board.txskel = finTX
	err = updateMove(board)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/game/"+board.multi, http.StatusFound)
	return
}

//update Board based on signed TX
func updateMove(board *Gob) (err error) {
	//find rawmove in OP_RETURN
	var raw string
	for _, v := range board.txskel.Trans.Outputs {
		if v.ScriptType == "pay-to-script-hash" {
			board.wager = v.Value
		}
		if v.DataString != "" {
			raw = v.DataString
		}
	}
	//decide what to do
	if strings.HasPrefix(raw, "bitduck") || raw == "gameover" {
		return
	}
	rawmove := strings.Split(raw, "-")
	xmove, _ := strconv.Atoi(rawmove[1])
	ymove, _ := strconv.Atoi(rawmove[2])
	if board.blackMove {
		err = board.state.SetB(xmove, ymove)
		if err != nil {
			return
		}
	} else if !board.blackMove {
		err = board.state.SetW(xmove, ymove)
		if err != nil {
			return
		}
	}
	if board.blackMove {
		board.blackMove = false
	} else {
		board.blackMove = true
	}
	board.txskel = gobcy.TXSkel{}
	return
}
<commit_msg>move handlers and fix awfully stupid typo<commit_after>package main

import (
	"encoding/hex"
	"net/http"
	"strconv"
	"strings"
	"text/template"

	"github.com/acityinohio/baduk"
	"github.com/blockcypher/gobcy"
)

type Gob struct {
	multi     string
	blackPK   string
	whitePK   string
	blackMove bool
	wager     int
	txskel    gobcy.TXSkel
	state     baduk.Board
}

const FEES = 9999

var templates = template.Must(template.ParseGlob("templates/*"))

//Keeping it all in memory
var boards map[string]*Gob
var bcy gobcy.API

func init() {
	boards = make(map[string]*Gob)
	bcy = gobcy.API{"TESTTOKEN", "bcy", "test"}
}

func main() {
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/games/", gameHandler)
	http.HandleFunc("/sign/", signHandler)
	http.HandleFunc("/new/", newGameHandler)
	http.ListenAndServe(":80", nil)
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	err := templates.ExecuteTemplate(w, "index.html", "")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func newGameHandler(w http.ResponseWriter, r *http.Request) {
	f := r.FormValue
	var board Gob
	var err error
	//Initialize Board
	sz, err := strconv.Atoi(f("size"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	wager, err := strconv.Atoi(f("wager"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	board.state.Init(sz)
	board.blackPK = f("blackPK")
	board.whitePK = f("whitePK")
	board.wager = wager
	board.blackMove = true
	//Generate Multisig Address for this board
	keychain, err := bcy.GenAddrMultisig(gobcy.AddrKeychain{PubKeys: []string{board.blackPK, board.whitePK}, ScriptType: "multisig-2-of-2"})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	board.multi = keychain.Address
	//Fund Multisig with Faucet (this can be improved!)
	_, err = bcy.Faucet(gobcy.AddrKeychain{Address: board.multi}, wager)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	//Put Multisig Address in Memory
	boards[board.multi] = &board
	//Setup Multisig Transaction with OP_RETURN(bitduckSIZE)
	sendTXHandler(w, r, &board, "bitduck"+f("size"))
	return
}

func sendTXHandler(w http.ResponseWriter, r *http.Request, board *Gob, raw string) {
	//Send MultiTX TX
	//note that api protections mean that OP_RETURN needs to burn at least 1 satoshi
	temptx, err := gobcy.TempMultiTX("", board.multi, board.wager-FEES-1, 2, []string{board.blackPK, board.whitePK})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	opreturn := buildNullData(raw)
	temptx.Outputs = append(temptx.Outputs, opreturn)
	temptx.Fees = FEES
	txskel, err := bcy.NewTX(temptx, false)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	board.txskel = txskel
	//Redirect to Sign Handler
	http.Redirect(w, r, "/sign/"+board.multi, http.StatusFound)
	return
}

func buildNullData(data string) (opreturn gobcy.TXOutput) {
	//set value to one
	opreturn.Value = 1
	//set script type
	opreturn.ScriptType = "null-data"
	//manually craft OP_RETURN byte array with ugly one-liner
	raw := append([]byte{106, byte(len([]byte(data)))}, []byte(data)...)
	opreturn.Script = hex.EncodeToString(raw)
	return
}

func signHandler(w http.ResponseWriter, r *http.Request) {
	multi := r.URL.Path[len("/sign/"):]
	board, ok := boards[multi]
	if !ok {
		http.Error(w, "Game does not exist at that address", http.StatusInternalServerError)
		return
	}
	if r.Method == "POST" {
		signPostHandler(w, r, board)
		return
	}
	type signTemp struct {
		Multi  string
		ToSign string
	}
	err := templates.ExecuteTemplate(w, "sign.html", signTemp{board.multi, board.txskel.ToSign[0]})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func signPostHandler(w http.ResponseWriter, r *http.Request, board *Gob) {
	f := r.FormValue
	board.txskel.Signatures = append(board.txskel.Signatures, f("blackSig"), f("whiteSig"))
	board.txskel.PubKeys = append(board.txskel.PubKeys, board.blackPK, board.whitePK)
	finTX, err := bcy.SendTX(board.txskel)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	board.txskel = finTX
	err = updateMove(board)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/games/"+board.multi, http.StatusFound)
	return
}

func gameHandler(w http.ResponseWriter, r *http.Request) {
	multi := r.URL.Path[len("/games/"):]
	board, ok := boards[multi]
	if !ok {
		http.Error(w, "Game does not exist at that address", http.StatusInternalServerError)
		return
	}
	if r.Method == "POST" {
		moveHandler(w, r, board)
		return
	}
	type gameTemp struct {
		Multi     string
		PrettySVG string
		BlackMove bool
	}
	necessary := gameTemp{board.multi, board.state.PrettySVG(), board.blackMove}
	err := templates.ExecuteTemplate(w, "game.html", necessary)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func moveHandler(w http.ResponseWriter, r *http.Request, board *Gob) {
	//Get move, send transaction
	f := r.FormValue
	raw := f("orig-message")
	rawmove := strings.Split(raw, "-")
	if board.blackMove && rawmove[0] != "black" {
		http.Error(w, "Not black's turn", http.StatusInternalServerError)
		return
	}
	if !board.blackMove && rawmove[0] != "white" {
		http.Error(w, "Not white's turn", http.StatusInternalServerError)
		return
	}
	sendTXHandler(w, r, board, raw)
	return
}

//update Board based on signed TX
func updateMove(board *Gob) (err error) {
	defer func() { board.txskel = gobcy.TXSkel{} }()
	//find rawmove in OP_RETURN
	var raw string
	for _, v := range board.txskel.Trans.Outputs {
		if v.ScriptType == "pay-to-script-hash" {
			board.wager = v.Value
		}
		if v.DataString != "" {
			raw = v.DataString
		}
	}
	//decide what to do
	if strings.HasPrefix(raw, "bitduck") || raw == "gameover" {
		return
	}
	rawmove := strings.Split(raw, "-")
	xmove, _ := strconv.Atoi(rawmove[1])
	ymove, _ := strconv.Atoi(rawmove[2])
	if board.blackMove {
		err = board.state.SetB(xmove, ymove)
		if err != nil {
			return
		}
	} else if !board.blackMove {
		err = board.state.SetW(xmove, ymove)
		if err != nil {
			return
		}
	}
	if board.blackMove {
		board.blackMove = false
	} else {
		board.blackMove = true
	}
	return
}
<|endoftext|>


<commit_before>package tw

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	baseURL = "https://api.twitter.com/1.1"
	authURL = "https://api.twitter.com/oauth2/token"
)

var (
	ErrTooManyRequests = errors.New("Too Many Requests")
)

func GetBearerAccessToken(consumerKey, consumerSecret string) (string, error) {
	client := &http.Client{}
	req, err := http.NewRequest("POST", authURL, nil)
	req.Header.Add("User-Agent", "My Twitter app")
	ck := url.QueryEscape(consumerKey)
	cs := url.QueryEscape(consumerSecret)
	bt := base64.StdEncoding.EncodeToString([]byte(ck + ":" + cs))
	req.Header.Add("Authorization", fmt.Sprintf("Basic %s", bt))
	req.Header.Add("Content-Type",
		"application/x-www-form-urlencoded;charset=UTF-8")
	req.Header.Add("Content-Length", "29")
	req.Header.Add("Accept-Encoding", "gzip")

	body := []byte("grant_type=client_credentials")
	req.Body = ioutil.NopCloser(bytes.NewReader(body))

	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	r, err := gzip.NewReader(resp.Body)
	if err != nil {
		return "", err
	}
	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return "", err
	}
	var data map[string]interface{}
	err = json.Unmarshal(buf, &data)
	if err != nil {
		return "", err
	}
	return data["access_token"].(string), nil
}

func NewClient() *Client {
	return &Client{}
}

func (c *Client) SetKeys(consumerKey, consumerSecret string) error {
	bat, err := GetBearerAccessToken(consumerKey, consumerSecret)
	if err != nil {
		return err
	}
	c.consumerSecret = consumerSecret
	c.consumerKey = consumerKey
	c.bearerAccessToken = bat
	return nil
}

func (c *Client) prepareRequest(method, url string) (*http.Request, error) {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("User-Agent", "My Twitter App")
	auth := fmt.Sprintf("Bearer %s", c.bearerAccessToken)
	req.Header.Add("Authorization", auth)
	req.Header.Add("Accept-Encoding", "gzip")
	return req, err
}

func (c *Client) GetUsersShow(screenName string) (*User, error) {
	screenName = url.QueryEscape(screenName)
	url := fmt.Sprintf("%s/users/show.json?screen_name=%s", baseURL, screenName)
	req, err := c.prepareRequest("GET", url)
	if err != nil {
		return nil, err
	}
	var user User
	err = exec(req, &user)
	return &user, err
}

func (c *Client) GetUsersShowByID(id uint64) (*User, error) {
	url := fmt.Sprintf("%s/users/show.json?user_id=%d", baseURL, id)
	req, err := c.prepareRequest("GET", url)
	if err != nil {
		return nil, err
	}
	var user User
	err = exec(req, &user)
	return &user, err
}

func exec(req *http.Request, data interface{}) error {
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	r, err := gzip.NewReader(resp.Body)
	if err != nil {
		return err
	}
	rb, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}
	if err = json.Unmarshal(rb, data); err != nil {
		return err
	}

	// Too Many Requests
	if resp.StatusCode == 429 {
		return ErrTooManyRequests
	}
	if resp.StatusCode != http.StatusOK {
		return errors.New(resp.Status)
	}
	return nil
}

func (c *Client) GetTweets(screenName string, count uint) ([]Tweet, error) {
	screenName = url.QueryEscape(screenName)
	url := fmt.Sprintf("%s/statuses/user_timeline.json?screen_name=%s&count=%d",
		baseURL, screenName, count)
	req, err := c.prepareRequest("GET", url)
	tweets := make([]Tweet, 0)
	if err != nil {
		return tweets, err
	}
	err = exec(req, &tweets)
	return tweets, err
}

func (c *Client) GetTweetsByID(id uint64, count uint) ([]Tweet, error) {
	url := fmt.Sprintf("%s/statuses/user_timeline.json?user_id=%d&count=%d",
		baseURL, id, count)
	tweets := make([]Tweet, 0)
	req, err := c.prepareRequest("GET", url)
	if err != nil {
		return tweets, err
	}
	err = exec(req, &tweets)
	return tweets, err
}

func (c *Client) GetFollowersIdsByID(id uint64, count int) *FollowersIterator {
	return &FollowersIterator{
		client: c,
		userID: id,
		count:  count,
		cursor: -1,
	}
}

func (c *Client) GetFriendsIdsByID(id uint64, count int) *FriendsIterator {
	return &FriendsIterator{
		client: c,
		userID: id,
		count:  count,
		cursor: -1,
	}
}
<commit_msg>Fix bug: first handle errors, then marshal data<commit_after>package tw

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	baseURL = "https://api.twitter.com/1.1"
	authURL = "https://api.twitter.com/oauth2/token"
)

var (
	ErrTooManyRequests = errors.New("Too Many Requests")
	ErrUnauthorized    = errors.New("Authorization Required")
)

func GetBearerAccessToken(consumerKey, consumerSecret string) (string, error) {
	client := &http.Client{}
	req, err := http.NewRequest("POST", authURL, nil)
	req.Header.Add("User-Agent", "My Twitter app")
	ck := url.QueryEscape(consumerKey)
	cs := url.QueryEscape(consumerSecret)
	bt := base64.StdEncoding.EncodeToString([]byte(ck + ":" + cs))
	req.Header.Add("Authorization", fmt.Sprintf("Basic %s", bt))
	req.Header.Add("Content-Type",
		"application/x-www-form-urlencoded;charset=UTF-8")
	req.Header.Add("Content-Length", "29")
	req.Header.Add("Accept-Encoding", "gzip")

	body := []byte("grant_type=client_credentials")
	req.Body = ioutil.NopCloser(bytes.NewReader(body))

	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	r, err := gzip.NewReader(resp.Body)
	if err != nil {
		return "", err
	}
	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return "", err
	}
	var data map[string]interface{}
	err = json.Unmarshal(buf, &data)
	if err != nil {
		return "", err
	}
	return data["access_token"].(string), nil
}

func NewClient() *Client {
	return &Client{}
}

func (c *Client) SetKeys(consumerKey, consumerSecret string) error {
	bat, err := GetBearerAccessToken(consumerKey, consumerSecret)
	if err != nil {
		return err
	}
	c.consumerSecret = consumerSecret
	c.consumerKey = consumerKey
	c.bearerAccessToken = bat
	return nil
}

func (c *Client) prepareRequest(method, url string) (*http.Request, error) {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("User-Agent", "My Twitter App")
	auth := fmt.Sprintf("Bearer %s", c.bearerAccessToken)
	req.Header.Add("Authorization", auth)
	req.Header.Add("Accept-Encoding", "gzip")
	return req, err
}

func (c *Client) GetUsersShow(screenName string) (*User, error) {
	screenName = url.QueryEscape(screenName)
	url := fmt.Sprintf("%s/users/show.json?screen_name=%s", baseURL, screenName)
	req, err := c.prepareRequest("GET", url)
	if err != nil {
		return nil, err
	}
	var user User
	err = exec(req, &user)
	return &user, err
}

func (c *Client) GetUsersShowByID(id uint64) (*User, error) {
	url := fmt.Sprintf("%s/users/show.json?user_id=%d", baseURL, id)
	req, err := c.prepareRequest("GET", url)
	if err != nil {
		return nil, err
	}
	var user User
	err = exec(req, &user)
	return &user, err
}

func exec(req *http.Request, data interface{}) error {
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	r, err := gzip.NewReader(resp.Body)
	if err != nil {
		return err
	}
	rb, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}
	// Too Many Requests
	if resp.StatusCode == 429 {
		return ErrTooManyRequests
	}
	if resp.StatusCode == 401 {
		return ErrUnauthorized
	}

	if resp.StatusCode != http.StatusOK {
		return errors.New(resp.Status)
	}
	if err = json.Unmarshal(rb, data); err != nil {
		return err
	}
	return nil
}

func (c *Client) GetTweets(screenName string, count uint) ([]Tweet, error) {
	screenName = url.QueryEscape(screenName)
	url := fmt.Sprintf("%s/statuses/user_timeline.json?screen_name=%s&count=%d",
		baseURL, screenName, count)
	req, err := c.prepareRequest("GET", url)
	tweets := make([]Tweet, 0)
	if err != nil {
		return tweets, err
	}
	err = exec(req, &tweets)
	return tweets, err
}

func (c *Client) GetTweetsByID(id uint64, count uint) ([]Tweet, error) {
	url := fmt.Sprintf("%s/statuses/user_timeline.json?user_id=%d&count=%d",
		baseURL, id, count)
	tweets := make([]Tweet, 0)
	req, err := c.prepareRequest("GET", url)
	if err != nil {
		return tweets, err
	}
	err = exec(req, &tweets)
	return tweets, err
}

func (c *Client) GetFollowersIdsByID(id uint64, count int) *FollowersIterator {
	return &FollowersIterator{
		client: c,
		userID: id,
		count:  count,
		cursor: -1,
	}
}

func (c *Client) GetFriendsIdsByID(id uint64, count int) *FriendsIterator {
	return &FriendsIterator{
		client: c,
		userID: id,
		count:  count,
		cursor: -1,
	}
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "net"
    "net/rpc"
    "time"
)

// Amazingly this function does not exist in the standard library
func max(a uint64, b uint64) uint64 {
    if (a > b) {
        return a
    } else {
        return b
    }
}

type Role struct {
    roleId uint64
    client chan string
    peers map[uint64]string
}

/*
 * Acceptor Role
 */
type AcceptorRole struct {
    Role
    minProposalId uint64
    acceptedProposalId uint64
    acceptedValue string
}

type PromiseReq struct {
    ProposalId uint64
}

type Promise struct {
    PromiseAccepted bool
    AcceptedProposalId uint64
    AcceptedValue string
}

func (this *AcceptorRole) Prepare(req *PromiseReq, reply *Promise) error {
    fmt.Println(this.Role.roleId, "considering promise", req.ProposalId, this.minProposalId)
    reply.PromiseAccepted = req.ProposalId > this.minProposalId
    reply.AcceptedProposalId = this.acceptedProposalId
    reply.AcceptedValue = this.acceptedValue
    this.minProposalId = max(req.ProposalId, this.minProposalId)
    return nil
}

type Proposal struct {
    ProposalId uint64
    Value string
}

func (this *AcceptorRole) Accept(proposal *Proposal, reply *uint64) error {
    fmt.Println(this.Role.roleId, "considering proposal", proposal.ProposalId, ":", proposal.Value)
    if proposal.ProposalId >= this.minProposalId {
        fmt.Println("Accepted proposal", proposal.ProposalId)
        this.acceptedProposalId = proposal.ProposalId
        this.acceptedValue = proposal.Value
    }
    *reply = this.minProposalId
    return nil
}

func (this *AcceptorRole) run() {
    fmt.Println("Registering acceptor", this.Role.roleId, "at", this.Role.peers[this.Role.roleId])
    rpc.Register(this)
    ln, err := net.Listen("tcp", this.Role.peers[this.Role.roleId])
    if err != nil {
        fmt.Println("Listening error:", err)
        return
    }
    for {
        cxn, err := ln.Accept()
        fmt.Println("Accepting connection", this.Role.roleId, cxn)
        if err != nil { continue }
        go rpc.ServeConn(cxn)
    }
}

/*
 * Proposer Role
 */
type ProposerRole struct {
    Role
    proposalId uint64
    value string
}

// Connects to Acceptors
func (this *ProposerRole) connect() (map[uint64]*rpc.Client, error) {
    acceptors := make(map[uint64]*rpc.Client)
    for key, val := range this.Role.peers {
        cxn, err := rpc.Dial("tcp", val)
        if err != nil { return acceptors, err }
        fmt.Println("Connected to acceptor", key, "at", val, cxn)
        acceptors[key] = cxn
    }
    return acceptors, nil
}

// Prepare phase
func (this *ProposerRole) preparePhase(acceptors map[uint64]*rpc.Client) (bool, error) {
    peerCount := len(this.Role.peers)
    majority := peerCount / 2 + 1
    endpoint := make(chan *rpc.Call, peerCount)

    // Sends out promise requests
    req := &PromiseReq{this.proposalId}
    for _, acceptor := range acceptors {
        var promiseReply Promise
        fmt.Println("Sending prepare request to", acceptor)
        acceptor.Go("AcceptorRole.Prepare", req, &promiseReply, endpoint)
    }

    // Waits for promises from majority of acceptors
    replyCount := 0
    promiseCount := 0
    var highestAccepted uint64 = 0
    for promiseCount < majority && replyCount < peerCount {
        var promise *Promise
        select {
            case reply := <- endpoint:
                if reply.Error != nil { return false, reply.Error }
                promise = reply.Reply.(*Promise)
                replyCount++
            case <- time.After(1000000000):
                return false, nil
        }

        if promise.PromiseAccepted {
            promiseCount++
            if promise.AcceptedProposalId > highestAccepted {
                highestAccepted = promise.AcceptedProposalId
                this.value = promise.AcceptedValue
            }
        }
    }

    fmt.Println("Promisecount", promiseCount, peerCount, majority, replyCount)
    return promiseCount >= majority, nil
}

// Proposal phase
func (this *ProposerRole) proposalPhase(acceptors map[uint64]*rpc.Client) (bool, error) {
    peerCount := len(this.Role.peers)
    endpoint := make(chan *rpc.Call, peerCount)

    // Sends out proposals
    proposal := &Proposal{this.proposalId, this.value}
    for _, acceptor := range acceptors {
        var proposalReply uint64
        acceptor.Go("AcceptorRole.Accept", proposal, &proposalReply, endpoint)
    }

    // Waits for acceptance from majority of acceptors
    acceptCount := 0
    for acceptCount < (peerCount / 2 + 1) {
        reply := <- endpoint
        if reply.Error != nil {
            return false, reply.Error
        }
        acceptedId := reply.Reply.(*uint64)

        if *acceptedId <= this.proposalId {
            acceptCount++
        } else {
            return false, nil
        }
    }

    return true, nil
}

func (this *ProposerRole) run() {
    // Connects to acceptors
    acceptors, err := this.connect()
    if err != nil {
        fmt.Println("Connection error:", err)
        return
    }

    // Initiates Paxos protocol
    notChosen := true
    this.proposalId = 0
    this.value = <- this.Role.client
    if err != nil {
        fmt.Println("Client request error", err)
        return
    }

    for notChosen {
        // Generates new proposal ID
        this.proposalId += this.Role.roleId

        success, err := this.preparePhase(acceptors)
        if err != nil {
            fmt.Println("Prepare phase error:", err)
            return
        }

        if success {
            notChosen, err = this.proposalPhase(acceptors)
            if err != nil {
                fmt.Println("Proposal phase error:", err)
                return
            }
        }
    }
}

func main() {
    client := make(chan string)
    peers := map[uint64]string {
        1: "127.0.0.1:10000",
        2: "127.0.0.1:10010",
    }

    role := Role{0, client, peers}
    for roleId := range peers {
        role.roleId = roleId
        acceptor := AcceptorRole{role, 2, 0, ""}
        go acceptor.run()
    }

    role.roleId = 2
    proposer := ProposerRole{role, 0, ""}
    go proposer.run()

    client <- "Hello, world!"

    var input string
    fmt.Scanln(&input)
}

<commit_msg>Paxos fully functional for single round<commit_after>package main

import (
    "fmt"
    "net"
    "net/rpc"
    "time"
)

// Amazingly this function does not exist in the standard library
func max(a uint64, b uint64) uint64 {
    if (a > b) {
        return a
    } else {
        return b
    }
}

type Role struct {
    roleId uint64
    client chan string
    peers map[uint64]string
}

/*
 * Acceptor Role
 */
type AcceptorRole struct {
    Role
    minProposalId uint64
    acceptedProposalId uint64
    acceptedValue string
}

type PromiseReq struct {
    ProposalId uint64
}

type Promise struct {
    PromiseAccepted bool
    AcceptedProposalId uint64
    AcceptedValue string
}

func (this *AcceptorRole) Prepare(req *PromiseReq, reply *Promise) error {
    fmt.Println("Acceptor", this.Role.roleId, "considering promise", req.ProposalId, "vs", this.minProposalId)
    reply.PromiseAccepted = req.ProposalId > this.minProposalId
    reply.AcceptedProposalId = this.acceptedProposalId
    reply.AcceptedValue = this.acceptedValue
    this.minProposalId = max(req.ProposalId, this.minProposalId)
    return nil
}

type Proposal struct {
    ProposalId uint64
    Value string
}

func (this *AcceptorRole) Accept(proposal *Proposal, reply *uint64) error {
    fmt.Println("Acceptor", this.Role.roleId, "considering proposal", proposal.ProposalId)
    if proposal.ProposalId >= this.minProposalId {
        this.acceptedProposalId = proposal.ProposalId
        this.acceptedValue = proposal.Value
    }
    *reply = this.minProposalId
    return nil
}

func (this *AcceptorRole) run(handler *rpc.Server, ln net.Listener) {
    for {
        cxn, err := ln.Accept()
        if err != nil { continue }
        go handler.ServeConn(cxn)
    }
}

/*
 * Proposer Role
 */
type ProposerRole struct {
    Role
    proposalId uint64
    value string
}

// Connects to Acceptors
func (this *ProposerRole) connect() (map[uint64]*rpc.Client, error) {
    acceptors := make(map[uint64]*rpc.Client)
    for key, val := range this.Role.peers {
        cxn, err := rpc.Dial("tcp", val)
        if err != nil { return acceptors, err }
        acceptors[key] = cxn
    }
    return acceptors, nil
}

// Prepare phase
func (this *ProposerRole) preparePhase(acceptors map[uint64]*rpc.Client) (bool, error) {
    peerCount := len(this.Role.peers)
    majority := peerCount / 2 + 1
    endpoint := make(chan *rpc.Call, peerCount)

    // Sends out promise requests
    req := &PromiseReq{this.proposalId}
    for _, acceptor := range acceptors {
        var promiseReply Promise
        acceptor.Go("AcceptorRole.Prepare", req, &promiseReply, endpoint)
    }

    // Waits for promises from majority of acceptors
    replyCount := 0
    promiseCount := 0
    var highestAccepted uint64 = 0
    for promiseCount < majority && replyCount < peerCount {
        var promise Promise
        select {
            case reply := <- endpoint:
                if reply.Error != nil { return false, reply.Error }
                promise = *reply.Reply.(*Promise)
                replyCount++
            case <- time.After(1000000000):
                fmt.Println("Prepare phase time-out: proposal", this.proposalId)
                return false, nil
        }

        if promise.PromiseAccepted {
            promiseCount++
            if promise.AcceptedProposalId > highestAccepted {
                highestAccepted = promise.AcceptedProposalId
                this.value = promise.AcceptedValue
            }
        }
    }

    fmt.Println("Processed", replyCount, "replies with", promiseCount, "promises.")
    return promiseCount >= majority, nil
}

// Proposal phase
func (this *ProposerRole) proposalPhase(acceptors map[uint64]*rpc.Client) (bool, error) {
    peerCount := len(this.Role.peers)
    majority := peerCount / 2 + 1
    endpoint := make(chan *rpc.Call, peerCount)

    // Sends out proposals
    proposal := &Proposal{this.proposalId, this.value}
    for _, acceptor := range acceptors {
        var proposalReply uint64
        acceptor.Go("AcceptorRole.Accept", proposal, &proposalReply, endpoint)
    }

    // Waits for acceptance from majority of acceptors
    acceptCount := 0
    for acceptCount < majority {
        var acceptedId uint64
        select {
            case reply := <- endpoint :
                if reply.Error != nil { return false, reply.Error }
                acceptedId = *reply.Reply.(*uint64)
            case <- time.After(1000000000):
                fmt.Println("Accept phase time-out: proposal", this.proposalId)
                return false, nil
        }

        if acceptedId <= this.proposalId {
            acceptCount++
        } else {
            return false, nil
        }
    }

    fmt.Println("Majority accepted proposal", this.proposalId, "with value", this.value)
    return true, nil
}

func (this *ProposerRole) run() {
    // Connects to acceptors
    acceptors, err := this.connect()
    if err != nil {
        fmt.Println("Connection error:", err)
        return
    }

    // Initiates Paxos protocol
    notChosen := true
    this.proposalId = 0
    this.value = <- this.Role.client
    if err != nil {
        fmt.Println("Client request error", err)
        return
    }

    for notChosen {
        this.proposalId += this.Role.roleId

        // Executes prepare phase
        success, err := this.preparePhase(acceptors)
        if err != nil {
            fmt.Println("Prepare phase error:", err)
            return
        }

        // Executes proposal phase
        if success {
            success, err = this.proposalPhase(acceptors)
            if err != nil {
                fmt.Println("Proposal phase error:", err)
                return
            }
            notChosen = !success
        }
    }
}

func main() {
    client := make(chan string)
    peers := map[uint64]string {
        1: "127.0.0.1:10000",
        2: "127.0.0.1:10001",
        3: "127.0.0.1:10002",
        4: "127.0.0.1:10003",
        5: "127.0.0.1:10004",
    }

    role := Role{0, client, peers}
    for roleId, address := range peers {
        role.roleId = roleId
        acceptor := AcceptorRole{role, 5, 0, "foobar"}
        handler := rpc.NewServer()
        err := handler.Register(&acceptor)
        if err != nil {
            fmt.Println("Failed to register Acceptor", roleId, err)
            continue
        }
        ln, err := net.Listen("tcp", address)
        if err != nil {
            fmt.Println("Listening error:", err)
            return
        }
        go acceptor.run(handler, ln)
    }

    role.roleId = 5
    proposer := ProposerRole{role, 0, ""}
    go proposer.run()

    client <- "Hello, world!"

    var input string
    fmt.Scanln(&input)
}

<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const version = "1.0.0"
const usageText = `Usage: grepby [regex1] [regex2] [regex3]...

  Use grepby to count lines that match regular expressions. It's a bit like
  having group by for grep.

  By default, all of stdin in read and the aggregate counts are output to
  stdout. When --tail or --output are used or combined, counts are output to
  stderr and matching lines are output to stdout.

Options:
  --help          Print this help
  --tail          Print aggregate output every 2 seconds to stderr
  --tail=10       Print aggregate output every 10 seconds to stderr
  --output        Print all lines that match at least one regex to stdout
  --version       Print the version number

Examples:
  grepby 'potato' 'banana' '[Tt]omato' < groceries.txt")
  20% -  600 - potato")
  13% -  400 - banana")
  17% -  500 - [Tt]omato")
  50% - 1500 - (unmatched)")

Report bugs and find the latest updates at https://github.com/rholder/grepby.
`

type Config struct {
	help          bool
	tail          bool
	tailDelay     float64
	outputMatches bool
	countWriter   io.Writer
	matchWriter   io.Writer
	patterns      []string
	countTemplate string
	version       bool
}

type PatternCount struct {
	pattern string
	count   uint64
	regex   *regexp.Regexp
}

type Rollup struct {
	config   *Config
	patterns []*PatternCount
	total    uint64
}

func newRollup(config *Config) (*Rollup, error) {
	rollup := Rollup{}
	rollup.total = 0
	rollup.config = config
	for _, pattern := range config.patterns {
		regex, err := regexp.Compile(pattern)
		if err != nil {
			return nil, err
		}
		pc := PatternCount{pattern, 0, regex}
		rollup.patterns = append(rollup.patterns, &pc)
	}
	return &rollup, nil
}

func newConfig(args []string, stdout io.Writer, stderr io.Writer) (*Config, error) {
	config := Config{}
	config.countWriter = stdout
	config.tailDelay = 2.0

	enableTail := false
	enableOutput := false

	// default is to output a count to stdout when complete
	var patterns []string
	for _, arg := range args {
		if strings.HasPrefix(arg, "--tail") {
			enableTail = true
			if strings.HasPrefix(arg, "--tail=") {
				td, err := strconv.Atoi(arg[7:])
				if err != nil {
					return nil, err
				}
				config.tailDelay = float64(td)
			}
		} else if "--output" == arg {
			enableOutput = true
		} else if "--version" == arg {
			config.version = true
		} else if "--help" == arg {
			config.help = true
		} else {
			patterns = append(patterns, arg)
		}
	}
	config.patterns = patterns

	// --tail always outputs counts to stderr
	if enableTail {
		config.tail = true
		config.countWriter = stderr
	}

	// --output outputs matches to stdout and forces counts to stderr
	if enableOutput {
		config.outputMatches = true
		config.countWriter = stderr
		config.matchWriter = stdout
	}

	// TODO make configurable via argument
	config.countTemplate = "%4.0f%% - %6v - %v" + "\n"

	return &config, nil
}

// Output the rollup counts.
func outputCounts(rollup *Rollup) {
	var totalMatched uint64 = 0
	output := rollup.config.countWriter
	template := rollup.config.countTemplate

	for _, pc := range rollup.patterns {
		totalMatched += pc.count
	}

	if rollup.config.tail {
		fmt.Fprintf(output, "(last %v lines)\n", rollup.total)
	}

	totalUnmatched := rollup.total - totalMatched
	for _, pc := range rollup.patterns {
		var percentMatched float64 = 0
		if rollup.total != 0 {
			percentMatched = 100 * float64(pc.count) / float64(rollup.total)
		}
		fmt.Fprintf(output, template, percentMatched, pc.count, pc.pattern)
	}
	var percentUnmatched float64 = 0
	if rollup.total != 0 {
		percentUnmatched = 100 * float64(totalUnmatched) / float64(rollup.total)
	}
	fmt.Fprintf(output, template, percentUnmatched, totalUnmatched, "(unmatched)")
}

// Update counts from the given input line. Return true if there was a match.
func updateCounts(rollup *Rollup, line string) bool {
	rollup.total += 1
	for _, pc := range rollup.patterns {
		// only first matching pattern counts
		if pc.regex.MatchString(line) {
			pc.count += 1
			return true
		}
	}
	return false
}

func cli(args []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
	if len(args) == 0 {
		fmt.Fprintln(stdout, usageText)
		return errors.New("Invalid number of arguments.")
	}

	config, err := newConfig(args, stdout, stderr)
	if err != nil {
		return err
	}

	// short circuit on --version
	if config.version {
		fmt.Fprintln(stdout, version)
		return nil
	}

	// short circuit on --help
	if config.help {
		fmt.Fprintln(stdout, usageText)
		return nil
	}

	rollup, err := newRollup(config)
	if err != nil {
		return err
	}

	// read from input
	last := time.Now()
	scanner := bufio.NewScanner(stdin)
	outputMatches := rollup.config.outputMatches
	matchWriter := rollup.config.matchWriter
	for scanner.Scan() {
		line := scanner.Text()
		matched := updateCounts(rollup, line)
		if outputMatches && matched {
			fmt.Fprintln(matchWriter, line)
		}
		if config.tail {
			now := time.Now()
			if now.Sub(last).Seconds() > config.tailDelay {
				outputCounts(rollup)
				last = now
			}
		}
	}
	outputCounts(rollup)
	return nil
}

func main() {
	args := os.Args[1:]
	err := cli(args, os.Stdin, os.Stdout, os.Stderr)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>add a few comments<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const version = "1.0.0"
const usageText = `Usage: grepby [regex1] [regex2] [regex3]...

  Use grepby to count lines that match regular expressions. It's a bit like
  having group by for grep.

  By default, all of stdin in read and the aggregate counts are output to
  stdout. When --tail or --output are used or combined, counts are output to
  stderr and matching lines are output to stdout.

Options:
  --help          Print this help
  --tail          Print aggregate output every 2 seconds to stderr
  --tail=10       Print aggregate output every 10 seconds to stderr
  --output        Print all lines that match at least one regex to stdout
  --version       Print the version number

Examples:
  grepby 'potato' 'banana' '[Tt]omato' < groceries.txt")
  20% -  600 - potato")
  13% -  400 - banana")
  17% -  500 - [Tt]omato")
  50% - 1500 - (unmatched)")

Report bugs and find the latest updates at https://github.com/rholder/grepby.
`

type Config struct {
	help          bool
	tail          bool
	tailDelay     float64
	outputMatches bool
	countWriter   io.Writer
	matchWriter   io.Writer
	patterns      []string
	countTemplate string
	version       bool
}

type PatternCount struct {
	pattern string
	count   uint64
	regex   *regexp.Regexp
}

type Rollup struct {
	config   *Config
	patterns []*PatternCount
	total    uint64
}

func newRollup(config *Config) (*Rollup, error) {
	rollup := Rollup{}
	rollup.total = 0
	rollup.config = config
	for _, pattern := range config.patterns {
		regex, err := regexp.Compile(pattern)
		if err != nil {
			// give up if any regex doesn't compile
			return nil, err
		}
		pc := PatternCount{pattern, 0, regex}
		rollup.patterns = append(rollup.patterns, &pc)
	}
	return &rollup, nil
}

func newConfig(args []string, stdout io.Writer, stderr io.Writer) (*Config, error) {
	config := Config{}
	config.countWriter = stdout
	config.tailDelay = 2.0

	enableTail := false
	enableOutput := false

	// default is to output a count to stdout when complete
	var patterns []string
	for _, arg := range args {
		if strings.HasPrefix(arg, "--tail") {
			// handle a --tail and a --tail=N
			enableTail = true
			if strings.HasPrefix(arg, "--tail=") {
				td, err := strconv.Atoi(arg[7:])
				if err != nil {
					return nil, err
				}
				config.tailDelay = float64(td)
			}
		} else if "--output" == arg {
			enableOutput = true
		} else if "--version" == arg {
			config.version = true
		} else if "--help" == arg {
			config.help = true
		} else {
			// everything else is a pattern
			patterns = append(patterns, arg)
		}
	}
	config.patterns = patterns

	// --tail always outputs counts to stderr
	if enableTail {
		config.tail = true
		config.countWriter = stderr
	}

	// --output outputs matches to stdout and forces counts to stderr
	if enableOutput {
		config.outputMatches = true
		config.countWriter = stderr
		config.matchWriter = stdout
	}

	// TODO make configurable via argument
	config.countTemplate = "%4.0f%% - %6v - %v" + "\n"

	return &config, nil
}

// Output the rollup counts.
func outputCounts(rollup *Rollup) {
	var totalMatched uint64 = 0
	output := rollup.config.countWriter
	template := rollup.config.countTemplate

	for _, pc := range rollup.patterns {
		totalMatched += pc.count
	}

	if rollup.config.tail {
		fmt.Fprintf(output, "(last %v lines)\n", rollup.total)
	}

	totalUnmatched := rollup.total - totalMatched
	for _, pc := range rollup.patterns {
		var percentMatched float64 = 0
		if rollup.total != 0 {
			percentMatched = 100 * float64(pc.count) / float64(rollup.total)
		}
		fmt.Fprintf(output, template, percentMatched, pc.count, pc.pattern)
	}
	var percentUnmatched float64 = 0
	if rollup.total != 0 {
		percentUnmatched = 100 * float64(totalUnmatched) / float64(rollup.total)
	}
	fmt.Fprintf(output, template, percentUnmatched, totalUnmatched, "(unmatched)")
}

// Update counts from the given input line. Return true if there was a match.
func updateCounts(rollup *Rollup, line string) bool {
	rollup.total += 1
	for _, pc := range rollup.patterns {
		// only first matching pattern counts
		if pc.regex.MatchString(line) {
			pc.count += 1
			return true
		}
	}
	return false
}

func cli(args []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
	if len(args) == 0 {
		fmt.Fprintln(stdout, usageText)
		return errors.New("Invalid number of arguments.")
	}

	config, err := newConfig(args, stdout, stderr)
	if err != nil {
		return err
	}

	// short circuit on --version
	if config.version {
		fmt.Fprintln(stdout, version)
		return nil
	}

	// short circuit on --help
	if config.help {
		fmt.Fprintln(stdout, usageText)
		return nil
	}

	rollup, err := newRollup(config)
	if err != nil {
		return err
	}

	// read from input
	last := time.Now()
	scanner := bufio.NewScanner(stdin)
	outputMatches := rollup.config.outputMatches
	matchWriter := rollup.config.matchWriter
	for scanner.Scan() {
		line := scanner.Text()
		matched := updateCounts(rollup, line)
		if outputMatches && matched {
			fmt.Fprintln(matchWriter, line)
		}
		if config.tail {
			now := time.Now()
			if now.Sub(last).Seconds() > config.tailDelay {
				outputCounts(rollup)
				last = now
			}
		}
	}
	outputCounts(rollup)
	return nil
}

func main() {
	args := os.Args[1:]
	err := cli(args, os.Stdin, os.Stdout, os.Stderr)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/luismesas/goPi/piface"
	"github.com/luismesas/goPi/spi"
	"time"
)

func main() {

	// creates a new pifacedigital instance
	pfd := piface.NewPiFaceDigital(spi.DEFAULT_HARDWARE_ADDR, spi.DEFAULT_BUS, spi.DEFAULT_CHIP)

	// initializes pifacedigital board
	err := pfd.InitBoard()
	if err != nil {
		fmt.Printf("Error on init board: %s", err)
		return
	}

	for k, v := range pfd.Leds {
		v.AllOn()
		time.Sleep(time.Second)
	}
	for k, v := range pfd.Leds {
		v.AllOff()
	}
}
<commit_msg>removed k<commit_after>package main

import (
	"fmt"
	"github.com/luismesas/goPi/piface"
	"github.com/luismesas/goPi/spi"
	"time"
)

func main() {

	// creates a new pifacedigital instance
	pfd := piface.NewPiFaceDigital(spi.DEFAULT_HARDWARE_ADDR, spi.DEFAULT_BUS, spi.DEFAULT_CHIP)

	// initializes pifacedigital board
	err := pfd.InitBoard()
	if err != nil {
		fmt.Printf("Error on init board: %s", err)
		return
	}

	for _, v := range pfd.Leds {
		v.AllOn()
		time.Sleep(time.Second)
	}
	for _, v := range pfd.Leds {
		v.AllOff()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"flag"
	"fmt"
	"golang.org/x/crypto/nacl/box"
	"golang.org/x/crypto/nacl/secretbox"
	"io"
	"log"
	"net"
	"os"
)

// header encodes encrypted message length and nonce information.
// It is sent unencrypted at the start of the message.
// The length is used to ensure we read enough data to decrypt the
// fix length message.
type header struct {
	Length uint64
	Nonce  [24]byte
}

type secureReader struct {
	src io.Reader
	key *[32]byte
	buf []byte
}

type secureWriter struct {
	dst io.Writer
	key *[32]byte
}

func (p secureReader) Read(b []byte) (int, error) {
	// Check to see if there are still remnants of the last message to
	// read
	if p.buf == nil {
		// Read header from stream
		var h header
		if err := binary.Read(p.src, binary.LittleEndian, &h); err != nil {
			return 0, err
		}

		// Allocate a buffer to contain the encrypted and decrypted message
		p.buf = make([]byte, h.Length-secretbox.Overhead)
		tmp := make([]byte, h.Length)

		// Read the encrypted message
		if _, err := io.ReadFull(p.src, tmp); err != nil {
			return 0, err
		}

		// Decrypt message and check it is authentic
		_, auth := secretbox.Open(p.buf[:0], tmp[:], &h.Nonce, p.key)
		if !auth {
			return 0, fmt.Errorf("Message failed authentication")
		}
	}

	// Copy the result into the output buffer, leaving a partial result
	// in the buffer if needed
	size := copy(b, p.buf)
	if size == len(p.buf) {
		p.buf = nil
	} else {
		p.buf = p.buf[size:]
	}
	return size, nil
}

func (p secureWriter) Write(b []byte) (int, error) {
	// Encode header containing length and randomly generated nonce
	var h header
	h.Length = uint64(len(b) + secretbox.Overhead)
	if _, err := io.ReadFull(rand.Reader, h.Nonce[:]); err != nil {
		return 0, err
	}

	// Write header out
	hbuf := new(bytes.Buffer)
	binary.Write(hbuf, binary.LittleEndian, &h)
	if _, err := p.dst.Write(hbuf.Bytes()); err != nil {
		return 0, err
	}

	// Encrypt and send the message
	tmp := make([]byte, h.Length)
	secretbox.Seal(tmp[:0], b, &h.Nonce, p.key)
	if _, err := p.dst.Write(tmp); err != nil {
		return 0, err
	}
	return len(b), nil
}

// NewSecureReader instantiates a new SecureReader
func NewSecureReader(r io.Reader, priv, pub *[32]byte) io.Reader {
	sr := secureReader{src: r, key: new([32]byte), buf: nil}
	box.Precompute(sr.key, pub, priv)
	return sr
}

// NewSecureWriter instantiates a new SecureWriter
func NewSecureWriter(w io.Writer, priv, pub *[32]byte) io.Writer {
	sw := secureWriter{dst: w, key: new([32]byte)}
	box.Precompute(sw.key, pub, priv)
	return sw
}

// Generate a public/private key pair.
// Swap public keys over ReadWriter.
func swapKeys(rw io.ReadWriter) (priv, peer *[32]byte, err error) {
	// Generate our public/private key pair
	pub, priv, err := box.GenerateKey(rand.Reader)
	if err != nil {
		return nil, nil, err
	}

	// Send our public key
	senderr := make(chan error)
	go func() {
		_, err := rw.Write(pub[:])
		senderr <- err
	}()

	// Receive their public key
	peer = new([32]byte)
	_, err = io.ReadFull(rw, peer[:])
	if err != nil {
		return nil, nil, err
	}

	// Wait for our send to complete
	if err = <-senderr; err != nil {
		return nil, nil, err
	}

	return
}

// Dial generates a private/public key pair,
// connects to the server, perform the handshake
// and return a reader/writer.
func Dial(addr string) (io.ReadWriteCloser, error) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}

	priv, pub, err := swapKeys(conn)
	if err != nil {
		return nil, err
	}

	return struct {
		io.Reader
		io.Writer
		io.Closer
	}{
		NewSecureReader(conn, priv, pub),
		NewSecureWriter(conn, priv, pub),
		conn,
	}, nil
}

func connect(conn net.Conn) {
	defer conn.Close()

	priv, pub, err := swapKeys(conn)
	if err != nil {
		log.Fatal(err)
	}

	r := NewSecureReader(conn, priv, pub)
	w := NewSecureWriter(conn, priv, pub)

	if _, err := io.Copy(w, r); err != nil {
		log.Fatal(err)
	}
}

// Serve starts a secure echo server on the given listener.
func Serve(l net.Listener) error {
	for {
		conn, err := l.Accept()
		if err != nil {
			return err
		}
		go connect(conn)
	}
}

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

func main() {
	port := flag.Int("l", 0, "Listen mode. Specify port")
	flag.Parse()

	// Server mode
	if *port != 0 {
		l, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
		if err != nil {
			log.Fatal(err)
		}
		defer l.Close()
		log.Fatal(Serve(l))
	}

	// Client mode
	if len(os.Args) != 3 {
		log.Fatalf("Usage: %s <port> <message>", os.Args[0])
	}
	conn, err := Dial("localhost:" + os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	if _, err := conn.Write([]byte(os.Args[2])); err != nil {
		log.Fatal(err)
	}
	buf := make([]byte, len(os.Args[2]))
	n, err := conn.Read(buf)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", buf[:n])
}
<commit_msg>Remove init.<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"flag"
	"fmt"
	"golang.org/x/crypto/nacl/box"
	"golang.org/x/crypto/nacl/secretbox"
	"io"
	"log"
	"net"
	"os"
)

// header encodes encrypted message length and nonce information.
// It is sent unencrypted at the start of the message.
// The length is used to ensure we read enough data to decrypt the
// fix length message.
type header struct {
	Length uint64
	Nonce  [24]byte
}

type secureReader struct {
	src io.Reader
	key *[32]byte
	buf []byte
}

type secureWriter struct {
	dst io.Writer
	key *[32]byte
}

func (p secureReader) Read(b []byte) (int, error) {
	// Check to see if there are still remnants of the last message to
	// read
	if p.buf == nil {
		// Read header from stream
		var h header
		if err := binary.Read(p.src, binary.LittleEndian, &h); err != nil {
			return 0, err
		}

		// Allocate a buffer to contain the encrypted and decrypted message
		p.buf = make([]byte, h.Length-secretbox.Overhead)
		tmp := make([]byte, h.Length)

		// Read the encrypted message
		if _, err := io.ReadFull(p.src, tmp); err != nil {
			return 0, err
		}

		// Decrypt message and check it is authentic
		_, auth := secretbox.Open(p.buf[:0], tmp[:], &h.Nonce, p.key)
		if !auth {
			return 0, fmt.Errorf("Message failed authentication")
		}
	}

	// Copy the result into the output buffer, leaving a partial result
	// in the buffer if needed
	size := copy(b, p.buf)
	if size == len(p.buf) {
		p.buf = nil
	} else {
		p.buf = p.buf[size:]
	}
	return size, nil
}

func (p secureWriter) Write(b []byte) (int, error) {
	// Encode header containing length and randomly generated nonce
	var h header
	h.Length = uint64(len(b) + secretbox.Overhead)
	if _, err := io.ReadFull(rand.Reader, h.Nonce[:]); err != nil {
		return 0, err
	}

	// Write header out
	hbuf := new(bytes.Buffer)
	binary.Write(hbuf, binary.LittleEndian, &h)
	if _, err := p.dst.Write(hbuf.Bytes()); err != nil {
		return 0, err
	}

	// Encrypt and send the message
	tmp := make([]byte, h.Length)
	secretbox.Seal(tmp[:0], b, &h.Nonce, p.key)
	if _, err := p.dst.Write(tmp); err != nil {
		return 0, err
	}
	return len(b), nil
}

// NewSecureReader instantiates a new SecureReader
func NewSecureReader(r io.Reader, priv, pub *[32]byte) io.Reader {
	sr := secureReader{src: r, key: new([32]byte), buf: nil}
	box.Precompute(sr.key, pub, priv)
	return sr
}

// NewSecureWriter instantiates a new SecureWriter
func NewSecureWriter(w io.Writer, priv, pub *[32]byte) io.Writer {
	sw := secureWriter{dst: w, key: new([32]byte)}
	box.Precompute(sw.key, pub, priv)
	return sw
}

// Generate a public/private key pair.
// Swap public keys over ReadWriter.
func swapKeys(rw io.ReadWriter) (priv, peer *[32]byte, err error) {
	// Generate our public/private key pair
	pub, priv, err := box.GenerateKey(rand.Reader)
	if err != nil {
		return nil, nil, err
	}

	// Send our public key
	senderr := make(chan error)
	go func() {
		_, err := rw.Write(pub[:])
		senderr <- err
	}()

	// Receive their public key
	peer = new([32]byte)
	_, err = io.ReadFull(rw, peer[:])
	if err != nil {
		return nil, nil, err
	}

	// Wait for our send to complete
	if err = <-senderr; err != nil {
		return nil, nil, err
	}

	return
}

// Dial generates a private/public key pair,
// connects to the server, perform the handshake
// and return a reader/writer.
func Dial(addr string) (io.ReadWriteCloser, error) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}

	priv, pub, err := swapKeys(conn)
	if err != nil {
		return nil, err
	}

	return struct {
		io.Reader
		io.Writer
		io.Closer
	}{
		NewSecureReader(conn, priv, pub),
		NewSecureWriter(conn, priv, pub),
		conn,
	}, nil
}

func connect(conn net.Conn) {
	defer conn.Close()

	priv, pub, err := swapKeys(conn)
	if err != nil {
		log.Fatal(err)
	}

	r := NewSecureReader(conn, priv, pub)
	w := NewSecureWriter(conn, priv, pub)

	if _, err := io.Copy(w, r); err != nil {
		log.Fatal(err)
	}
}

// Serve starts a secure echo server on the given listener.
func Serve(l net.Listener) error {
	for {
		conn, err := l.Accept()
		if err != nil {
			return err
		}
		go connect(conn)
	}
}

func main() {
	port := flag.Int("l", 0, "Listen mode. Specify port")
	flag.Parse()

	// Server mode
	if *port != 0 {
		l, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
		if err != nil {
			log.Fatal(err)
		}
		defer l.Close()
		log.Fatal(Serve(l))
	}

	// Client mode
	if len(os.Args) != 3 {
		log.Fatalf("Usage: %s <port> <message>", os.Args[0])
	}
	conn, err := Dial("localhost:" + os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	if _, err := conn.Write([]byte(os.Args[2])); err != nil {
		log.Fatal(err)
	}
	buf := make([]byte, len(os.Args[2]))
	n, err := conn.Read(buf)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", buf[:n])
}
<|endoftext|>


<commit_before>package main

/*
   TODO:
   o oop
   o log
   o chunk i/o
   o keep alive
*/

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/exec"
	"strings"
)

type config struct {
	Bind    string
	Port    string
	Cmd     string
	CmdArgs []string
}

type option struct {
	Addr string
	Cmd  string
}

var deb bool
var opt option

func init() {
	const (
		verbUsage  = "Enable verbose"
		verbDefVal = false
	)

	flag.BoolVar(&deb, "v", verbDefVal, verbUsage)
	flag.BoolVar(&deb, "verbose", verbDefVal, verbUsage)

	flag.StringVar(&opt.Addr, "addr", "127.0.0.1:3131", "Ip address to bind")
	flag.StringVar(&opt.Cmd, "cmd", "", "Command to run")
}

func main() {
	flag.Parse()
	debug("env var GOPATH: [%s]", os.Getenv("GOPATH"))
	debug("%s", opt)

	conf := getConf()
	listener := getListener(conf)
	run(conf, listener)
}

func getConf() config {
	conf := config{
		Bind:    "127.0.0.1",
		Port:    "3000",
		Cmd:     "tee",
		CmdArgs: []string{},
	}

	if len(opt.Addr) > 0 {
		conf.Bind, conf.Port = parseOptAddr(opt.Addr)
	}

	if len(opt.Cmd) > 0 {
		conf.Cmd, conf.CmdArgs = parseOptCmd(opt.Cmd)
	}

	debug("Config: %s", conf)
	return conf
}

func parseOptAddr(addr string) (string, string) {
	addrs := strings.Split(addr, ":")
	if len(addrs) != 2 {
		printUsage()
		log.Fatal("Unable to parse addr")
	}
	return addrs[0], addrs[1]
}

func parseOptCmd(cmd string) (string, []string) {
	cmds := strings.Split(cmd, " ")
	if len(cmds[0]) == 0 || len(cmds) < 1 {
		printUsage()
		log.Fatal("Unable to parse cmd. cmd is required!")
	}

	args := make([]string, 0)
	for _, arg := range cmds[1:] {
		if arg == "" || arg == " " {
			continue
		}
		args = append(args, arg)
	}

	return cmds[0], args
}

func printUsage() {
	fmt.Println("Usage: tcpserver [--addr 0.0.0.0:3000] --cmd 'tr a-z A-Z'")
	flag.PrintDefaults()
	fmt.Println()
}

func getListener(conf config) net.Listener {
	addr := conf.Bind + ":" + conf.Port
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(fmt.Sprintf("Unable to listen to address: [%v] ERROR: %v", addr, err))
	}
	debug("Listenning to: %v", ln.Addr())
	return ln
}

func run(conf config, listener net.Listener) {
	for {
		conn, err := listener.Accept()
		if err != nil {
			errr(fmt.Sprintf("Something went wrong while connecting! ERROR: %v", err))
		} else {
			go handleConn(conn, conf)
		}
	}
}

func getCmd(conf config) *exec.Cmd {
	cmd := exec.Command(conf.Cmd)
	for _, arg := range conf.CmdArgs {
		cmd.Args = append(cmd.Args, arg)
	}
	debug("cmd: %s", cmd.Args)
	return cmd
}

func handleConn(conn net.Conn, conf config) {
	defer conn.Close()

	cmd := getCmd(conf)
	remote := conn.RemoteAddr()
	from := fmt.Sprintf("%s ", remote)
	debug("Accepted connection from: %v", remote)

	var buff bytes.Buffer
	arr := make([]byte, 50)
	prev := make([]byte, 50)
	for {
		prev = arr
		n, err := conn.Read(arr)
		if n > 0 {
			debug("%s-> Read bytes: %v", from, n)
			debug("%s-> data: [%s]", from, arr[:n])

			if prev[0] == '\r' && arr[0] == '\r' {
				str := string(buff.Bytes())
				runCmd(cmd, conn, str)
				debug(from + "XX ... connection closed")
				return
			}

			buff.Write(arr[:n])
		}

		if err != nil {
			if err == io.EOF {
				debug(from + "XX ... connection closed")
				return
			}
			errr(from + fmt.Sprintf("!! Something happened while reading! ERROR: [%v]", err))
			return
		}
	}
}

func runCmd(cmd *exec.Cmd, conn net.Conn, str string) {
	from := fmt.Sprintf("%s ", conn.RemoteAddr())
	debug("echo '%s' | %s", str, opt.Cmd)

	cmd.Stdin = strings.NewReader(str)
	cmd.Stdout = conn
	cmd.Stderr = conn

	err := cmd.Run()
	if err != nil {
		errr(from + fmt.Sprintf("!! Failed to exec! ERROR: %s\n", err))
		errstr := strings.NewReader(fmt.Sprintf("err: %s\n", err))
		io.Copy(conn, errstr)
		return
	}

	debug(from + "!! ... Ran cmd")
	debug("%s", cmd.ProcessState)
}

func debug(pattern string, args ...interface{}) {
	if !deb {
		return
	}
	pattern = "[debug] " + pattern
	log.Printf(pattern, args...)
}

func errr(log interface{}) {
	fmt.Fprintf(os.Stderr, "[error] %s\n", log)
}
<commit_msg>Improve errr<commit_after>package main

/*
   TODO:
   o oop
   o log
   o chunk i/o
   o keep alive
*/

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os/exec"
	"strings"
)

type config struct {
	Bind    string
	Port    string
	Cmd     string
	CmdArgs []string
}

type option struct {
	Addr string
	Cmd  string
}

var deb bool
var opt option

func init() {
	const (
		verbUsage  = "Enable verbose"
		verbDefVal = false
	)

	flag.BoolVar(&deb, "v", verbDefVal, verbUsage)
	flag.BoolVar(&deb, "verbose", verbDefVal, verbUsage)

	flag.StringVar(&opt.Addr, "addr", "127.0.0.1:3131", "Ip address to bind")
	flag.StringVar(&opt.Cmd, "cmd", "", "Command to run")
}

func main() {
	flag.Parse()
	debug("%s", opt)

	conf := getConf()
	listener := getListener(conf)
	run(conf, listener)
}

func getConf() config {
	conf := config{
		Bind:    "127.0.0.1",
		Port:    "3000",
		Cmd:     "tee",
		CmdArgs: []string{},
	}

	if len(opt.Addr) > 0 {
		conf.Bind, conf.Port = parseOptAddr(opt.Addr)
	}

	if len(opt.Cmd) > 0 {
		conf.Cmd, conf.CmdArgs = parseOptCmd(opt.Cmd)
	}

	debug("Config: %s", conf)
	return conf
}

func parseOptAddr(addr string) (string, string) {
	addrs := strings.Split(addr, ":")
	if len(addrs) != 2 {
		printUsage()
		log.Fatal("Unable to parse addr")
	}
	return addrs[0], addrs[1]
}

func parseOptCmd(cmd string) (string, []string) {
	cmds := strings.Split(cmd, " ")
	if len(cmds[0]) == 0 || len(cmds) < 1 {
		printUsage()
		log.Fatal("Unable to parse cmd. cmd is required!")
	}

	args := make([]string, 0)
	for _, arg := range cmds[1:] {
		if arg == "" || arg == " " {
			continue
		}
		args = append(args, arg)
	}

	return cmds[0], args
}

func printUsage() {
	fmt.Println("Usage: tcpserver [--addr 0.0.0.0:3000] --cmd 'tr a-z A-Z'")
	flag.PrintDefaults()
	fmt.Println()
}

func getListener(conf config) net.Listener {
	addr := conf.Bind + ":" + conf.Port
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(fmt.Sprintf("Unable to listen to address: [%v] ERROR: %v", addr, err))
	}
	debug("Listenning to: %v", ln.Addr())
	return ln
}

func run(conf config, listener net.Listener) {
	for {
		conn, err := listener.Accept()
		if err != nil {
			errr("Something went wrong while connecting! ERROR: %v", err)
		} else {
			go handleConn(conn, conf)
		}
	}
}

func getCmd(conf config) *exec.Cmd {
	cmd := exec.Command(conf.Cmd)
	for _, arg := range conf.CmdArgs {
		cmd.Args = append(cmd.Args, arg)
	}
	debug("cmd: %s", cmd.Args)
	return cmd
}

func handleConn(conn net.Conn, conf config) {
	defer conn.Close()

	cmd := getCmd(conf)
	remote := conn.RemoteAddr()
	from := fmt.Sprintf("%s ", remote)
	debug("Accepted connection from: %v", remote)

	var buff bytes.Buffer
	arr := make([]byte, 50)
	prev := make([]byte, 50)
	for {
		prev = arr
		n, err := conn.Read(arr)
		if n > 0 {
			debug("%s-> Read bytes: %v", from, n)
			debug("%s-> data: [%s]", from, arr[:n])

			if prev[0] == '\r' && arr[0] == '\r' {
				str := string(buff.Bytes())
				runCmd(cmd, conn, str)
				debug(from + "XX ... connection closed")
				return
			}

			buff.Write(arr[:n])
		}

		if err != nil {
			if err == io.EOF {
				debug(from + "XX ... connection closed")
				return
			}
			errr("%s!! Something happened while reading! ERROR: [%v]", from, err)
			return
		}
	}
}

func runCmd(cmd *exec.Cmd, conn net.Conn, str string) {
	from := fmt.Sprintf("%s ", conn.RemoteAddr())
	debug("echo '%s' | %s", str, opt.Cmd)

	cmd.Stdin = strings.NewReader(str)
	cmd.Stdout = conn
	cmd.Stderr = conn

	err := cmd.Run()
	if err != nil {
		errr("%s!! Failed to exec! ERROR: %s\n", from, err)
		errstr := strings.NewReader(fmt.Sprintf("err: %s\n", err))
		io.Copy(conn, errstr)
		return
	}

	debug(from + "!! ... Ran cmd")
	debug("%s", cmd.ProcessState)
}

func debug(pattern string, args ...interface{}) {
	if !deb {
		return
	}
	pattern = "[debug] " + pattern
	log.Printf(pattern, args...)
}

func errr(pattern string, args ...interface{}) {
	pattern = "[error] " + pattern
	log.Printf(pattern, args...)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"syscall"

	"github.com/fsnotify/fsnotify"
	"github.com/jessevdk/go-flags"
)

const (
	program = "Sentinel"
	version = "0.4.2"
	// ACTION is the environment variable for the type of notification triggered.
	ACTION = "SENTINEL_ACTION"
	// PATH is the environment variable for the type of notification triggered.
	PATH = "SENTINEL_PATH"
)

var opts struct {
	Verbose bool `short:"v" long:"verbose" description:"Print more details during operation, otherwise remain quiet until an error occurs."`
	Version bool `short:"V" long:"version" description:"Show program version and exit."`
	Flags   struct {
		Create bool `short:"c" long:"create" description:"Watch for file creation."`
		Write  bool `short:"w" long:"write" description:"Watch for file editing."`
		Delete bool `short:"d" long:"delete" description:"Watch for file deletion."`
		Rename bool `short:"r" long:"rename" description:"Watch for file renaming."`
		Chmod  bool `short:"m" long:"chmod" description:"Watch for file attribute changes (date or permissions)."`
		Loop   bool `short:"L" long:"loop" description:"Don't quit after each triggered event."`
	} `group:"Flags"`
	Commands struct {
		CreateAction string `short:"C" long:"createaction" description:"Script to run when a file is created." value-name:"CMD"`
		WriteAction  string `short:"W" long:"writeaction" description:"Script to run when a file is edited." value-name:"CMD"`
		DeleteAction string `short:"D" long:"deleteaction" description:"Script to run when a file is deleted." value-name:"CMD"`
		RenameAction string `short:"R" long:"renameaction" description:"Script to run when a file is renamed." value-name:"CMD"`
		ChmodAction  string `short:"M" long:"chmodaction" description:"Script to run when a file's date or permissions change." value-name:"CMD"`
	} `group:"Commands"`
	Args struct {
		Directory []string `positional-arg-name:"PATH"`
	} `positional-args:"yes"`
}

func main() {
	_, err := flags.Parse(&opts)
	if err != nil {
		return
	}

	if opts.Version {
		pr("%s %s\n", program, version)
		return
	}

	if len(opts.Args.Directory) == 0 {
		warn("No paths specified.")
	}
	var paths []string
	for _, d := range opts.Args.Directory {
		if !exists(d) {
			warn("Path %s does not exist.", d)
		}
		paths = append(paths, d)
	}

	// Default: Watch for any changes
	var flags fsnotify.Op

	if opts.Flags.Create {
		v("Watching for creation.\n")
		flags |= fsnotify.Create
	}

	if opts.Flags.Write {
		v("Watching for write.\n")
		flags |= fsnotify.Write
	}

	if opts.Flags.Delete {
		v("Watching for delete.\n")
		flags |= fsnotify.Remove
	}

	if opts.Flags.Rename {
		v("Watching for rename.\n")
		flags |= fsnotify.Rename
	}

	if opts.Flags.Chmod {
		v("Watching for permission changes.\n")
		flags |= fsnotify.Chmod
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				if flags&event.Op&fsnotify.Create == fsnotify.Create {
					if opts.Commands.CreateAction != "" {
						v("CREATE: Running '%s'\n", opts.Commands.CreateAction)
						os.Setenv(ACTION, "create")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.CreateAction)
					}
					if !opts.Flags.Loop {
						done <- true
					}
				}
				if flags&event.Op&fsnotify.Write == fsnotify.Write {
					if opts.Commands.WriteAction != "" {
						v("WRITE: Running '%s'\n", opts.Commands.WriteAction)
						os.Setenv(ACTION, "write")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.WriteAction)
					}
					if !opts.Flags.Loop {
						done <- true
					}
				}
				if flags&event.Op&fsnotify.Remove == fsnotify.Remove {
					if opts.Commands.DeleteAction != "" {
						v("REMOVE: Running '%s'\n", opts.Commands.DeleteAction)
						os.Setenv(ACTION, "delete")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.DeleteAction)
					}
					if !opts.Flags.Loop {
						done <- true
					}
				}
				if flags&event.Op&fsnotify.Rename == fsnotify.Rename {
					if opts.Commands.RenameAction != "" {
						v("RENAME: Running '%s'\n", opts.Commands.RenameAction)
						os.Setenv(ACTION, "rename")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.RenameAction)
					}
					if !opts.Flags.Loop {
						done <- true
					}
				}
				if flags&event.Op&fsnotify.Chmod == fsnotify.Chmod {
					if opts.Commands.ChmodAction != "" {
						v("CHMOD: Running '%s'\n", opts.Commands.ChmodAction)
						os.Setenv(ACTION, "chmod")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.ChmodAction)
					}
					if !opts.Flags.Loop {
						done <- true
					}
				}
			case err := <-watcher.Errors:
				if err.Error() != "" {
					fatal("Error: ", err.Error())
				}
				done <- true
			}
		}
	}()

	for _, dir := range paths {
		v("* %s\n", dir)
		err = watcher.Add(dir)
		if err != nil {
			fatal(err.Error())
		}
	}

	// We'll never return from this without a break signal if in loop mode
	<-done
}

func runCommand(script string) {
	cmd := exec.Command("bash", script)
	err := cmd.Start()
	if err != nil {
		v("Error: %s\n", err)
	}

	err = cmd.Wait()
	if err != nil {
		exit, ok := err.(*exec.ExitError)
		if ok {
			status, ok := exit.Sys().(syscall.WaitStatus)
			if ok {
				if status == 256 || status == 512 {
					os.Exit(0)
					v("Exit code: %d\n", status)
				}
			}
		} else {
			v("Error: %s\n", err)
		}
	}

}
<commit_msg>Phrasing!<commit_after>package main

import (
	"os"
	"os/exec"
	"syscall"

	"github.com/fsnotify/fsnotify"
	"github.com/jessevdk/go-flags"
)

const (
	program = "Sentinel"
	version = "0.4.2"
	// ACTION is the environment variable for the type of notification triggered.
	ACTION = "SENTINEL_ACTION"
	// PATH is the environment variable for the type of notification triggered.
	PATH = "SENTINEL_PATH"
)

var opts struct {
	Verbose bool `short:"v" long:"verbose" description:"Print more details during operation, otherwise remain quiet until an error occurs."`
	Version bool `short:"V" long:"version" description:"Show program version and exit."`
	Flags   struct {
		Create bool `short:"c" long:"create" description:"Watch for new files."`
		Write  bool `short:"w" long:"write" description:"Watch for changed files."`
		Delete bool `short:"d" long:"delete" description:"Watch for deletion."`
		Rename bool `short:"r" long:"rename" description:"Watch for renamed files."`
		Chmod  bool `short:"m" long:"chmod" description:"Watch for attribute changes (date or permissions)."`
	} `group:"Trigger flags"`
	Other struct {
		Loop bool `short:"L" long:"loop" description:"Don't quit after each triggered event."`
	}
	Commands struct {
		CreateAction string `short:"C" long:"createaction" description:"Script to run when a file is created. Implies -c." value-name:"SCRIPT"`
		WriteAction  string `short:"W" long:"writeaction" description:"Script to run when a file is edited. Implies -w." value-name:"SCRIPT"`
		DeleteAction string `short:"D" long:"deleteaction" description:"Script to run when a file is deleted. Implies -d." value-name:"SCRIPT"`
		RenameAction string `short:"R" long:"renameaction" description:"Script to run when a file is renamed. Implies -r." value-name:"SCRIPT"`
		ChmodAction  string `short:"M" long:"chmodaction" description:"Script to run when a file's date or permissions change. Implies -m." value-name:"SCRIPT"`
		ScriptAction string `short:"S" long:"scriptaction" description:"Script to run for all events. Requires any of the trigger flags. Overrides the other scripts." value-name:"SCRIPT"`
	} `group:"Scripts"`
	Args struct {
		Directory []string `positional-arg-name:"PATH"`
	} `positional-args:"yes"`
}

func main() {
	_, err := flags.Parse(&opts)
	if err != nil {
		return
	}

	if opts.Version {
		pr("%s %s\n", program, version)
		return
	}

	if len(opts.Args.Directory) == 0 {
		warn("No paths specified.")
	}
	var paths []string
	for _, d := range opts.Args.Directory {
		if !exists(d) {
			warn("Path %s does not exist.", d)
		}
		paths = append(paths, d)
	}

	// Default: Watch for any changes
	var flags fsnotify.Op

	if opts.Commands.CreateAction != "" {
		opts.Flags.Create = true
	}
	if opts.Flags.Create {
		v("Watching for creation.\n")
		flags |= fsnotify.Create
	}

	if opts.Commands.WriteAction != "" {
		opts.Flags.Write = true
	}
	if opts.Flags.Write {
		v("Watching for write.\n")
		flags |= fsnotify.Write
	}

	if opts.Commands.DeleteAction != "" {
		opts.Flags.Delete = true
	}
	if opts.Flags.Delete {
		v("Watching for delete.\n")
		flags |= fsnotify.Remove
	}

	if opts.Commands.RenameAction != "" {
		opts.Flags.Rename = true
	}
	if opts.Flags.Rename {
		v("Watching for rename.\n")
		flags |= fsnotify.Rename
	}

	if opts.Commands.ChmodAction != "" {
		opts.Flags.Chmod = true
	}
	if opts.Flags.Chmod {
		v("Watching for permission changes.\n")
		flags |= fsnotify.Chmod
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				if flags&event.Op&fsnotify.Create == fsnotify.Create {
					if opts.Commands.CreateAction != "" {
						v("CREATE: Running '%s'\n", opts.Commands.CreateAction)
						os.Setenv(ACTION, "create")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.CreateAction)
					}
					if !opts.Other.Loop {
						done <- true
					}
				}
				if flags&event.Op&fsnotify.Write == fsnotify.Write {
					if opts.Commands.WriteAction != "" {
						v("WRITE: Running '%s'\n", opts.Commands.WriteAction)
						os.Setenv(ACTION, "write")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.WriteAction)
					}
					if !opts.Other.Loop {
						done <- true
					}
				}
				if flags&event.Op&fsnotify.Remove == fsnotify.Remove {
					if opts.Commands.DeleteAction != "" {
						v("REMOVE: Running '%s'\n", opts.Commands.DeleteAction)
						os.Setenv(ACTION, "delete")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.DeleteAction)
					}
					if !opts.Other.Loop {
						done <- true
					}
				}
				if flags&event.Op&fsnotify.Rename == fsnotify.Rename {
					if opts.Commands.RenameAction != "" {
						v("RENAME: Running '%s'\n", opts.Commands.RenameAction)
						os.Setenv(ACTION, "rename")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.RenameAction)
					}
					if !opts.Other.Loop {
						done <- true
					}
				}
				if flags&event.Op&fsnotify.Chmod == fsnotify.Chmod {
					if opts.Commands.ChmodAction != "" {
						v("CHMOD: Running '%s'\n", opts.Commands.ChmodAction)
						os.Setenv(ACTION, "chmod")
						os.Setenv(PATH, event.Name)
						runCommand(opts.Commands.ChmodAction)
					}
					if !opts.Other.Loop {
						done <- true
					}
				}
			case err := <-watcher.Errors:
				if err.Error() != "" {
					fatal("Error: ", err.Error())
				}
				done <- true
			}
		}
	}()

	for _, dir := range paths {
		v("* %s\n", dir)
		err = watcher.Add(dir)
		if err != nil {
			fatal(err.Error())
		}
	}

	// We'll never return from this without a break signal if in loop mode
	<-done
}

func runCommand(script string) {
	cmd := exec.Command("bash", script)
	err := cmd.Start()
	if err != nil {
		v("Error: %s\n", err)
	}

	err = cmd.Wait()
	if err != nil {
		exit, ok := err.(*exec.ExitError)
		if ok {
			status, ok := exit.Sys().(syscall.WaitStatus)
			if ok {
				if status == 256 || status == 512 {
					os.Exit(0)
					v("Exit code: %d\n", status)
				}
			}
		} else {
			v("Error: %s\n", err)
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/iron-io/iron_go3/cache"
	"github.com/iron-io/iron_go3/config"
	"github.com/iron-io/iron_go3/mq"
	"github.com/iron-io/iron_go3/worker"
)

const (
	interval   = 5 * time.Second
	maxRunTime = 30 * time.Minute
	swapi      = "worker-aws-us-east-1.iron.io"
)

const (
	TriggerFixed       = "fixed"
	TriggerProgressive = "progressive"
	TriggerRatio       = "ratio"
)

var (
	prev    map[string]int
	codeIds map[string]string
)

type Config struct {
	Environments map[string]config.Settings `json:"envs"`
	Alerts       []QueueWorkerAlert         `json:"alerts"`
	CacheEnv     string                     `json:"cacheEnv"`
}

type QueueWorkerAlert struct {
	QueueName  string    `json:"queueName"`
	QueueEnv   string    `json:"queueEnv"`
	WorkerName string    `json:"workerName"`
	WorkerEnv  string    `json:"workerEnv"`
	Cluster    string    `json:"cluster"`
	Triggers   []Trigger `json:"triggers"`
}

type Trigger struct {
	Typ   string `json:"type"`
	Value int    `json:"value"`
}

func queueKey(qw QueueWorkerAlert) string {
	return qw.QueueEnv + "|" + qw.QueueName
}

func main() {
	start := time.Now()
	prev = make(map[string]int)
	codeIds = make(map[string]string)

	// Retrieve configuration
	c := &Config{}
	worker.ParseFlags()
	err := worker.ConfigFromJSON(c)
	if err != nil {
		log.Fatalln("Could not unparse config", err)
	}

	if len(c.Alerts) == 0 || len(c.Environments) == 0 {
		fmt.Println("No config set")
		return
	}

	cacheEnv, exists := c.Environments[c.CacheEnv]
	if !exists {
		log.Fatalln("No cache environment set")
		return
	}
	config.ManualConfig("iron_cache", &cacheEnv)
	queueCache := cache.New("autoscale-prevs")

	for {
		if time.Since(start) > maxRunTime {
			fmt.Println("No triggers specified for an alert")
			break
		}

		for _, alert := range c.Alerts {
			if len(alert.Triggers) == 0 {
				fmt.Println("No triggers found for alert")
				continue
			}

			queueSize, prevQueueSize := 0, 0
			key := queueKey(alert)

			// Get previous size
			if _, e := prev[key]; !e {
				v, err := queueCache.Get(key)
				if err != nil {
					fmt.Println("Could not get cache", err)
				} else {
					prev[key] = int(v.(float64))
				}
			}
			prevQueueSize = prev[key]

			queueEnv, exists := c.Environments[alert.QueueEnv]
			if !exists {
				fmt.Printf("Environment %q is not defined for queue %q\n", alert.QueueEnv, alert.QueueName)
				continue
			}

			queueConfig := config.ManualConfig("iron_mq", &queueEnv)
			q := mq.ConfigNew(alert.QueueName, &queueConfig)
			info, err := q.Info()
			if err != nil {
				fmt.Println("Could not get information about", alert.QueueName, err)
				continue
			}

			queueSize = info.Size
			// Update previous size
			queueCache.Set(key, info.Size, 900)
			prev[key] = info.Size

			workerEnv, exists := c.Environments[alert.WorkerEnv]
			if !exists {
				fmt.Printf("Environment %q is not defined for worker %q\n", alert.WorkerEnv, alert.WorkerName)
				continue
			}
			queued, running, err := workerStats(&workerEnv, alert.WorkerName)
			if err != nil {
				fmt.Printf("Could not get code stats for %s, %v", alert.WorkerName, err)
				continue
			}

			launch := evalTriggers(queued, running, queueSize, prevQueueSize, alert.Triggers)
			fmt.Printf("Queue: %s (size=%d, prev=%d), CodeName=%s (queued=%d, running=%d), Launching %d\n", alert.QueueName, queueSize, prevQueueSize, alert.WorkerName, queued, running, launch)

			if launch > 0 {
				workerConfig := config.ManualConfig("iron_worker", &workerEnv)
				w := &worker.Worker{Settings: workerConfig}

				tasks := make([]worker.Task, launch)
				for x := 0; x < len(tasks); x++ {
					tasks[x].CodeName = alert.WorkerName
					tasks[x].Cluster = alert.Cluster
				}

				_, err = w.TaskQueue(tasks...)
				if err != nil {
					fmt.Println("Could not create tasks for", alert.WorkerName)
					continue
				}
			}
		}

		time.Sleep(interval)
	}
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func workerKey(projectID, codeName string) string {
	return projectID + "|" + codeName
}

type CodeStats struct {
	Running int `json:"running"`
	Queued  int `json:"queued"`
	// ignore other states
}

func workerStats(env *config.Settings, codeName string) (queued, running int, err error) {
	codeID, exists := codeIds[workerKey(env.ProjectId, codeName)]
	if !exists {
		workerConfig := config.ManualConfig("iron_worker", env)
		w := &worker.Worker{Settings: workerConfig}
		codes, err := w.CodePackageList(0, 100)
		if err != nil {
			return 0, 0, err
		}

		for _, c := range codes {
			codeIds[workerKey(c.ProjectId, c.Name)] = c.Id
			if c.Name == codeName {
				codeID = c.Id
			}
		}
	}

	if len(codeID) == 0 {
		return 0, 0, fmt.Errorf("Could not get id for %s", codeName)
	}
	if len(env.ProjectId) == 0 || len(env.Token) == 0 {
		return 0, 0, fmt.Errorf("Could not get env for %s", codeName)
	}

	url := fmt.Sprintf("https://%s/2/projects/%s/codes/%s/stats?oauth=%s", swapi, env.ProjectId, codeID, env.Token)
	resp, err := http.Get(url)
	if err != nil {
		return 0, 0, err
	}
	defer resp.Body.Close()
	decoder := json.NewDecoder(resp.Body)
	var s CodeStats
	err = decoder.Decode(&s)
	if err != nil {
		return 0, 0, err
	}

	return s.Queued, s.Running, nil
}

func evalTriggers(queued, running, queueSize, prevQueueSize int, triggers []Trigger) (launch int) {
	for _, t := range triggers {
		switch t.Typ {
		case TriggerFixed:
			if queueSize >= t.Value {
				if t.Value <= prevQueueSize {
					continue
				}
				launch = max(launch, 1)
			}
		case TriggerProgressive:
			if queueSize < t.Value {
				continue
			}

			previous_level := prevQueueSize / t.Value
			current_level := queueSize / t.Value
			if current_level > previous_level {
				launch = max(launch, current_level-previous_level)
			}
		case TriggerRatio:
			expected_runners := (queueSize + t.Value - 1) / t.Value // Only have 0 runners if qsize=0

			diff := expected_runners - (queued + running)
			if diff > 0 {
				launch = max(launch, diff)
			}
		}
	}
	return
}
<commit_msg>Use api's http.Client<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/iron-io/iron_go3/api"
	"github.com/iron-io/iron_go3/cache"
	"github.com/iron-io/iron_go3/config"
	"github.com/iron-io/iron_go3/mq"
	"github.com/iron-io/iron_go3/worker"
)

const (
	interval   = 5 * time.Second
	maxRunTime = 30 * time.Minute
	swapi      = "worker-aws-us-east-1.iron.io"
)

const (
	TriggerFixed       = "fixed"
	TriggerProgressive = "progressive"
	TriggerRatio       = "ratio"
)

var (
	prev    map[string]int
	codeIds map[string]string
	client  *http.Client
)

type Config struct {
	Environments map[string]config.Settings `json:"envs"`
	Alerts       []QueueWorkerAlert         `json:"alerts"`
	CacheEnv     string                     `json:"cacheEnv"`
}

type QueueWorkerAlert struct {
	QueueName  string    `json:"queueName"`
	QueueEnv   string    `json:"queueEnv"`
	WorkerName string    `json:"workerName"`
	WorkerEnv  string    `json:"workerEnv"`
	Cluster    string    `json:"cluster"`
	Triggers   []Trigger `json:"triggers"`
}

type Trigger struct {
	Typ   string `json:"type"`
	Value int    `json:"value"`
}

func queueKey(qw QueueWorkerAlert) string {
	return qw.QueueEnv + "|" + qw.QueueName
}

func main() {
	start := time.Now()
	prev = make(map[string]int)
	codeIds = make(map[string]string)
	client = api.HttpClient

	// Retrieve configuration
	c := &Config{}
	worker.ParseFlags()
	err := worker.ConfigFromJSON(c)
	if err != nil {
		log.Fatalln("Could not unparse config", err)
	}

	if len(c.Alerts) == 0 || len(c.Environments) == 0 {
		fmt.Println("No config set")
		return
	}

	cacheEnv, exists := c.Environments[c.CacheEnv]
	if !exists {
		log.Fatalln("No cache environment set")
		return
	}
	config.ManualConfig("iron_cache", &cacheEnv)
	queueCache := cache.New("autoscale-prevs")

	for {
		if time.Since(start) > maxRunTime {
			fmt.Println("No triggers specified for an alert")
			break
		}

		for _, alert := range c.Alerts {
			if len(alert.Triggers) == 0 {
				fmt.Println("No triggers found for alert")
				continue
			}

			queueSize, prevQueueSize := 0, 0
			key := queueKey(alert)

			// Get previous size
			if _, e := prev[key]; !e {
				v, err := queueCache.Get(key)
				if err != nil {
					fmt.Println("Could not get cache", err)
				} else {
					prev[key] = int(v.(float64))
				}
			}
			prevQueueSize = prev[key]

			queueEnv, exists := c.Environments[alert.QueueEnv]
			if !exists {
				fmt.Printf("Environment %q is not defined for queue %q\n", alert.QueueEnv, alert.QueueName)
				continue
			}

			queueConfig := config.ManualConfig("iron_mq", &queueEnv)
			q := mq.ConfigNew(alert.QueueName, &queueConfig)
			info, err := q.Info()
			if err != nil {
				fmt.Println("Could not get information about", alert.QueueName, err)
				continue
			}
			queueSize = info.Size
			// Update previous size
			go queueCache.Set(key, queueSize, 900)
			prev[key] = queueSize

			workerEnv, exists := c.Environments[alert.WorkerEnv]
			if !exists {
				fmt.Printf("Environment %q is not defined for worker %q\n", alert.WorkerEnv, alert.WorkerName)
				continue
			}
			queued, running, err := workerStats(&workerEnv, alert.WorkerName)
			if err != nil {
				fmt.Printf("Could not get code stats for %s, %v", alert.WorkerName, err)
				continue
			}

			launch := evalTriggers(queued, running, queueSize, prevQueueSize, alert.Triggers)
			fmt.Printf("Queue: %s (size=%d, prev=%d), CodeName=%s (queued=%d, running=%d), Launching %d\n", alert.QueueName, queueSize, prevQueueSize, alert.WorkerName, queued, running, launch)

			if launch > 0 {
				workerConfig := config.ManualConfig("iron_worker", &workerEnv)
				w := &worker.Worker{Settings: workerConfig}

				tasks := make([]worker.Task, launch)
				for x := 0; x < len(tasks); x++ {
					tasks[x].CodeName = alert.WorkerName
					tasks[x].Cluster = alert.Cluster
				}

				_, err = w.TaskQueue(tasks...)
				if err != nil {
					fmt.Println("Could not create tasks for", alert.WorkerName)
					continue
				}
			}
		}

		time.Sleep(interval)
	}
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func workerKey(projectID, codeName string) string {
	return projectID + "|" + codeName
}

type CodeStats struct {
	Running int `json:"running"`
	Queued  int `json:"queued"`
	// ignore other states
}

func workerStats(env *config.Settings, codeName string) (queued, running int, err error) {
	codeID, exists := codeIds[workerKey(env.ProjectId, codeName)]
	if !exists {
		workerConfig := config.ManualConfig("iron_worker", env)
		w := &worker.Worker{Settings: workerConfig}
		codes, err := w.CodePackageList(0, 100)
		if err != nil {
			return 0, 0, err
		}

		for _, c := range codes {
			codeIds[workerKey(c.ProjectId, c.Name)] = c.Id
			if c.Name == codeName {
				codeID = c.Id
			}
		}
	}

	if len(codeID) == 0 {
		return 0, 0, fmt.Errorf("Could not get id for %s", codeName)
	}
	if len(env.ProjectId) == 0 || len(env.Token) == 0 {
		return 0, 0, fmt.Errorf("Could not get env for %s", codeName)
	}

	url := fmt.Sprintf("https://%s/2/projects/%s/codes/%s/stats?oauth=%s", swapi, env.ProjectId, codeID, env.Token)
	resp, err := client.Get(url)
	if err != nil {
		return 0, 0, err
	}
	defer resp.Body.Close()
	decoder := json.NewDecoder(resp.Body)
	var s CodeStats
	err = decoder.Decode(&s)
	if err != nil {
		return 0, 0, err
	}

	return s.Queued, s.Running, nil
}

func evalTriggers(queued, running, queueSize, prevQueueSize int, triggers []Trigger) (launch int) {
	for _, t := range triggers {
		switch t.Typ {
		case TriggerFixed:
			if queueSize >= t.Value {
				if t.Value <= prevQueueSize {
					continue
				}
				launch = max(launch, 1)
			}
		case TriggerProgressive:
			if queueSize < t.Value {
				continue
			}

			previous_level := prevQueueSize / t.Value
			current_level := queueSize / t.Value
			if current_level > previous_level {
				launch = max(launch, current_level-previous_level)
			}
		case TriggerRatio:
			expected_runners := (queueSize + t.Value - 1) / t.Value // Only have 0 runners if qsize=0

			diff := expected_runners - (queued + running)
			if diff > 0 {
				launch = max(launch, diff)
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {
	fmt.Println("Hello hugoku!")
}
<commit_msg>Added basic routes and render of the home page template.<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"text/template"

	"github.com/julienschmidt/httprouter"
)

func main() {
	fmt.Println("Hello hugoku!")
	Serve()
}

// Serve set the route handlers and serve
func Serve() {

	router := httprouter.New()
	router.GET("/", Index)
	router.GET("/login", GithubLogin)
	router.GET("/project/:id", GetProject)

	log.Fatal(http.ListenAndServe(":8080", router))
}

// Index is the Hugoku home page handler will redirect a non logged user to do the loging with Github
// or show a list of projectst and a form to add a project to a logged user,
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	//fmt.Fprint(w, "Hugoku home page!\n")
	t, err := template.ParseFiles("templates/index.html")
	if err != nil {
		log.Fatal("Error parsing the home page template")
	}
	t.Execute(w, nil)
}

func GithubLogin(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprint(w, "GithubLogin\n")
}

// GetProject is the Hugoku project page handdler and shows the project and the build history.
func GetProject(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	var id = ps.ByName("id")
	// TODO: sanitize id
	fmt.Fprintf(w, "GetProject %s!\n", id)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"os"
	"path"
	"reflect"
	"sort"
	"strings"

	"github.com/nelsam/gxui/drivers/gl"
)

var (
	appMaster map[string][]prtap
	cats      []string
	wineOnly  []string
	linOnly   []string
	conf      *os.File
	common    string
	commEnbl  bool
)

type prtap struct {
	name string
	cat  string
	ex   string
	desc string
	wine bool
}

func main() {
	commEnbl = true
	appMaster = make(map[string][]prtap)
	os.Mkdir("PortableApps", 0777)
	os.Mkdir("PortableApps/LinuxPACom", 0777)
	common = "PortableApps/LinuxPACom/common.sh"
	_, err := os.Open(common)
	if os.IsNotExist(err) {
		commEnbl = false
	}
	pa, err := os.Open("PortableApps")
	if err != nil {
		panic(err)
	}
	appstmp, _ := pa.Readdir(-1)
	var folds []string
	for _, v := range appstmp {
		if v.IsDir() && v.Name() != "LinuxPACom" && v.Name() != "PortableApps.com" {
			folds = append(folds, v.Name())
		}
	}
	sort.Strings(folds)
	for _, v := range folds {
		fi, _ := os.Open("PortableApps/" + v)
		pat := processApp(fi)
		if (pat != prtap{}) {
			if _, ok := appMaster[pat.cat]; !ok {
				if pat.wine {
					wineOnly = append(wineOnly, pat.cat)
					cats = append(cats, pat.cat)
				} else {
					linOnly = append(linOnly, pat.cat)
					cats = append(cats, pat.cat)
				}
			} else {
				if !pat.wine {
					for i, v := range wineOnly {
						if pat.cat == v {
							wineOnly = append(wineOnly[:i], wineOnly[i+1:]...)
							break
						}
					}
				}
			}
			appMaster[pat.cat] = append(appMaster[pat.cat], pat)
		}
	}
	sort.Strings(linOnly)
	sort.Strings(wineOnly)
	sort.Strings(cats)
	gl.StartDriver(uiMain)
}

func processApp(fi *os.File) (out prtap) {
	fis, _ := fi.Readdir(-1)
	if fil, err := os.Open(fi.Name() + "/App/AppInfo/appinfo.ini"); err == nil {
		out.name = getName(fil)
		fil, _ = os.Open(fi.Name() + "/App/AppInfo/appinfo.ini")
		out.cat = getCat(fil)
	} else if fil, err := os.Open(fi.Name() + "/appinfo.ini"); err == nil {
		out.name = getName(fil)
		fil, _ = os.Open(fi.Name() + "/appinfo.ini")
		out.cat = getCat(fil)
	} else {
		out.cat = "Other"
	}
	if out.name == "" {
		out.name = path.Base(fi.Name())
	}
	if out.cat == "" {
		out.cat = "Other"
	}
	//executable detection
	wd, _ := os.Getwd()
	var rdr *bufio.Reader
	for _, v := range fis {
		fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
		if err == nil {
			stat, _ := fil.Stat()
			if !stat.IsDir() {
				rdr = bufio.NewReader(fil)
				shebang := []byte{'#', '!'}
				two := make([]byte, 2)
				rdr.Read(two)
				if reflect.DeepEqual(shebang, two) {
					out.ex = wd + "/" + fi.Name() + "/" + v.Name()
					rdr.Reset(fil)
					return
				}
			}
		}
	}
	for _, v := range fis {
		fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
		if err == nil {
			stat, _ := fil.Stat()
			if !stat.IsDir() {
				rdr = bufio.NewReader(fil)
				thr := make([]byte, 4)
				rdr.Read(thr)
				if strings.Contains(string(thr), "ELF") {
					out.ex = wd + "/" + fi.Name() + "/" + v.Name()
					rdr.Reset(fil)
					return
				}
			}
		}
	}
	for _, v := range fis {
		fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
		if err == nil {
			stat, _ := fil.Stat()
			if !stat.IsDir() && strings.HasSuffix(stat.Name(), "exe") {
				out.wine = true
				out.ex = wd + "/" + fi.Name() + "/" + v.Name()
				out.name += " (Wine)"
				return
			}
		}
	}
	return prtap{}
}

func getCat(fi *os.File) (out string) {
	rdr := bufio.NewReader(fi)
	var err error
	var ln []byte
	for err == nil {
		ln, _, err = rdr.ReadLine()
		str := string(ln)
		if strings.HasPrefix(str, "Category=") {
			out = strings.TrimPrefix(str, "Category=")
			return
		}
	}
	return
}

func getName(fi *os.File) (out string) {
	rdr := bufio.NewReader(fi)
	var err error
	var ln []byte
	for err == nil {
		ln, _, err = rdr.ReadLine()
		str := string(ln)
		if strings.HasPrefix(str, "Name=") {
			out = strings.TrimPrefix(str, "Name=")
			return
		}
	}
	return
}
<commit_msg>fix with wine<commit_after>package main

import (
	"bufio"
	"os"
	"path"
	"reflect"
	"sort"
	"strings"

	"github.com/nelsam/gxui/drivers/gl"
)

var (
	appMaster map[string][]prtap
	cats      []string
	wineOnly  []string
	linOnly   []string
	conf      *os.File
	common    string
	commEnbl  bool
)

type prtap struct {
	name string
	cat  string
	ex   string
	desc string
	wine bool
}

func main() {
	commEnbl = true
	appMaster = make(map[string][]prtap)
	os.Mkdir("PortableApps", 0777)
	os.Mkdir("PortableApps/LinuxPACom", 0777)
	common = "PortableApps/LinuxPACom/common.sh"
	_, err := os.Open(common)
	if os.IsNotExist(err) {
		commEnbl = false
	}
	pa, err := os.Open("PortableApps")
	if err != nil {
		panic(err)
	}
	appstmp, _ := pa.Readdir(-1)
	var folds []string
	for _, v := range appstmp {
		if v.IsDir() && v.Name() != "LinuxPACom" && v.Name() != "PortableApps.com" {
			folds = append(folds, v.Name())
		}
	}
	sort.Strings(folds)
	for _, v := range folds {
		fi, _ := os.Open("PortableApps/" + v)
		pat := processApp(fi)
		if (pat != prtap{}) {
			if _, ok := appMaster[pat.cat]; !ok {
				if pat.wine {
					wineOnly = append(wineOnly, pat.cat)
					cats = append(cats, pat.cat)
				} else {
					linOnly = append(linOnly, pat.cat)
					cats = append(cats, pat.cat)
				}
			} else {
				if !pat.wine {
					for i, v := range wineOnly {
						if pat.cat == v {
							wineOnly = append(wineOnly[:i], wineOnly[i+1:]...)
							linOnly = append(linOnly, pat.cat)
							break
						}
					}
				}
			}
			appMaster[pat.cat] = append(appMaster[pat.cat], pat)
		}
	}
	sort.Strings(linOnly)
	sort.Strings(wineOnly)
	sort.Strings(cats)
	gl.StartDriver(uiMain)
}

func processApp(fi *os.File) (out prtap) {
	fis, _ := fi.Readdir(-1)
	if fil, err := os.Open(fi.Name() + "/App/AppInfo/appinfo.ini"); err == nil {
		out.name = getName(fil)
		fil, _ = os.Open(fi.Name() + "/App/AppInfo/appinfo.ini")
		out.cat = getCat(fil)
	} else if fil, err := os.Open(fi.Name() + "/appinfo.ini"); err == nil {
		out.name = getName(fil)
		fil, _ = os.Open(fi.Name() + "/appinfo.ini")
		out.cat = getCat(fil)
	} else {
		out.cat = "Other"
	}
	if out.name == "" {
		out.name = path.Base(fi.Name())
	}
	if out.cat == "" {
		out.cat = "Other"
	}
	//executable detection
	wd, _ := os.Getwd()
	var rdr *bufio.Reader
	for _, v := range fis {
		fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
		if err == nil {
			stat, _ := fil.Stat()
			if !stat.IsDir() {
				rdr = bufio.NewReader(fil)
				shebang := []byte{'#', '!'}
				two := make([]byte, 2)
				rdr.Read(two)
				if reflect.DeepEqual(shebang, two) {
					out.ex = wd + "/" + fi.Name() + "/" + v.Name()
					rdr.Reset(fil)
					return
				}
			}
		}
	}
	for _, v := range fis {
		fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
		if err == nil {
			stat, _ := fil.Stat()
			if !stat.IsDir() {
				rdr = bufio.NewReader(fil)
				thr := make([]byte, 4)
				rdr.Read(thr)
				if strings.Contains(string(thr), "ELF") {
					out.ex = wd + "/" + fi.Name() + "/" + v.Name()
					rdr.Reset(fil)
					return
				}
			}
		}
	}
	for _, v := range fis {
		fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
		if err == nil {
			stat, _ := fil.Stat()
			if !stat.IsDir() && strings.HasSuffix(stat.Name(), "exe") {
				out.wine = true
				out.ex = wd + "/" + fi.Name() + "/" + v.Name()
				out.name += " (Wine)"
				return
			}
		}
	}
	return prtap{}
}

func getCat(fi *os.File) (out string) {
	rdr := bufio.NewReader(fi)
	var err error
	var ln []byte
	for err == nil {
		ln, _, err = rdr.ReadLine()
		str := string(ln)
		if strings.HasPrefix(str, "Category=") {
			out = strings.TrimPrefix(str, "Category=")
			return
		}
	}
	return
}

func getName(fi *os.File) (out string) {
	rdr := bufio.NewReader(fi)
	var err error
	var ln []byte
	for err == nil {
		ln, _, err = rdr.ReadLine()
		str := string(ln)
		if strings.HasPrefix(str, "Name=") {
			out = strings.TrimPrefix(str, "Name=")
			return
		}
	}
	return
}
<|endoftext|>