<commit_before>package main

import (
	"fmt"
	"log"
	"regexp"
	"net/url"
//	"net/smtp"	// TODO: Find a workaround for problem with self-signed TLS cert

	"gopkg.in/gcfg.v1"						// Config file parser
	"github.com/ChimeraCoder/anaconda"		// Twitter API
)

// Config
type Config struct {
	Auth struct {
		ConsumerKey       string
		ConsumerSecret    string
		AccessToken       string
		AccessTokenSecret string
	}
	Auth2 struct {
		ConsumerKey       string
		ConsumerSecret    string
		AccessToken       string
		AccessTokenSecret string
	}
	Settings struct {
		FriendsCount      string
		FollowerCount     string
		MentionsCount     string
	}
	Email struct {
		Server            string
		ServerPort        string
		AuthUsername      string
		AuthPassword      string
		FromAddress       string
		AdminAddress      string
	}
}

// Load config, connect to Twitter API, fetch and check mentions, block and notify users where necessary
func main() {
	// Get config from file
	cfg := getConfig( "config.gcfg" )

	// Initialise and authenticate API objects
	anaconda.SetConsumerKey( cfg.Auth.ConsumerKey )
	anaconda.SetConsumerSecret( cfg.Auth.ConsumerSecret )
	api := anaconda.NewTwitterApi( cfg.Auth.AccessToken, cfg.Auth.AccessTokenSecret )

	// Get friends' and followers' IDs
	friendsIds   := getFriendIDs(    cfg.Settings.FriendsCount,  api )
	followersIds := getFollowersIDs( cfg.Settings.FollowerCount, api )

	// Get mentions
	mentions := getMentions( cfg.Settings.MentionsCount, api )

	// Run through mentions checking against friend/follower lists and block criteria
	for _ , tweet := range mentions {
		fmt.Println( "<" + tweet.User.ScreenName + ">", tweet.Text )
		// Check to see if tweet was posted by a friend
		if ! friendsIds[ tweet.User.Id ] && ! followersIds[ tweet.User.Id ] {
			// Not a friend or follower - check the tweet content against block rules
			checkTweet( tweet, cfg, api )
		}
	}
}

// Read config file
func getConfig( filename string ) ( *Config ) {
	cfg := new( Config )
	cfgerr := gcfg.ReadFileInto( cfg, filename )
	if cfgerr != nil { log.Fatalf( "Failed to parse gcfg data: %s", cfgerr ) }
	return( cfg )
}

// Get friends' user IDs
func getFriendIDs( friendsCount string, api *anaconda.TwitterApi ) ( map[int64]bool ) {
	params := url.Values{}
	params.Set( "count", friendsCount )

	// Get the list of IDs from the API
	friendsIdsAll, err := api.GetFriendsIds( params )
	if err != nil { log.Fatalf( "Failed to get friends data: %s", err ) }
	friendsIdsTemp := friendsIdsAll.Ids

	// Create a map
	friendsIds := make( map[int64]bool )
	for _ , friendId := range friendsIdsTemp {
		friendsIds[ friendId ] = true
	}

	return( friendsIds )
}

// Get followers' user IDs
func getFollowersIDs( followerCount string, api *anaconda.TwitterApi ) ( map[int64]bool ) {
	params := url.Values{}
	params.Set( "count", followerCount )

	// Get the list of IDs from the API
	followerIdsAll, err := api.GetFollowersIds( params )
	if err != nil { log.Fatalf( "Failed to get followers data: %s", err ) }
	followerIdsTemp := followerIdsAll.Ids

	// Create a map
	followerIds := make( map[int64]bool )
	for _ , followerId := range followerIdsTemp {
		followerIds[ followerId ] = true
	}

	return( followerIds )
}

// Get mentions
func getMentions( mentionsCount string, api *anaconda.TwitterApi ) ( []anaconda.Tweet ) {
	params := url.Values{}
	params.Set( "count", mentionsCount )

	// TODO: Track tweet ID we checked up to last time, and check from there onwards

	mentions, err := api.GetMentionsTimeline( params )
	if err != nil { log.Fatalf( "Failed to get mentions: %s", err ) }

	return( mentions )
}

// Check a tweet to see if it matches any of the block rules
// TODO: Pull the rules out into a config file (or database?)
func checkTweet( tweet anaconda.Tweet, cfg *Config, api *anaconda.TwitterApi ) {
	// Body text
	textRules := map[string]string {
		// Celebrities
		"(?i)Hamlin":  "dennyhamlin",	// Denny Hamlin - NASCAR driver
		"(?i)NASCAR":  "dennyhamlin",	// ""
		"(?i)Cagur":   "dennycagur",	// Denny Cagur - Indonesian actor
		"(?i)Sumargo": "dennysumargo",	// Denny Sumargo - Indonesian basketball player
		"(?i)Gitong":  "dennygitong",	// Denny Gitong - Indonesian comedian
		// Denny's Diner
		"(?i)^@Denny's$": "atdennys",
		"(?i)@Denny's.+(breakfast|lunch|dinner|food|coffee|milkshake|Grand Slam|diner|waitress|service|smash)": "dennysdiner",
		"(?i)(breakfast|lunch|dinner|food|coffee|milkshake|Grand Slam|diner|waitress|service|fam |smash).+@Denny's": "dennysdiner" }

	for rule, ruleName := range textRules {
		match, err := regexp.MatchString( rule, tweet.Text )
		if err != nil { log.Fatalf( "Regexp failed: %s", err ) }
		if match {
			blockUser( tweet.User, ruleName, cfg, api )
//			emailNotification( tweet, ruleName, cfg )
			return
		}
	}

	// Location
	locationRules := map[string]string {
		// Indonesia in general is a problem for me on Twitter, unfortunately!
		"(?i)Indonesia": "indonesia",
		"(?i)Jakarta":   "indonesia",
		"(?i)Bandung":   "indonesia",
		"(?i)Padang":    "indonesia",
	}

	for rule, ruleName := range locationRules {
		location := tweet.Place.Country + " " + tweet.Place.Name + " " + tweet.Place.FullName
		match, err := regexp.MatchString( rule, location )
		if err != nil { log.Fatalf( "Regexp failed: %s", err ) }
		if match {
			blockUser( tweet.User, ruleName, cfg, api )
//			emailNotification( tweet, ruleName, cfg )
			return
		}
	}
}

// Block a user, and tweet a notification of why they were blocked
func blockUser( user anaconda.User, ruleName string, cfg *Config, api *anaconda.TwitterApi ) {
	// Block the user from the main account
	user, err1 := api.BlockUserId( user.Id, nil )
	if err1 != nil { log.Fatalf( "Failed to block user: %s", err1 ) }

	// Let them know via the notification account
	anaconda.SetConsumerKey( cfg.Auth2.ConsumerKey )
	anaconda.SetConsumerSecret( cfg.Auth2.ConsumerSecret )
	api2 := anaconda.NewTwitterApi( cfg.Auth2.AccessToken, cfg.Auth2.AccessTokenSecret )

	tweet, err2 := api2.PostTweet( "@" + user.ScreenName +
		": Hi! You've been blocked by @Denny. Reason: "  +
		"http://denny.me/blockbot/reason.html#" + ruleName,
		nil )
	if err2 != nil { log.Fatalf( "Failed to notify blocked user: %s", err2 ) }

	// Display tweet in terminal
	fmt.Println( ">> " + tweet.Text )

	// Restore API to main account auth settings
	anaconda.SetConsumerKey( cfg.Auth.ConsumerKey )
	anaconda.SetConsumerSecret( cfg.Auth.ConsumerSecret )
}

// Send an email letting admin know that bot did something
// TODO: Find a workaround for problem with self-signed TLS cert
func emailNotification( tweet anaconda.Tweet, ruleName string, cfg *Config ) {
	// Create the email body text
	body := "From: " + cfg.Email.FromAddress + "\n" +
			"To: " + cfg.Email.AdminAddress + "\n" +
			"\n" +
			"Your block bot just blocked " + tweet.User.ScreenName +
			" for the following tweet: " + tweet.Text + "\n"
	// Display email in terminal too
	fmt.Println( body )

	// TODO: Need one of these two flags to exist?
	// smtp.ServerInfo.AcceptSelfSignedCert = true
	// smtp.ServerInfo.UseTLS = false

/*
	// Set up authentication details
	auth := smtp.PlainAuth(
		"",
		cfg.Email.AuthUsername,
		cfg.Email.AuthPassword,
		cfg.Email.Server,
	)

	// Connect to SMTP server and send the email
	err := smtp.SendMail(
		cfg.Email.Server + ":" + cfg.Email.ServerPort,
		auth,
		cfg.Email.FromAddress,
		[]string{ cfg.Email.AdminAddress },
		[]byte( body ),
	)
	if err != nil { log.Fatal( err ) }
*/
}

<commit_msg>Trying (and failing) to set InReplyTo on notification tweets.<commit_after>package main

import (
	"fmt"
	"log"
	"regexp"
	"net/url"
//	"net/smtp"	// TODO: Find a workaround for problem with self-signed TLS cert

	"gopkg.in/gcfg.v1"						// Config file parser
	"github.com/ChimeraCoder/anaconda"		// Twitter API
)

// Config
type Config struct {
	Auth struct {
		ConsumerKey       string
		ConsumerSecret    string
		AccessToken       string
		AccessTokenSecret string
	}
	Auth2 struct {
		ConsumerKey       string
		ConsumerSecret    string
		AccessToken       string
		AccessTokenSecret string
	}
	Settings struct {
		FriendsCount      string
		FollowerCount     string
		MentionsCount     string
	}
	Email struct {
		Server            string
		ServerPort        string
		AuthUsername      string
		AuthPassword      string
		FromAddress       string
		AdminAddress      string
	}
}

// Load config, connect to Twitter API, fetch and check mentions, block and notify users where necessary
func main() {
	// Get config from file
	cfg := getConfig( "config.gcfg" )

	// Initialise and authenticate API objects
	anaconda.SetConsumerKey( cfg.Auth.ConsumerKey )
	anaconda.SetConsumerSecret( cfg.Auth.ConsumerSecret )
	api := anaconda.NewTwitterApi( cfg.Auth.AccessToken, cfg.Auth.AccessTokenSecret )

	// Get friends' and followers' IDs
	friendsIds   := getFriendIDs(    cfg.Settings.FriendsCount,  api )
	followersIds := getFollowersIDs( cfg.Settings.FollowerCount, api )

	// Get mentions
	mentions := getMentions( cfg.Settings.MentionsCount, api )

	// Run through mentions checking against friend/follower lists and block criteria
	for _ , tweet := range mentions {
		fmt.Println( "<" + tweet.User.ScreenName + ">", tweet.Text )
		// Check to see if tweet was posted by a friend
		if ! friendsIds[ tweet.User.Id ] && ! followersIds[ tweet.User.Id ] {
			// Not a friend or follower - check the tweet content against block rules
			checkTweet( tweet, cfg, api )
		}
	}
}

// Read config file
func getConfig( filename string ) ( *Config ) {
	cfg := new( Config )
	cfgerr := gcfg.ReadFileInto( cfg, filename )
	if cfgerr != nil { log.Fatalf( "Failed to parse gcfg data: %s", cfgerr ) }
	return( cfg )
}

// Get friends' user IDs
func getFriendIDs( friendsCount string, api *anaconda.TwitterApi ) ( map[int64]bool ) {
	params := url.Values{}
	params.Set( "count", friendsCount )

	// Get the list of IDs from the API
	friendsIdsAll, err := api.GetFriendsIds( params )
	if err != nil { log.Fatalf( "Failed to get friends data: %s", err ) }
	friendsIdsTemp := friendsIdsAll.Ids

	// Create a map
	friendsIds := make( map[int64]bool )
	for _ , friendId := range friendsIdsTemp {
		friendsIds[ friendId ] = true
	}

	return( friendsIds )
}

// Get followers' user IDs
func getFollowersIDs( followerCount string, api *anaconda.TwitterApi ) ( map[int64]bool ) {
	params := url.Values{}
	params.Set( "count", followerCount )

	// Get the list of IDs from the API
	followerIdsAll, err := api.GetFollowersIds( params )
	if err != nil { log.Fatalf( "Failed to get followers data: %s", err ) }
	followerIdsTemp := followerIdsAll.Ids

	// Create a map
	followerIds := make( map[int64]bool )
	for _ , followerId := range followerIdsTemp {
		followerIds[ followerId ] = true
	}

	return( followerIds )
}

// Get mentions
func getMentions( mentionsCount string, api *anaconda.TwitterApi ) ( []anaconda.Tweet ) {
	params := url.Values{}
	params.Set( "count", mentionsCount )

	// TODO: Track tweet ID we checked up to last time, and check from there onwards

	mentions, err := api.GetMentionsTimeline( params )
	if err != nil { log.Fatalf( "Failed to get mentions: %s", err ) }

	return( mentions )
}

// Check a tweet to see if it matches any of the block rules
// TODO: Pull the rules out into a config file (or database?)
func checkTweet( tweet anaconda.Tweet, cfg *Config, api *anaconda.TwitterApi ) {
	// Body text
	textRules := map[string]string {
		// Celebrities
		"(?i)Hamlin":  "dennyhamlin",	// Denny Hamlin - NASCAR driver
		"(?i)NASCAR":  "dennyhamlin",	// ""
		"(?i)Cagur":   "dennycagur",	// Denny Cagur - Indonesian actor
		"(?i)Sumargo": "dennysumargo",	// Denny Sumargo - Indonesian basketball player
		"(?i)Gitong":  "dennygitong",	// Denny Gitong - Indonesian comedian
		// Denny's Diner
		"(?i)^@Denny's$": "atdennys",
		"(?i)@Denny's.+(breakfast|lunch|dinner|food|coffee|milkshake|Grand Slam|diner|waitress|service|smash|IHOP)": "dennysdiner",
		"(?i)(breakfast|lunch|dinner|food|coffee|milkshake|Grand Slam|diner|waitress|service|fam |smash|IHOP).+@Denny's": "dennysdiner" }

	for rule, ruleName := range textRules {
		match, err := regexp.MatchString( rule, tweet.Text )
		if err != nil { log.Fatalf( "Regexp failed: %s", err ) }
		if match {
			blockUser( tweet, ruleName, cfg, api )
//			emailNotification( tweet, ruleName, cfg )
			return
		}
	}

	// Location
	locationRules := map[string]string {
		// Indonesia in general is a problem for me on Twitter, unfortunately!
		"(?i)Indonesia": "indonesia",
		"(?i)Jakarta":   "indonesia",
		"(?i)Bandung":   "indonesia",
		"(?i)Padang":    "indonesia",
	}

	for rule, ruleName := range locationRules {
		location := tweet.Place.Country + " " + tweet.Place.Name + " " + tweet.Place.FullName
		match, err := regexp.MatchString( rule, location )
		if err != nil { log.Fatalf( "Regexp failed: %s", err ) }
		if match {
			blockUser( tweet, ruleName, cfg, api )
//			emailNotification( tweet, ruleName, cfg )
			return
		}
	}
}

// Block a user, and tweet a notification of why they were blocked
func blockUser( tweet anaconda.Tweet, ruleName string, cfg *Config, api *anaconda.TwitterApi ) {
	// Block the user from the main account
	user, err1 := api.BlockUserId( tweet.User.Id, nil )
	if err1 != nil { log.Fatalf( "Failed to block user: %s", err1 ) }

	// Let them know via the notification account
	anaconda.SetConsumerKey( cfg.Auth2.ConsumerKey )
	anaconda.SetConsumerSecret( cfg.Auth2.ConsumerSecret )
	api2 := anaconda.NewTwitterApi( cfg.Auth2.AccessToken, cfg.Auth2.AccessTokenSecret )

	params := url.Values{}
	params.Set( "InReplyToStatusID",    tweet.IdStr )
	params.Set( "InReplyToStatusIdStr", tweet.IdStr )

	tweet2, err2 := api2.PostTweet( "@" + user.ScreenName +
		": Hi! You've been blocked by @Denny. Reason: "  +
		"http://denny.me/blockbot/reason.html#" + ruleName, params )
	if err2 != nil { log.Fatalf( "Failed to notify blocked user: %s", err2 ) }

	// Display tweet in terminal
	fmt.Println( ">> " + tweet2.Text )

	// Restore API to main account auth settings
	anaconda.SetConsumerKey( cfg.Auth.ConsumerKey )
	anaconda.SetConsumerSecret( cfg.Auth.ConsumerSecret )
}

// Send an email letting admin know that bot did something
// TODO: Find a workaround for problem with self-signed TLS cert
func emailNotification( tweet anaconda.Tweet, ruleName string, cfg *Config ) {
	// Create the email body text
	body := "From: " + cfg.Email.FromAddress + "\n" +
			"To: " + cfg.Email.AdminAddress + "\n" +
			"\n" +
			"Your block bot just blocked " + tweet.User.ScreenName +
			" for the following tweet: " + tweet.Text + "\n"
	// Display email in terminal too
	fmt.Println( body )

	// TODO: Need one of these two flags to exist?
	// smtp.ServerInfo.AcceptSelfSignedCert = true
	// smtp.ServerInfo.UseTLS = false

/*
	// Set up authentication details
	auth := smtp.PlainAuth(
		"",
		cfg.Email.AuthUsername,
		cfg.Email.AuthPassword,
		cfg.Email.Server,
	)

	// Connect to SMTP server and send the email
	err := smtp.SendMail(
		cfg.Email.Server + ":" + cfg.Email.ServerPort,
		auth,
		cfg.Email.FromAddress,
		[]string{ cfg.Email.AdminAddress },
		[]byte( body ),
	)
	if err != nil { log.Fatal( err ) }
*/
}

<|endoftext|>


<commit_before>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016
	All Rights Reserved

	For Licensing and Usage information, please see LICENSE.md
*/
package input

import (
	"os"
	"io"
	"path"
	"regexp"
	"syscall"
	"io/ioutil"
    "path/filepath"
	"encoding/binary"
)

import (
	"fmt"
)

////////////////////////////////////////////////////////////////////////////////

type FT5406 struct {
	device string
	file   *os.File
	poll   int
	event  syscall.EpollEvent
}

type FT5406Callback func (syscall.EpollEvent)

type FT5406Event struct {
	Second uint32
	Microsecond uint32
	Type uint16
	Code uint16
	Value uint32
}

////////////////////////////////////////////////////////////////////////////////

const (
	PATH_INPUT_DEVICES = "/sys/class/input/event*"
	MAX_POLL_EVENTS = 32
	MAX_EVENT_SIZE_BYTES = 1024
)

////////////////////////////////////////////////////////////////////////////////

var (
	REGEXP_DEVICENAME = regexp.MustCompile("^FT5406")
)

////////////////////////////////////////////////////////////////////////////////
// Create Touchscreen

func NewFT5406() (*FT5406, error) {
	var err error

	this := new(FT5406)
	this.device, err = getDeviceName()
	if err != nil {
		return nil,err
	}

	// open driver
	this.file, err = os.Open(this.device)
	if err != nil {
		return nil, err
	}

	// create a poll
	this.poll, err = syscall.EpollCreate1(0)
	if err != nil {
		this.file.Close()
		return nil, err
	}

	// register the poll with the device
	this.event.Events = syscall.EPOLLIN
	this.event.Fd = int32(this.file.Fd())
	if err = syscall.EpollCtl(this.poll,syscall.EPOLL_CTL_ADD,int(this.event.Fd),&this.event); err != nil {
		syscall.Close(this.poll)
		this.file.Close()
		return nil,err
	}

	return this, nil
}

func (this *FT5406) Close() error {
	syscall.Close(this.poll)
	this.file.Close()
	return nil
}

func (this *FT5406) waitForEvents(callback FT5406Callback) error {
	events := make([]syscall.EpollEvent,MAX_POLL_EVENTS)
	for {
		n, err := syscall.EpollWait(this.poll, events, -1)
		if err != nil {
			return err
		}
		if n <= 0 {
			continue
		}
		for _, event := range events[:n] {
			if event.Fd != int32(this.file.Fd()) {
				continue
			}
			callback(event)
		}
	}
}

func (this *FT5406) ProcessEvents() {
	this.waitForEvents(func(event syscall.EpollEvent) {
		for {
			var event FT5406Event
			err := binary.Read(this.file,binary.LittleEndian,&event)
			if err == io.EOF {
				break
			}
			if err != nil {
				fmt.Println("Decode error:",err)
			} else {
				fmt.Println(event)
			}
		}
	})
}

////////////////////////////////////////////////////////////////////////////////
// Private Methods

func getDeviceName() (string,error) {
	files, err := filepath.Glob(PATH_INPUT_DEVICES)
	if err != nil {
		return "",err
	}
	for _, file := range files {
		buf, err := ioutil.ReadFile(path.Join(file,"device","name"))
		if err != nil {
			continue
		}
		if REGEXP_DEVICENAME.Match(buf) {
			return path.Join("/","dev","input",path.Base(file)),nil
		}
	}
	return "",nil
}
<commit_msg>Working on touchscreen driver<commit_after>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016
	All Rights Reserved

	For Licensing and Usage information, please see LICENSE.md
*/
package input

import (
	"os"
	"io"
	"path"
	"regexp"
	"syscall"
	"errors"
	"time"
	"io/ioutil"
    "path/filepath"
	"encoding/binary"
)

import (
	"fmt"
)

////////////////////////////////////////////////////////////////////////////////

type FT5406 struct {
	device string
	file   *os.File
	poll   int
	event  syscall.EpollEvent
}

type FT5406Callback func (syscall.EpollEvent)

type FT5406Event struct {
	Second uint32
	Microsecond uint32
	Type uint16
	Code uint16
	Value uint32
}

////////////////////////////////////////////////////////////////////////////////

const (
	PATH_INPUT_DEVICES = "/sys/class/input/event*"
	MAX_POLL_EVENTS = 32
	MAX_EVENT_SIZE_BYTES = 1024
)

const ( // https://www.kernel.org/doc/Documentation/input/event-codes.txt
	EV_SYN uint16 = 0
	EV_KEY uint16 = 1
	EV_ABS uint16 = 3
	BTN_TOUCH uint16 = 330
	BTN_TOUCH_RELEASE uint32 = 0
	BTN_TOUCH_PRESS uint32 = 1
	ABS_X uint16 = 0
	ABS_Y uint16 = 1
	ABS_MT_SLOT uint16 = 0x2F // 47 MT slot being modified
	ABS_MT_POSITION_X uint16 = 0x35 // 53 Center X of multi touch position
	ABS_MT_POSITION_Y uint16 = 0x36 // 54 Center Y of multi touch position
	ABS_MT_TRACKING_ID uint16 = 0x39 // 57 Unique ID of initiated contact
)

////////////////////////////////////////////////////////////////////////////////

var (
	REGEXP_DEVICENAME = regexp.MustCompile("^FT5406")
)

////////////////////////////////////////////////////////////////////////////////
// Create Touchscreen

func NewFT5406() (*FT5406, error) {
	var err error

	this := new(FT5406)
	this.device, err = getDeviceName()
	if err != nil {
		return nil,err
	}

	// open driver
	this.file, err = os.Open(this.device)
	if err != nil {
		return nil, err
	}

	// create a poll
	this.poll, err = syscall.EpollCreate1(0)
	if err != nil {
		this.file.Close()
		return nil, err
	}

	// register the poll with the device
	this.event.Events = syscall.EPOLLIN
	this.event.Fd = int32(this.file.Fd())
	if err = syscall.EpollCtl(this.poll,syscall.EPOLL_CTL_ADD,int(this.event.Fd),&this.event); err != nil {
		syscall.Close(this.poll)
		this.file.Close()
		return nil,err
	}

	return this, nil
}

func (this *FT5406) Close() error {
	syscall.Close(this.poll)
	this.file.Close()
	return nil
}

func (this *FT5406) waitForEvents(callback FT5406Callback) error {
	events := make([]syscall.EpollEvent,MAX_POLL_EVENTS)
	for {
		n, err := syscall.EpollWait(this.poll, events, -1)
		if err != nil {
			return err
		}
		if n <= 0 {
			continue
		}
		for _, event := range events[:n] {
			if event.Fd != int32(this.file.Fd()) {
				continue
			}
			callback(event)
		}
	}
}

func (this *FT5406) ProcessEvents() {
	this.waitForEvents(func(event syscall.EpollEvent) {
		for {
			var event FT5406Event
			err := binary.Read(this.file,binary.LittleEndian,&event)
			if err == io.EOF {
				break
			}
			if err != nil {
				fmt.Println("Decode error:",err)
				continue
			}
			err = this.ProcessEvent(&event)
			if err != nil {
				fmt.Println("Decode error:",err)
			}
		}
	})
}

func (this *FT5406) ProcessEvent(event *FT5406Event) error {
	timestamp := time.Duration(time.Duration(event.Second) * time.Second + time.Duration(event.Microsecond) * time.Microsecond)
	switch {
	case event.Type == EV_SYN:
		fmt.Println("SYNC:",timestamp)
		return nil
	case event.Type == EV_KEY && event.Code == BTN_TOUCH && event.Value == BTN_TOUCH_PRESS:
		fmt.Println("BTN_TOUCH_PRESS")
		return nil
	case event.Type == EV_KEY && event.Code == BTN_TOUCH && event.Value == BTN_TOUCH_RELEASE:
		fmt.Println("BTN_TOUCH_RELEASE")
		return nil
	case event.Type == EV_ABS && event.Code == ABS_MT_SLOT:
		fmt.Println("SLOT:",event.Value)
		return nil
	case event.Type == EV_ABS && event.Code == ABS_MT_POSITION_X:
		fmt.Println("X:",event.Value)
		return nil
	case event.Type == EV_ABS && event.Code == ABS_MT_POSITION_Y:
		fmt.Println("Y:",event.Value)
		return nil
	case event.Type == EV_ABS && event.Code == ABS_MT_TRACKING_ID:
		fmt.Println("ID:",event.Value)
		return nil
	case event.Type == EV_ABS && event.Code == ABS_X:
		fmt.Println("ABS X:",event.Value)
		return nil
	case event.Type == EV_ABS && event.Code == ABS_Y:
		fmt.Println("ABS X:",event.Value)
		return nil
	default:
		return errors.New(fmt.Sprintf("Invalid event: %v",event))
	}
}

////////////////////////////////////////////////////////////////////////////////
// Private Methods

func getDeviceName() (string,error) {
	files, err := filepath.Glob(PATH_INPUT_DEVICES)
	if err != nil {
		return "",err
	}
	for _, file := range files {
		buf, err := ioutil.ReadFile(path.Join(file,"device","name"))
		if err != nil {
			continue
		}
		if REGEXP_DEVICENAME.Match(buf) {
			return path.Join("/","dev","input",path.Base(file)),nil
		}
	}
	return "",nil
}
<|endoftext|>


<commit_before>package goriak

import (
	"errors"
	riak "github.com/basho/riak-go-client"
)

type requestData struct {
	bucket     string
	bucketType string
	key        string
}

type MapSetCommand struct {
	bucket     string
	bucketType string
	key        string
	input      interface{}

	builder *riak.UpdateMapCommandBuilder

	includeFilter [][]string
	excludeFilter [][]string
}

/*
Set automatically converts your Go datatype to the equivalent type in Riak

	|  Go Type   | Riak Type |
	|------------|-----------|
	| struct     | map       |
	| string     | register  |
	| [n]byte    | register  |
	| []byte     | register  |
	| []slice    | set       |
	| []slice    | set       |
	| [][]byte   | set       |
	| map        | map       |
	| time.Time  | register  |
*/
func (cmd *Command) Set(val interface{}) *MapSetCommand {
	c := &MapSetCommand{
		input:      val,
		bucket:     cmd.bucket,
		bucketType: cmd.bucketType,
	}

	c.builder = riak.NewUpdateMapCommandBuilder().
		WithBucket(cmd.bucket).
		WithBucketType(cmd.bucketType)

	return c
}

func (c *MapSetCommand) Key(key string) *MapSetCommand {
	c.key = key
	c.builder.WithKey(key)
	return c
}

// Takes a *riakMapOperation (our type) applies any filtering rules set on the Command
// Returns a *riak.MapOperation (from riak-go-client)
func filterMapOperation(cmd *MapSetCommand, input *riakMapOperation, path []string, op *riak.MapOperation) *riak.MapOperation {

	if op == nil {
		op = &riak.MapOperation{}
	}

	// Not implemented:
	// RemoveRegister()
	// RemoveCounter()
	// RemoveFlag()
	// RemoveMap()
	// RemoveSet()

	// AddToSet
	for key, values := range input.addToSets {
		for _, value := range values {
			if cmd.filterAllowPath(append(path, key)...) {
				op.AddToSet(key, value)
			}
		}
	}

	// RemoveFromSet
	for key, values := range input.removeFromSets {
		for _, value := range values {
			if cmd.filterAllowPath(append(path, key)...) {
				op.RemoveFromSet(key, value)
			}
		}
	}

	// SetRegister
	for key, value := range input.registersToSet {
		if cmd.filterAllowPath(append(path, key)...) {
			op.SetRegister(key, value)
		}
	}

	// Map
	for key, value := range input.maps {
		// No filtering is performed here
		subOp := op.Map(key)
		filterMapOperation(cmd, value, append(path, key), subOp)
	}

	// IncrementCounter
	for key, value := range input.incrementCounters {
		if cmd.filterAllowPath(append(path, key)...) {
			op.IncrementCounter(key, value)
		}
	}

	// SetFlag
	for key, value := range input.flagsToSet {
		if cmd.filterAllowPath(append(path, key)...) {
			op.SetFlag(key, value)
		}
	}

	return op
}

func (c *MapSetCommand) WithPw(pw uint32) *MapSetCommand {
	c.builder.WithPw(pw)
	return c
}

func (c *MapSetCommand) WithDw(dw uint32) *MapSetCommand {
	c.builder.WithDw(dw)
	return c
}

func (c *MapSetCommand) WithW(w uint32) *MapSetCommand {
	c.builder.WithPw(w)
	return c
}

func (c *MapSetCommand) Run(session *Session) (*Result, error) {
	riakContext, op, err := encodeInterface(c.input, requestData{
		bucket:     c.bucket,
		bucketType: c.bucketType,
		key:        c.key,
	})
	if err != nil {
		return nil, err
	}

	// Set context
	if len(riakContext) > 0 {
		c.builder.WithContext(riakContext)
	}

	// Set the map operation
	op2 := filterMapOperation(c, op, []string{}, nil)

	c.builder.WithMapOperation(op2)

	cmd, err := c.builder.Build()
	if err != nil {
		return nil, err
	}

	err = session.riak.Execute(cmd)
	if err != nil {
		return nil, err
	}

	updateCmd := cmd.(*riak.UpdateMapCommand)

	if !updateCmd.Success() {
		return nil, errors.New("Not successful")
	}

	if c.key != "" {
		return &Result{
			Key: c.key,
		}, nil
	}

	return &Result{
		Key: updateCmd.Response.GeneratedKey,
	}, nil
}
<commit_msg>Updated Set() to be consistent with other query builder methods<commit_after>package goriak

import (
	"errors"
	riak "github.com/basho/riak-go-client"
)

type requestData struct {
	bucket     string
	bucketType string
	key        string
}

type MapSetCommand struct {
	bucket     string
	bucketType string
	key        string
	input      interface{}

	builder *riak.UpdateMapCommandBuilder

	includeFilter [][]string
	excludeFilter [][]string
}

/*
Set automatically converts your Go datatype to the equivalent type in Riak

	|  Go Type   | Riak Type |
	|------------|-----------|
	| struct     | map       |
	| string     | register  |
	| [n]byte    | register  |
	| []byte     | register  |
	| []slice    | set       |
	| []slice    | set       |
	| [][]byte   | set       |
	| map        | map       |
	| time.Time  | register  |
*/
func (c *Command) Set(val interface{}) *MapSetCommand {
	builder := riak.NewUpdateMapCommandBuilder().
		WithBucket(c.bucket).
		WithBucketType(c.bucketType)

	return &MapSetCommand{
		input:      val,
		bucket:     c.bucket,
		bucketType: c.bucketType,
		builder:    builder,
	}
}

func (c *MapSetCommand) Key(key string) *MapSetCommand {
	c.key = key
	c.builder.WithKey(key)
	return c
}

// Takes a *riakMapOperation (our type) applies any filtering rules set on the Command
// Returns a *riak.MapOperation (from riak-go-client)
func filterMapOperation(cmd *MapSetCommand, input *riakMapOperation, path []string, op *riak.MapOperation) *riak.MapOperation {

	if op == nil {
		op = &riak.MapOperation{}
	}

	// Not implemented:
	// RemoveRegister()
	// RemoveCounter()
	// RemoveFlag()
	// RemoveMap()
	// RemoveSet()

	// AddToSet
	for key, values := range input.addToSets {
		for _, value := range values {
			if cmd.filterAllowPath(append(path, key)...) {
				op.AddToSet(key, value)
			}
		}
	}

	// RemoveFromSet
	for key, values := range input.removeFromSets {
		for _, value := range values {
			if cmd.filterAllowPath(append(path, key)...) {
				op.RemoveFromSet(key, value)
			}
		}
	}

	// SetRegister
	for key, value := range input.registersToSet {
		if cmd.filterAllowPath(append(path, key)...) {
			op.SetRegister(key, value)
		}
	}

	// Map
	for key, value := range input.maps {
		// No filtering is performed here
		subOp := op.Map(key)
		filterMapOperation(cmd, value, append(path, key), subOp)
	}

	// IncrementCounter
	for key, value := range input.incrementCounters {
		if cmd.filterAllowPath(append(path, key)...) {
			op.IncrementCounter(key, value)
		}
	}

	// SetFlag
	for key, value := range input.flagsToSet {
		if cmd.filterAllowPath(append(path, key)...) {
			op.SetFlag(key, value)
		}
	}

	return op
}

func (c *MapSetCommand) WithPw(pw uint32) *MapSetCommand {
	c.builder.WithPw(pw)
	return c
}

func (c *MapSetCommand) WithDw(dw uint32) *MapSetCommand {
	c.builder.WithDw(dw)
	return c
}

func (c *MapSetCommand) WithW(w uint32) *MapSetCommand {
	c.builder.WithPw(w)
	return c
}

func (c *MapSetCommand) Run(session *Session) (*Result, error) {
	riakContext, op, err := encodeInterface(c.input, requestData{
		bucket:     c.bucket,
		bucketType: c.bucketType,
		key:        c.key,
	})
	if err != nil {
		return nil, err
	}

	// Set context
	if len(riakContext) > 0 {
		c.builder.WithContext(riakContext)
	}

	// Set the map operation
	op2 := filterMapOperation(c, op, []string{}, nil)

	c.builder.WithMapOperation(op2)

	cmd, err := c.builder.Build()
	if err != nil {
		return nil, err
	}

	err = session.riak.Execute(cmd)
	if err != nil {
		return nil, err
	}

	updateCmd := cmd.(*riak.UpdateMapCommand)

	if !updateCmd.Success() {
		return nil, errors.New("Not successful")
	}

	if c.key != "" {
		return &Result{
			Key: c.key,
		}, nil
	}

	return &Result{
		Key: updateCmd.Response.GeneratedKey,
	}, nil
}
<|endoftext|>


<commit_before>package elasticorm

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/pkg/errors"
)

type MappingConfig struct {
	Type     string `json:"type"`
	Analyzer string `json:"analyzer,omitempty"`
}

func MappingFromStruct(i interface{}) (map[string]map[string]MappingConfig, error) {
	mapping := make(map[string]map[string]MappingConfig)
	mapping[`properties`] = make(map[string]MappingConfig)
	var err error

	v := reflect.ValueOf(i).Elem()
	for n := 0; n < v.NumField(); n++ {
		name := v.Type().Field(n).Name
		if jn := v.Type().Field(n).Tag.Get(`json`); jn != `` {
			name = jn
		}

		mappingType := `text`
		var analyzer string
		if et := v.Type().Field(n).Tag.Get(`elasticorm`); et != `` {
			opts := strings.Split(et, `=`)
			switch opts[0] {
			case `type`:
				mappingType = opts[1]
			case `analyzer`:
				analyzer = opts[1]
			default:
				err = errors.Wrap(InvalidOptionErr, fmt.Sprintf("parsing option %s failed", et))
			}
		}

		mapping[`properties`][name] = MappingConfig{
			Type:     mappingType,
			Analyzer: analyzer,
		}
	}

	return mapping, err
}
<commit_msg>[TASK] refactoring of mapping generation<commit_after>package elasticorm

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/pkg/errors"
)

type MappingConfig struct {
	Type     string `json:"type"`
	Analyzer string `json:"analyzer,omitempty"`
}

func MappingFromStruct(i interface{}) (map[string]map[string]MappingConfig, error) {
	mapping := make(map[string]map[string]MappingConfig)
	mapping[`properties`] = make(map[string]MappingConfig)
	var err error

	v := reflect.ValueOf(i).Elem()
	for n := 0; n < v.NumField(); n++ {
		fieldMapping, propErr := mappingForField(v.Type().Field(n).Tag.Get(`elasticorm`))
		if propErr != nil {
			err = propErr
		}
		name := nameForField(v.Type().Field(n))
		mapping[`properties`][name] = fieldMapping
	}

	return mapping, err
}

func mappingForField(tag string) (MappingConfig, error) {
	var err error
	propMapping := MappingConfig{
		Type: `text`,
	}

	if tag != `` {
		opts := strings.Split(tag, `=`)
		switch opts[0] {
		case `type`:
			propMapping.Type = opts[1]
		case `analyzer`:
			propMapping.Analyzer = opts[1]
		default:
			err = errors.Wrap(InvalidOptionErr, fmt.Sprintf("parsing option %s failed", tag))
		}
	}
	return propMapping, err
}

func nameForField(field reflect.StructField) string {
	name := field.Name
	if json := field.Tag.Get(`json`); json != `` {
		name = json
	}
	return name
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"strconv"
	"strings"

	"github.com/ajm188/advent_of_code/pkg/cli"
)

func pivot(lines []string) []string {
	bufs := make([]strings.Builder, len(lines))
	for _, line := range lines {
		for j, c := range line {
			bufs[j].WriteRune(c)
		}
	}

	result := make([]string, 0, len(bufs))
	for _, buf := range bufs {
		if s := buf.String(); s != "" {
			result = append(result, s)
		}
	}

	return result
}

func main() {
	path := flag.String("path", "input.txt", "")
	flag.Parse()

	data, err := cli.GetInput(*path)
	cli.ExitOnError(err)

	lines := strings.Split(string(data), "\n")
	if lines[len(lines)-1] == "" {
		lines = lines[:len(lines)-1]
	}

	columns := pivot(lines)
	var (
		mcbs string
		lcbs string
	)

	for _, column := range columns {
		if strings.Count(column, "0") >= len(column)/2 {
			mcbs += "0"
			lcbs += "1"
		} else {
			mcbs += "1"
			lcbs += "0"
		}
	}

	gamma, err := strconv.ParseInt(mcbs, 2, 64)
	cli.ExitOnError(err)
	epsilon, err := strconv.ParseInt(lcbs, 2, 64)
	cli.ExitOnError(err)

	fmt.Printf("gamma=%d\tepsilon=%d\tproduct=%d\n", gamma, epsilon, gamma*epsilon)
}
<commit_msg>refactor part1, super hacky part2<commit_after>package main

import (
	"flag"
	"fmt"
	"strconv"
	"strings"

	"github.com/ajm188/advent_of_code/pkg/cli"
)

func pivot(lines []string) []string {
	bufs := make([]strings.Builder, len(lines))
	for _, line := range lines {
		for j, c := range line {
			bufs[j].WriteRune(c)
		}
	}

	result := make([]string, 0, len(bufs))
	for _, buf := range bufs {
		if s := buf.String(); s != "" {
			result = append(result, s)
		}
	}

	return result
}

func partitionBinary(s string, include map[int]struct{}) (zeroes []int, ones []int) {
	keep := func(i int) bool {
		if include == nil {
			return true
		}

		_, ok := include[i]
		return ok
	}

	for i, c := range s {
		if keep(i) {
			switch c {
			case '0':
				zeroes = append(zeroes, i)
			case '1':
				ones = append(ones, i)
			default:
				cli.ExitOnError(fmt.Errorf("invalid binary digit %c (col:%d)", c, i))
			}
		}
	}

	return zeroes, ones
}

func main() {
	path := flag.String("path", "input.txt", "")
	flag.Parse()

	data, err := cli.GetInput(*path)
	cli.ExitOnError(err)

	lines := strings.Split(string(data), "\n")
	if lines[len(lines)-1] == "" {
		lines = lines[:len(lines)-1]
	}

	columns := pivot(lines)
	var (
		mcbs string
		lcbs string
	)

	for _, column := range columns {
		if zeroes, ones := partitionBinary(column, nil); len(zeroes) > len(ones) {
			mcbs += "0"
			lcbs += "1"
		} else {
			mcbs += "1"
			lcbs += "0"
		}
	}

	gamma, err := strconv.ParseInt(mcbs, 2, 64)
	cli.ExitOnError(err)
	epsilon, err := strconv.ParseInt(lcbs, 2, 64)
	cli.ExitOnError(err)

	fmt.Printf("gamma=%d\tepsilon=%d\tproduct=%d\n", gamma, epsilon, gamma*epsilon)

	var (
		o2bits  string
		o2rows  = map[int]struct{}{}
		co2bits string
		co2rows = map[int]struct{}{}
	)

	for i := range lines {
		o2rows[i] = struct{}{}
		co2rows[i] = struct{}{}
	}

	for _, column := range columns {
		if len(o2rows) > 1 {
			if zeroes, ones := partitionBinary(column, o2rows); len(ones) >= len(zeroes) {
				o2bits += "1"
				for _, skip := range zeroes {
					delete(o2rows, skip)
				}
			} else {
				o2bits += "0"
				for _, skip := range ones {
					delete(o2rows, skip)
				}
			}
		}

		if len(co2rows) > 1 {
			if zeroes, ones := partitionBinary(column, co2rows); len(zeroes) <= len(ones) {
				co2bits += "0"
				for _, skip := range ones {
					delete(co2rows, skip)
				}
			} else {
				co2bits += "1"
				for _, skip := range zeroes {
					delete(co2rows, skip)
				}
			}
		}
	}

	for row := range o2rows {
		o2bits = lines[row]
		break
	}

	for row := range co2rows {
		co2bits = lines[row]
		break
	}

	o2, err := strconv.ParseInt(o2bits, 2, 64)
	cli.ExitOnError(err)

	co2, err := strconv.ParseInt(co2bits, 2, 64)
	cli.ExitOnError(err)

	fmt.Printf("o2=%d\tco2=%d\tproduct=%d\n", o2, co2, o2*co2)
}
<|endoftext|>


<commit_before>package main

func main() {
}
<commit_msg>Add 3-mvp-http code<commit_after>package main

import (
	"bufio"
	"log"
	"net"
)

func main() {
	l, err := net.Listen("tcp", ":7000")
	if err != nil {
		log.Fatalln("unable to listen:", err)
	}
	defer l.Close()

	log.Print("listening")

	for {
		conn, err := l.Accept()
		if err != nil {
			log.Println("unable to accept")
			break
		}

		serve(conn)
	}
}

func serve(c net.Conn) {
	defer c.Close()

	r := bufio.NewReader(c)

	// Read request line
	ln0, err := r.ReadString('\n')
	if err != nil {
		return
	}
	log.Printf("read request line: %q", ln0)

	// Read headers
	for {
		ln, err := r.ReadString('\n')
		if err != nil {
			break
		}

		// An empty line with crlf marks the end of the headers
		if ln == "\r\n" {
			break
		}

		// Must be a header if we have reached this point
		log.Printf("read request header: %q", ln)
	}

	// Ignore body

	// Write response
	c.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"))
}
<|endoftext|>


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

package dict

import "testing"

func TestFindAVP(t *testing.T) {
	if _, err := Default.FindAVP(0, 263); err != nil {
		t.Fatal(err)
	}
}

func TestScanAVP(t *testing.T) {
	if avp, err := Default.ScanAVP("Session-Id"); err != nil {
		t.Error(err)
	} else if avp.Code != 263 {
		t.Fatalf("Unexpected code %d for Session-Id AVP", avp.Code)
	}
}

func TestFindCmd(t *testing.T) {
	if cmd, err := Default.FindCMD(0, 257); err != nil {
		t.Error(err)
	} else if cmd.Short != "CE" {
		t.Fatalf("Unexpected command: %#v", cmd)
	}
}

func TestEnum(t *testing.T) {
	if item, err := Default.Enum(0, 274, 1); err != nil {
		t.Fatal(err)
	} else if item.Name != "AUTHENTICATE_ONLY" {
		t.Errorf(
			"Unexpected value %s, expected AUTHENTICATE_ONLY",
			item.Name,
		)
	}
}

func TestRule(t *testing.T) {
	if rule, err := Default.Rule(0, 284, "Proxy-Host"); err != nil {
		t.Fatal(err)
	} else if !rule.Required {
		t.Errorf("Unexpected rule %#v", rule)
	}
}

func BenchmarkFindAVPName(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Default.FindAVP(0, "Session-Id")
	}
}

func BenchmarkFindAVPCode(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Default.FindAVP(0, 263)
	}
}

func BenchmarkScanAVPName(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Default.ScanAVP("Session-Id")
	}
}

func BenchmarkScanAVPCode(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Default.ScanAVP(263)
	}
}
<commit_msg>Testing different appIds<commit_after>// Copyright 2013-2014 go-diameter authors.  All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package dict

import "testing"

func TestFindAVP(t *testing.T) {
	if _, err := Default.FindAVP(999, 263); err != nil {
		t.Fatal(err)
	}
}

func TestScanAVP(t *testing.T) {
	if avp, err := Default.ScanAVP("Session-Id"); err != nil {
		t.Error(err)
	} else if avp.Code != 263 {
		t.Fatalf("Unexpected code %d for Session-Id AVP", avp.Code)
	}
}

func TestFindCmd(t *testing.T) {
	if cmd, err := Default.FindCMD(999, 257); err != nil {
		t.Error(err)
	} else if cmd.Short != "CE" {
		t.Fatalf("Unexpected command: %#v", cmd)
	}
}

func TestEnum(t *testing.T) {
	if item, err := Default.Enum(0, 274, 1); err != nil {
		t.Fatal(err)
	} else if item.Name != "AUTHENTICATE_ONLY" {
		t.Errorf(
			"Unexpected value %s, expected AUTHENTICATE_ONLY",
			item.Name,
		)
	}
}

func TestRule(t *testing.T) {
	if rule, err := Default.Rule(0, 284, "Proxy-Host"); err != nil {
		t.Fatal(err)
	} else if !rule.Required {
		t.Errorf("Unexpected rule %#v", rule)
	}
}

func BenchmarkFindAVPName(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Default.FindAVP(0, "Session-Id")
	}
}

func BenchmarkFindAVPCode(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Default.FindAVP(0, 263)
	}
}

func BenchmarkScanAVPName(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Default.ScanAVP("Session-Id")
	}
}

func BenchmarkScanAVPCode(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Default.ScanAVP(263)
	}
}
<|endoftext|>


<commit_before>package config

type FirebaseConfig struct {
	ApiKey            string
	AuthDomain        string
	DatabaseURL       string
	ProjectID         string
	StorageBucket     string
	MessagingSenderID string
}

func (f *FirebaseConfig) copy() *FirebaseConfig {

	if f == nil {
		return nil
	}

	result := &FirebaseConfig{}
	(*result) = *f
	return result
}

func (f *FirebaseConfig) extend(other *FirebaseConfig) *FirebaseConfig {
	if f == nil {
		return nil
	}
	result := f.copy()

	if other == nil {
		return result
	}

	if other.ApiKey != "" {
		result.ApiKey = other.ApiKey
	}

	if other.AuthDomain != "" {
		result.AuthDomain = other.AuthDomain
	}

	if other.DatabaseURL != "" {
		result.DatabaseURL = other.DatabaseURL
	}

	if other.ProjectID != "" {
		result.ProjectID = other.ProjectID
	}

	if other.StorageBucket != "" {
		result.StorageBucket = other.StorageBucket
	}

	if other.MessagingSenderID != "" {
		result.MessagingSenderID = other.MessagingSenderID
	}

	return result
}
<commit_msg>Updated the json output of config.ClientConfig to be the format the client expects. Part of #655.<commit_after>package config

type FirebaseConfig struct {
	ApiKey            string `json:"apiKey"`
	AuthDomain        string `json:"autoDomain"`
	DatabaseURL       string `json:"databaseURL"`
	ProjectID         string `json:"projectId"`
	StorageBucket     string `json:"storageBucket"`
	MessagingSenderID string `json:"messagingSenderId"`
}

func (f *FirebaseConfig) copy() *FirebaseConfig {

	if f == nil {
		return nil
	}

	result := &FirebaseConfig{}
	(*result) = *f
	return result
}

func (f *FirebaseConfig) extend(other *FirebaseConfig) *FirebaseConfig {
	if f == nil {
		return nil
	}
	result := f.copy()

	if other == nil {
		return result
	}

	if other.ApiKey != "" {
		result.ApiKey = other.ApiKey
	}

	if other.AuthDomain != "" {
		result.AuthDomain = other.AuthDomain
	}

	if other.DatabaseURL != "" {
		result.DatabaseURL = other.DatabaseURL
	}

	if other.ProjectID != "" {
		result.ProjectID = other.ProjectID
	}

	if other.StorageBucket != "" {
		result.StorageBucket = other.StorageBucket
	}

	if other.MessagingSenderID != "" {
		result.MessagingSenderID = other.MessagingSenderID
	}

	return result
}
<|endoftext|>


<commit_before>package main

import (
	"k8s.io/kubernetes/staging/src/k8s.io/client-go/_vendor/github.com/emicklei/go-restful/log"
	"io/ioutil"
	"strings"
)

func GetIgnitionJournal() []string {
	content, e := ioutil.ReadFile(CONF.IgnitionFile)
	var lines []string
	if e != nil {
		log.Print(e)
		return lines
	}
	lines = strings.Split(string(content), "\n")
	return lines
}
<commit_msg>Fix bad deps<commit_after>package main

import (
	"log"
	"io/ioutil"
	"strings"
)

func GetIgnitionJournal() []string {
	content, e := ioutil.ReadFile(CONF.IgnitionFile)
	var lines []string
	if e != nil {
		log.Print(e)
		return lines
	}
	lines = strings.Split(string(content), "\n")
	return lines
}
<|endoftext|>


<commit_before><commit_msg>pilad: set custom port on main test<commit_after><|endoftext|>


<commit_before><commit_msg>skip missing referrer values. closes #26<commit_after><|endoftext|>


<commit_before><commit_msg>Add logs around NEG CR GC<commit_after><|endoftext|>


<commit_before>package api

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/grafana/metrictank/api/middleware"
	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/api/response"
	"github.com/grafana/metrictank/cluster"
	"github.com/grafana/metrictank/stats"
	"github.com/raintank/worldping-api/pkg/log"
	"github.com/tinylib/msgp/msgp"
)

var NotFoundErr = errors.New("not found")

var (

	// metric api.cluster.speculative.attempts is how many peer queries resulted in speculation
	speculativeAttempts = stats.NewCounter32("api.cluster.speculative.attempts")

	// metric api.cluster.speculative.wins is how many peer queries were improved due to speculation
	speculativeWins = stats.NewCounter32("api.cluster.speculative.wins")

	// metric api.cluster.speculative.requests is how many speculative http requests made to peers
	speculativeRequests = stats.NewCounter32("api.cluster.speculative.requests")
)

func (s *Server) explainPriority(ctx *middleware.Context) {
	var data []interface{}
	for _, p := range s.prioritySetters {
		data = append(data, p.ExplainPriority())
	}
	response.Write(ctx, response.NewJson(200, data, ""))
}

func (s *Server) getNodeStatus(ctx *middleware.Context) {
	response.Write(ctx, response.NewJson(200, cluster.Manager.ThisNode(), ""))
}

func (s *Server) setNodeStatus(ctx *middleware.Context, status models.NodeStatus) {
	primary, err := strconv.ParseBool(status.Primary)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, fmt.Sprintf(
			"could not parse status to bool. %s",
			err.Error())),
		)
		return
	}
	cluster.Manager.SetPrimary(primary)
	ctx.PlainText(200, []byte("OK"))
}

func (s *Server) appStatus(ctx *middleware.Context) {
	if cluster.Manager.IsReady() {
		ctx.PlainText(200, []byte("OK"))
		return
	}

	response.Write(ctx, response.NewError(http.StatusServiceUnavailable, "node not ready"))
}

func (s *Server) getClusterStatus(ctx *middleware.Context) {
	status := models.ClusterStatus{
		ClusterName: cluster.ClusterName,
		NodeName:    cluster.Manager.ThisNode().GetName(),
		Members:     cluster.Manager.MemberList(),
	}
	response.Write(ctx, response.NewJson(200, status, ""))
}

func (s *Server) postClusterMembers(ctx *middleware.Context, req models.ClusterMembers) {
	memberNames := make(map[string]struct{})
	var toJoin []string

	for _, memberNode := range cluster.Manager.MemberList() {
		memberNames[memberNode.GetName()] = struct{}{}
	}

	for _, peerName := range req.Members {
		if _, ok := memberNames[peerName]; !ok {
			toJoin = append(toJoin, peerName)
		}
	}

	resp := models.ClusterMembersResp{
		Status:       "ok",
		MembersAdded: 0,
	}

	if len(toJoin) == 0 {
		response.Write(ctx, response.NewJson(200, resp, ""))
		return
	}

	n, err := cluster.Manager.Join(toJoin)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, fmt.Sprintf(
			"error when joining cluster members: %s", err.Error())),
		)
		return
	}
	resp.MembersAdded = n
	response.Write(ctx, response.NewJson(200, resp, ""))
}

// IndexFind returns a sequence of msgp encoded idx.Node's
func (s *Server) indexFind(ctx *middleware.Context, req models.IndexFind) {
	resp := models.NewIndexFindResp()

	for _, pattern := range req.Patterns {
		nodes, err := s.MetricIndex.Find(req.OrgId, pattern, req.From)
		if err != nil {
			response.Write(ctx, response.WrapError(err))
			return
		}
		resp.Nodes[pattern] = nodes
	}
	response.Write(ctx, response.NewMsgp(200, resp))
}

func (s *Server) indexTagDetails(ctx *middleware.Context, req models.IndexTagDetails) {
	values, err := s.MetricIndex.TagDetails(req.OrgId, req.Tag, req.Filter, req.From)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, &models.IndexTagDetailsResp{Values: values}))
}

func (s *Server) indexTags(ctx *middleware.Context, req models.IndexTags) {
	tags, err := s.MetricIndex.Tags(req.OrgId, req.Filter, req.From)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, &models.IndexTagsResp{Tags: tags}))
}

func (s *Server) indexAutoCompleteTags(ctx *middleware.Context, req models.IndexAutoCompleteTags) {
	tags, err := s.MetricIndex.FindTags(req.OrgId, req.Prefix, req.Expr, req.From, req.Limit)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, models.StringList(tags)))
}

func (s *Server) indexAutoCompleteTagValues(ctx *middleware.Context, req models.IndexAutoCompleteTagValues) {
	tags, err := s.MetricIndex.FindTagValues(req.OrgId, req.Tag, req.Prefix, req.Expr, req.From, req.Limit)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, models.StringList(tags)))
}

func (s *Server) indexTagDelSeries(ctx *middleware.Context, request models.IndexTagDelSeries) {
	deleted, err := s.MetricIndex.DeleteTagged(request.OrgId, request.Paths)
	if err != nil {
		response.Write(ctx, response.WrapErrorForTagDB(err))
		return
	}

	res := models.IndexTagDelSeriesResp{}
	res.Count = len(deleted)

	response.Write(ctx, response.NewMsgp(200, res))
}

func (s *Server) indexFindByTag(ctx *middleware.Context, req models.IndexFindByTag) {
	metrics, err := s.MetricIndex.FindByTag(req.OrgId, req.Expr, req.From)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, &models.IndexFindByTagResp{Metrics: metrics}))
}

// IndexGet returns a msgp encoded schema.MetricDefinition
func (s *Server) indexGet(ctx *middleware.Context, req models.IndexGet) {
	def, ok := s.MetricIndex.Get(req.MKey)
	if !ok {
		response.Write(ctx, response.NewError(http.StatusNotFound, "Not Found"))
		return
	}

	response.Write(ctx, response.NewMsgp(200, &def))
}

// IndexList returns msgp encoded schema.MetricDefinition's
func (s *Server) indexList(ctx *middleware.Context, req models.IndexList) {
	defs := s.MetricIndex.List(req.OrgId)
	resp := make([]msgp.Marshaler, len(defs))
	for i := range defs {
		d := defs[i]
		resp[i] = &d
	}
	response.Write(ctx, response.NewMsgpArray(200, resp))
}

func (s *Server) getData(ctx *middleware.Context, request models.GetData) {
	series, err := s.getTargetsLocal(ctx.Req.Context(), request.Requests)
	if err != nil {
		// the only errors returned are from us catching panics, so we should treat them
		// all as internalServerErrors
		log.Error(3, "HTTP getData() %s", err.Error())
		response.Write(ctx, response.WrapError(err))
		return
	}
	response.Write(ctx, response.NewMsgp(200, &models.GetDataResp{Series: series}))
}

func (s *Server) indexDelete(ctx *middleware.Context, req models.IndexDelete) {
	defs, err := s.MetricIndex.Delete(req.OrgId, req.Query)
	if err != nil {
		// errors can only be caused by bad request.
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}

	resp := models.MetricsDeleteResp{
		DeletedDefs: len(defs),
	}
	response.Write(ctx, response.NewMsgp(200, &resp))
}

type PeerResponse struct {
	peer cluster.Node
	buf  []byte
}

// peerQuery takes a request and the path to request it on, then fans it out
// across the cluster, except to the local peer. If any peer fails requests to
// other peers are aborted.
// ctx:          request context
// data:         request to be submitted
// name:         name to be used in logging & tracing
// path:         path to request on
func (s *Server) peerQuery(ctx context.Context, data cluster.Traceable, name, path string, allPeers bool) (map[string]PeerResponse, error) {
	var peers []cluster.Node
	var err error

	if allPeers {
		peers = cluster.Manager.MemberList()
	} else {
		peers, err = cluster.MembersForQuery()
		if err != nil {
			log.Error(3, "HTTP peerQuery unable to get peers, %s", err)
			return nil, err
		}
	}
	log.Debug("HTTP %s across %d instances", name, len(peers)-1)

	reqCtx, cancel := context.WithCancel(ctx)
	defer cancel()

	responses := make(chan struct {
		data PeerResponse
		err  error
	}, 1)
	var wg sync.WaitGroup
	for _, peer := range peers {
		if peer.IsLocal() {
			continue
		}
		wg.Add(1)
		go func(peer cluster.Node) {
			defer wg.Done()
			log.Debug("HTTP Render querying %s%s", peer.GetName(), path)
			buf, err := peer.Post(reqCtx, name, path, data)
			if err != nil {
				cancel()
				log.Error(4, "HTTP Render error querying %s%s: %q", peer.GetName(), path, err)
			}
			responses <- struct {
				data PeerResponse
				err  error
			}{PeerResponse{peer, buf}, err}
		}(peer)
	}
	// wait for all list goroutines to end, then close our responses channel
	go func() {
		wg.Wait()
		close(responses)
	}()

	result := make(map[string]PeerResponse)
	for resp := range responses {
		if resp.err != nil {
			return nil, err
		}
		result[resp.data.peer.GetName()] = resp.data
	}

	return result, nil
}

// peerQuerySpeculative takes a request and the path to request it on, then fans it out
// across the cluster, except to the local peer. If any peer fails requests to
// other peers are aborted. If enough peers have been heard from (based on
// speculation-threshold configuration), and we are missing the others, try to
// speculatively query each other member of each shard group.
// ctx:          request context
// data:         request to be submitted
// name:         name to be used in logging & tracing
// path:         path to request on
func (s *Server) peerQuerySpeculative(ctx context.Context, data cluster.Traceable, name, path string) (map[string]PeerResponse, error) {
	peerGroups, err := cluster.MembersForSpeculativeQuery()
	if err != nil {
		log.Error(3, "HTTP peerQuery unable to get peers, %s", err)
		return nil, err
	}
	log.Debug("HTTP %s across %d instances", name, len(peerGroups)-1)

	reqCtx, cancel := context.WithCancel(ctx)
	defer cancel()

	originalPeers := make(map[string]struct{}, len(peerGroups))
	pendingResponses := make(map[int32]struct{}, len(peerGroups))
	receivedResponses := make(map[int32]struct{}, len(peerGroups))

	responses := make(chan struct {
		shardGroup int32
		data       PeerResponse
		err        error
	}, 1)

	askPeer := func(shardGroup int32, peer cluster.Node) {
		log.Debug("HTTP Render querying %s%s", peer.GetName(), path)
		buf, err := peer.Post(reqCtx, name, path, data)

		select {
		case <-ctx.Done():
			return
		default:
			// Not canceled, continue
		}

		if err != nil {
			cancel()
			log.Error(4, "HTTP Render error querying %s%s: %q", peer.GetName(), path, err)
		}
		responses <- struct {
			shardGroup int32
			data       PeerResponse
			err        error
		}{shardGroup, PeerResponse{peer, buf}, err}
	}

	for group, peers := range peerGroups {
		peer := peers[0]
		originalPeers[peer.GetName()] = struct{}{}
		pendingResponses[group] = struct{}{}
		go askPeer(group, peer)
	}

	result := make(map[string]PeerResponse)

	var ticker *time.Ticker
	var tickChan <-chan time.Time
	if speculationThreshold != 1 {
		ticker = time.NewTicker(5 * time.Millisecond)
		tickChan = ticker.C
		defer ticker.Stop()
	}

	for len(pendingResponses) > 0 {
		select {
		case resp := <-responses:
			if _, ok := receivedResponses[resp.shardGroup]; ok {
				// already received this response (possibly speculatively)
				continue
			}

			if resp.err != nil {
				return nil, err
			}

			result[resp.data.peer.GetName()] = resp.data
			receivedResponses[resp.shardGroup] = struct{}{}
			delete(pendingResponses, resp.shardGroup)
			delete(originalPeers, resp.data.peer.GetName())

		case <-tickChan:
			// Check if it's time to speculate!
			percentReceived := 1 - (float64(len(pendingResponses)) / float64(len(peerGroups)))
			if percentReceived >= speculationThreshold {
				// kick off speculative queries to other members now
				ticker.Stop()
				speculativeAttempts.Inc()
				for shardGroup := range pendingResponses {
					eligiblePeers := peerGroups[shardGroup][1:]
					for _, peer := range eligiblePeers {
						speculativeRequests.Inc()
						go askPeer(shardGroup, peer)
					}
				}
			}
		}
	}

	if len(originalPeers) > 0 {
		speculativeWins.Inc()
	}

	return result, nil
}
<commit_msg>simpler way to compute percentReceived<commit_after>package api

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/grafana/metrictank/api/middleware"
	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/api/response"
	"github.com/grafana/metrictank/cluster"
	"github.com/grafana/metrictank/stats"
	"github.com/raintank/worldping-api/pkg/log"
	"github.com/tinylib/msgp/msgp"
)

var NotFoundErr = errors.New("not found")

var (

	// metric api.cluster.speculative.attempts is how many peer queries resulted in speculation
	speculativeAttempts = stats.NewCounter32("api.cluster.speculative.attempts")

	// metric api.cluster.speculative.wins is how many peer queries were improved due to speculation
	speculativeWins = stats.NewCounter32("api.cluster.speculative.wins")

	// metric api.cluster.speculative.requests is how many speculative http requests made to peers
	speculativeRequests = stats.NewCounter32("api.cluster.speculative.requests")
)

func (s *Server) explainPriority(ctx *middleware.Context) {
	var data []interface{}
	for _, p := range s.prioritySetters {
		data = append(data, p.ExplainPriority())
	}
	response.Write(ctx, response.NewJson(200, data, ""))
}

func (s *Server) getNodeStatus(ctx *middleware.Context) {
	response.Write(ctx, response.NewJson(200, cluster.Manager.ThisNode(), ""))
}

func (s *Server) setNodeStatus(ctx *middleware.Context, status models.NodeStatus) {
	primary, err := strconv.ParseBool(status.Primary)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, fmt.Sprintf(
			"could not parse status to bool. %s",
			err.Error())),
		)
		return
	}
	cluster.Manager.SetPrimary(primary)
	ctx.PlainText(200, []byte("OK"))
}

func (s *Server) appStatus(ctx *middleware.Context) {
	if cluster.Manager.IsReady() {
		ctx.PlainText(200, []byte("OK"))
		return
	}

	response.Write(ctx, response.NewError(http.StatusServiceUnavailable, "node not ready"))
}

func (s *Server) getClusterStatus(ctx *middleware.Context) {
	status := models.ClusterStatus{
		ClusterName: cluster.ClusterName,
		NodeName:    cluster.Manager.ThisNode().GetName(),
		Members:     cluster.Manager.MemberList(),
	}
	response.Write(ctx, response.NewJson(200, status, ""))
}

func (s *Server) postClusterMembers(ctx *middleware.Context, req models.ClusterMembers) {
	memberNames := make(map[string]struct{})
	var toJoin []string

	for _, memberNode := range cluster.Manager.MemberList() {
		memberNames[memberNode.GetName()] = struct{}{}
	}

	for _, peerName := range req.Members {
		if _, ok := memberNames[peerName]; !ok {
			toJoin = append(toJoin, peerName)
		}
	}

	resp := models.ClusterMembersResp{
		Status:       "ok",
		MembersAdded: 0,
	}

	if len(toJoin) == 0 {
		response.Write(ctx, response.NewJson(200, resp, ""))
		return
	}

	n, err := cluster.Manager.Join(toJoin)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, fmt.Sprintf(
			"error when joining cluster members: %s", err.Error())),
		)
		return
	}
	resp.MembersAdded = n
	response.Write(ctx, response.NewJson(200, resp, ""))
}

// IndexFind returns a sequence of msgp encoded idx.Node's
func (s *Server) indexFind(ctx *middleware.Context, req models.IndexFind) {
	resp := models.NewIndexFindResp()

	for _, pattern := range req.Patterns {
		nodes, err := s.MetricIndex.Find(req.OrgId, pattern, req.From)
		if err != nil {
			response.Write(ctx, response.WrapError(err))
			return
		}
		resp.Nodes[pattern] = nodes
	}
	response.Write(ctx, response.NewMsgp(200, resp))
}

func (s *Server) indexTagDetails(ctx *middleware.Context, req models.IndexTagDetails) {
	values, err := s.MetricIndex.TagDetails(req.OrgId, req.Tag, req.Filter, req.From)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, &models.IndexTagDetailsResp{Values: values}))
}

func (s *Server) indexTags(ctx *middleware.Context, req models.IndexTags) {
	tags, err := s.MetricIndex.Tags(req.OrgId, req.Filter, req.From)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, &models.IndexTagsResp{Tags: tags}))
}

func (s *Server) indexAutoCompleteTags(ctx *middleware.Context, req models.IndexAutoCompleteTags) {
	tags, err := s.MetricIndex.FindTags(req.OrgId, req.Prefix, req.Expr, req.From, req.Limit)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, models.StringList(tags)))
}

func (s *Server) indexAutoCompleteTagValues(ctx *middleware.Context, req models.IndexAutoCompleteTagValues) {
	tags, err := s.MetricIndex.FindTagValues(req.OrgId, req.Tag, req.Prefix, req.Expr, req.From, req.Limit)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, models.StringList(tags)))
}

func (s *Server) indexTagDelSeries(ctx *middleware.Context, request models.IndexTagDelSeries) {
	deleted, err := s.MetricIndex.DeleteTagged(request.OrgId, request.Paths)
	if err != nil {
		response.Write(ctx, response.WrapErrorForTagDB(err))
		return
	}

	res := models.IndexTagDelSeriesResp{}
	res.Count = len(deleted)

	response.Write(ctx, response.NewMsgp(200, res))
}

func (s *Server) indexFindByTag(ctx *middleware.Context, req models.IndexFindByTag) {
	metrics, err := s.MetricIndex.FindByTag(req.OrgId, req.Expr, req.From)
	if err != nil {
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}
	response.Write(ctx, response.NewMsgp(200, &models.IndexFindByTagResp{Metrics: metrics}))
}

// IndexGet returns a msgp encoded schema.MetricDefinition
func (s *Server) indexGet(ctx *middleware.Context, req models.IndexGet) {
	def, ok := s.MetricIndex.Get(req.MKey)
	if !ok {
		response.Write(ctx, response.NewError(http.StatusNotFound, "Not Found"))
		return
	}

	response.Write(ctx, response.NewMsgp(200, &def))
}

// IndexList returns msgp encoded schema.MetricDefinition's
func (s *Server) indexList(ctx *middleware.Context, req models.IndexList) {
	defs := s.MetricIndex.List(req.OrgId)
	resp := make([]msgp.Marshaler, len(defs))
	for i := range defs {
		d := defs[i]
		resp[i] = &d
	}
	response.Write(ctx, response.NewMsgpArray(200, resp))
}

func (s *Server) getData(ctx *middleware.Context, request models.GetData) {
	series, err := s.getTargetsLocal(ctx.Req.Context(), request.Requests)
	if err != nil {
		// the only errors returned are from us catching panics, so we should treat them
		// all as internalServerErrors
		log.Error(3, "HTTP getData() %s", err.Error())
		response.Write(ctx, response.WrapError(err))
		return
	}
	response.Write(ctx, response.NewMsgp(200, &models.GetDataResp{Series: series}))
}

func (s *Server) indexDelete(ctx *middleware.Context, req models.IndexDelete) {
	defs, err := s.MetricIndex.Delete(req.OrgId, req.Query)
	if err != nil {
		// errors can only be caused by bad request.
		response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error()))
		return
	}

	resp := models.MetricsDeleteResp{
		DeletedDefs: len(defs),
	}
	response.Write(ctx, response.NewMsgp(200, &resp))
}

type PeerResponse struct {
	peer cluster.Node
	buf  []byte
}

// peerQuery takes a request and the path to request it on, then fans it out
// across the cluster, except to the local peer. If any peer fails requests to
// other peers are aborted.
// ctx:          request context
// data:         request to be submitted
// name:         name to be used in logging & tracing
// path:         path to request on
func (s *Server) peerQuery(ctx context.Context, data cluster.Traceable, name, path string, allPeers bool) (map[string]PeerResponse, error) {
	var peers []cluster.Node
	var err error

	if allPeers {
		peers = cluster.Manager.MemberList()
	} else {
		peers, err = cluster.MembersForQuery()
		if err != nil {
			log.Error(3, "HTTP peerQuery unable to get peers, %s", err)
			return nil, err
		}
	}
	log.Debug("HTTP %s across %d instances", name, len(peers)-1)

	reqCtx, cancel := context.WithCancel(ctx)
	defer cancel()

	responses := make(chan struct {
		data PeerResponse
		err  error
	}, 1)
	var wg sync.WaitGroup
	for _, peer := range peers {
		if peer.IsLocal() {
			continue
		}
		wg.Add(1)
		go func(peer cluster.Node) {
			defer wg.Done()
			log.Debug("HTTP Render querying %s%s", peer.GetName(), path)
			buf, err := peer.Post(reqCtx, name, path, data)
			if err != nil {
				cancel()
				log.Error(4, "HTTP Render error querying %s%s: %q", peer.GetName(), path, err)
			}
			responses <- struct {
				data PeerResponse
				err  error
			}{PeerResponse{peer, buf}, err}
		}(peer)
	}
	// wait for all list goroutines to end, then close our responses channel
	go func() {
		wg.Wait()
		close(responses)
	}()

	result := make(map[string]PeerResponse)
	for resp := range responses {
		if resp.err != nil {
			return nil, err
		}
		result[resp.data.peer.GetName()] = resp.data
	}

	return result, nil
}

// peerQuerySpeculative takes a request and the path to request it on, then fans it out
// across the cluster, except to the local peer. If any peer fails requests to
// other peers are aborted. If enough peers have been heard from (based on
// speculation-threshold configuration), and we are missing the others, try to
// speculatively query each other member of each shard group.
// ctx:          request context
// data:         request to be submitted
// name:         name to be used in logging & tracing
// path:         path to request on
func (s *Server) peerQuerySpeculative(ctx context.Context, data cluster.Traceable, name, path string) (map[string]PeerResponse, error) {
	peerGroups, err := cluster.MembersForSpeculativeQuery()
	if err != nil {
		log.Error(3, "HTTP peerQuery unable to get peers, %s", err)
		return nil, err
	}
	log.Debug("HTTP %s across %d instances", name, len(peerGroups)-1)

	reqCtx, cancel := context.WithCancel(ctx)
	defer cancel()

	originalPeers := make(map[string]struct{}, len(peerGroups))
	pendingResponses := make(map[int32]struct{}, len(peerGroups))
	receivedResponses := make(map[int32]struct{}, len(peerGroups))

	responses := make(chan struct {
		shardGroup int32
		data       PeerResponse
		err        error
	}, 1)

	askPeer := func(shardGroup int32, peer cluster.Node) {
		log.Debug("HTTP Render querying %s%s", peer.GetName(), path)
		buf, err := peer.Post(reqCtx, name, path, data)

		select {
		case <-ctx.Done():
			return
		default:
			// Not canceled, continue
		}

		if err != nil {
			cancel()
			log.Error(4, "HTTP Render error querying %s%s: %q", peer.GetName(), path, err)
		}
		responses <- struct {
			shardGroup int32
			data       PeerResponse
			err        error
		}{shardGroup, PeerResponse{peer, buf}, err}
	}

	for group, peers := range peerGroups {
		peer := peers[0]
		originalPeers[peer.GetName()] = struct{}{}
		pendingResponses[group] = struct{}{}
		go askPeer(group, peer)
	}

	result := make(map[string]PeerResponse)

	var ticker *time.Ticker
	var tickChan <-chan time.Time
	if speculationThreshold != 1 {
		ticker = time.NewTicker(5 * time.Millisecond)
		tickChan = ticker.C
		defer ticker.Stop()
	}

	for len(pendingResponses) > 0 {
		select {
		case resp := <-responses:
			if _, ok := receivedResponses[resp.shardGroup]; ok {
				// already received this response (possibly speculatively)
				continue
			}

			if resp.err != nil {
				return nil, err
			}

			result[resp.data.peer.GetName()] = resp.data
			receivedResponses[resp.shardGroup] = struct{}{}
			delete(pendingResponses, resp.shardGroup)
			delete(originalPeers, resp.data.peer.GetName())

		case <-tickChan:
			// Check if it's time to speculate!
			percentReceived := float64(len(receivedResponses)) / float64(len(peerGroups))
			if percentReceived >= speculationThreshold {
				// kick off speculative queries to other members now
				ticker.Stop()
				speculativeAttempts.Inc()
				for shardGroup := range pendingResponses {
					eligiblePeers := peerGroups[shardGroup][1:]
					for _, peer := range eligiblePeers {
						speculativeRequests.Inc()
						go askPeer(shardGroup, peer)
					}
				}
			}
		}
	}

	if len(originalPeers) > 0 {
		speculativeWins.Inc()
	}

	return result, nil
}
<|endoftext|>


<commit_before>package services

import (
	"os"
	"io/ioutil"
	"encoding/json"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/vito/cmdtest/matchers"

	. "github.com/pivotal-cf-experimental/cf-test-helpers/generator"
	. "github.com/pivotal-cf-experimental/cf-test-helpers/cf"
	. "github.com/pivotal-cf-experimental/cf-acceptance-tests/helpers"
)

type ServicesResponse struct {
	Resources []ServiceResponse
}

type ServiceResponse struct {
	Entity struct {
		Label string
		ServicePlans []ServicePlanResponse `json:"service_plans"`
	}
}

type ServicePlanResponse struct {
	Entity struct {
		Name string
		Public bool
	}
	Metadata struct {
		Url string
	}
}

var _ = PDescribe("Service Broker Lifecycle", func() {
	var appName string

	BeforeEach(func() {
		appName = RandomName()
		Cf("login", "-u", os.Getenv("ADMIN_USER"), "-p", os.Getenv("ADMIN_PASSWORD"))
		Cf("target", "-o", os.Getenv("CF_ORG"), "-s", os.Getenv("CF_SPACE"))
		Expect(Cf("push", appName, "-p", serviceBrokerPath)).To(Say("App started"))
		configJSON, _ := ioutil.ReadFile(ServiceBrokerConfigPath)
		Expect(Cf("set-env", appName, "CONFIG", string(configJSON))).To(ExitWithTimeout(0, 2*time.Second))
		Expect(Cf("restart", appName)).To(Say("App started"))
	})

	AfterEach(func() {
		Expect(Cf("delete-service-broker", appName, "-f")).To(ExitWithTimeout(0, 2*time.Second))
		Expect(Cf("delete", appName, "-f")).To(ExitWithTimeout(0, 2*time.Second))
		Cf("login", "-u", os.Getenv("CF_USER"), "-p", os.Getenv("CF_USER_PASSWORD"))
		Cf("target", "-o", os.Getenv("CF_ORG"), "-s", os.Getenv("CF_SPACE"))
	})

	It("confirms correct behavior in the lifecycle of a service broker", func() {
		defer Recover() // Catches panic thrown by Require expectations

		// Adding the service broker
		Require(Cf("create-service-broker", appName, "username", "password", AppUri(appName, ""))).To(ExitWithTimeout(0, 2*time.Second))
		Expect(Cf("service-brokers")).To(Say(appName))

		// Confirming the plans are not yet public
		session := Cf("marketplace")
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerServiceLabel))
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerPlanName))

		// Making the plans public
		session = Cf("curl", "/v2/services?inline-relations-depth=1")
		structure := ServicesResponse{}
		json.Unmarshal(session.FullOutput(), &structure)
		for _, service := range structure.Resources {
			if service.Entity.Label == ServiceBrokerConfig.FirstBrokerServiceLabel {
				for _, plan := range service.Entity.ServicePlans {
					if plan.Entity.Name == ServiceBrokerConfig.FirstBrokerPlanName {
						MakePlanPublic(plan.Metadata.Url)
						break
					}
				}
			}
		}

		// Confirming plans show up in the marketplace
		session = Cf("marketplace")
		Expect(session).To(Say(ServiceBrokerConfig.FirstBrokerServiceLabel))
		Expect(session).To(Say(ServiceBrokerConfig.FirstBrokerPlanName))

		// Changing the catalog on the broker
		Eventually(Curling(AppUri(appName,"/v2/catalog"), "-X", "POST", "-i")).Should(Say("HTTP/1.1 200 OK"))
		Require(Cf("update-service-broker", appName, "username", "password", AppUri(appName, ""))).To(ExitWithTimeout(0, 2*time.Second))

		// Confirming the changes to the broker show up in the marketplace
		session = Cf("marketplace")
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerServiceLabel))
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerPlanName))
		Expect(session).To(Say(ServiceBrokerConfig.SecondBrokerServiceLabel))
		Expect(session).To(Say(ServiceBrokerConfig.SecondBrokerPlanName))

		// Deleting the service broker and confirming the plans no longer display
		Require(Cf("delete-service-broker", appName, "-f")).To(ExitWithTimeout(0, 2*time.Second))
		session = Cf("marketplace")
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerServiceLabel))
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerPlanName))
		Expect(session).NotTo(Say(ServiceBrokerConfig.SecondBrokerServiceLabel))
		Expect(session).NotTo(Say(ServiceBrokerConfig.SecondBrokerPlanName))
	})
})
<commit_msg>Fixes authentication issues for services test<commit_after>package services

import (
	"os"
	"encoding/json"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/vito/cmdtest/matchers"

	. "github.com/pivotal-cf-experimental/cf-test-helpers/generator"
	. "github.com/pivotal-cf-experimental/cf-test-helpers/cf"
	. "github.com/pivotal-cf-experimental/cf-acceptance-tests/helpers"
)

type ServicesResponse struct {
	Resources []ServiceResponse
}

type ServiceResponse struct {
	Entity struct {
		Label string
		ServicePlans []ServicePlanResponse `json:"service_plans"`
	}
}

type ServicePlanResponse struct {
	Entity struct {
		Name string
		Public bool
	}
	Metadata struct {
		Url string
	}
}

var _ = Describe("Service Broker Lifecycle", func() {
	var appName string

	BeforeEach(func() {
		appName = RandomName()
		Cf("login", "-u", os.Getenv("ADMIN_USER"), "-p", os.Getenv("ADMIN_PASSWORD"), "-o", os.Getenv("CF_ORG"), "-s", os.Getenv("CF_SPACE"))
		Expect(Cf("push", appName, "-p", serviceBrokerPath)).To(Say("App started"))
		configJSON, _ := json.Marshal(ServiceBrokerConfig)
		Expect(Cf("set-env", appName, "CONFIG", string(configJSON))).To(ExitWithTimeout(0, 2*time.Second))
		Expect(Cf("restart", appName)).To(Say("App started"))
	})

	AfterEach(func() {
		Expect(Cf("delete-service-broker", appName, "-f")).To(ExitWithTimeout(0, 2*time.Second))
		Expect(Cf("delete", appName, "-f")).To(ExitWithTimeout(0, 2*time.Second))
		Cf("login", "-u", os.Getenv("CF_USER"), "-p", os.Getenv("CF_USER_PASSWORD"), "-o", os.Getenv("CF_ORG"), "-s", os.Getenv("CF_SPACE"))
	})

	It("confirms correct behavior in the lifecycle of a service broker", func() {
		defer Recover() // Catches panic thrown by Require expectations

		// Adding the service broker
		Require(Cf("create-service-broker", appName, "username", "password", AppUri(appName, ""))).To(ExitWithTimeout(0, 30*time.Second))
		Expect(Cf("service-brokers")).To(Say(appName))

		// Confirming the plans are not yet public
		session := Cf("marketplace")
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerServiceLabel))
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerPlanName))

		// Making the plans public
		session = Cf("curl", "/v2/services?inline-relations-depth=1")
		structure := ServicesResponse{}
		json.Unmarshal(session.FullOutput(), &structure)
		for _, service := range structure.Resources {
			if service.Entity.Label == ServiceBrokerConfig.FirstBrokerServiceLabel {
				for _, plan := range service.Entity.ServicePlans {
					if plan.Entity.Name == ServiceBrokerConfig.FirstBrokerPlanName {
						MakePlanPublic(plan.Metadata.Url)
						break
					}
				}
			}
		}

		// Confirming plans show up in the marketplace
		session = Cf("marketplace")
		Expect(session).To(Say(ServiceBrokerConfig.FirstBrokerServiceLabel))
		Expect(session).To(Say(ServiceBrokerConfig.FirstBrokerPlanName))

		// Changing the catalog on the broker
		Eventually(Curling(AppUri(appName,"/v2/catalog"), "-X", "POST", "-i")).Should(Say("HTTP/1.1 200 OK"))
		Require(Cf("update-service-broker", appName, "username", "password", AppUri(appName, ""))).To(ExitWithTimeout(0, 30*time.Second))

		// Confirming the changes to the broker show up in the marketplace
		session = Cf("marketplace")
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerServiceLabel))
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerPlanName))
		Expect(session).To(Say(ServiceBrokerConfig.SecondBrokerServiceLabel))
		Expect(session).To(Say(ServiceBrokerConfig.SecondBrokerPlanName))

		// Deleting the service broker and confirming the plans no longer display
		Require(Cf("delete-service-broker", appName, "-f")).To(ExitWithTimeout(0, 2*time.Second))
		session = Cf("marketplace")
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerServiceLabel))
		Expect(session).NotTo(Say(ServiceBrokerConfig.FirstBrokerPlanName))
		Expect(session).NotTo(Say(ServiceBrokerConfig.SecondBrokerServiceLabel))
		Expect(session).NotTo(Say(ServiceBrokerConfig.SecondBrokerPlanName))
	})
})
<|endoftext|>


<commit_before>package genericsite

import (
	"strings"

	. "github.com/xyproto/browserspeak"
	"github.com/xyproto/web"
)

type MenuEntry struct {
	id string
	text string
	url string
}

type MenuEntries []*MenuEntry

// Generate a menu ID based on the first word in the menu text
func (me *MenuEntry) AutoId() {
	firstword := me.text
	if strings.Contains(me.text, " ") {
		// Get the first word of the menu text
		firstword = strings.SplitN(me.text, " ", 2)[0]
	}
	me.id = firstword
}

// Takes something like "Admin:/admin" and returns a *MenuEntry
func NewMenuEntry(text_and_url string) *MenuEntry {
	var me MenuEntry
	me.text, me.url = ColonSplit(text_and_url)
	me.AutoId()
	return &me
}

func Links2menuEntries(links []string) MenuEntries {
	menuEntries := make(MenuEntries, len(links))
	for i, text_and_url := range links {
		menuEntries[i] = NewMenuEntry(text_and_url)
	}
	return menuEntries
}

// Generate tags for the menu based on a list of "MenuDescription:/menu/url"
func MenuSnippet(menuEntries MenuEntries) *Page {
	var a, li, sep *Tag

	page, ul := CowboyTag("ul")
	ul.AddAttr("class", "menuList")
	//ul.AddStyle("list-style-type", "none")
	//ul.AddStyle("float", "left")
	//ul.AddStyle("margin", "0")

	for i, menuEntry := range menuEntries {

		li = ul.AddNewTag("li")
		li.AddAttr("class", "menuEntry")

		// TODO: Make sure not duplicate ids are added for two menu entries named "Hi there" and "Hi you"
		menuId := "menu" + menuEntry.id
		li.AddAttr("id", menuId)

		// All menu entries are now hidden by default!
		//li.AddStyle("display", "none")
		//li.AddStyle("display", "inline")
		li.SansSerif()
		//li.CustomSansSerif("Armata")

		// For every element, but not the first one
		if i > 0 {
			// Insert a '|' character in a div
			sep = li.AddNewTag("div")
			sep.AddContent("|")
			sep.AddAttr("class", "separator")
		}

		a = li.AddNewTag("a")
		a.AddAttr("class", "menulink")
		a.AddAttr("href", menuEntry.url)
		a.AddContent(menuEntry.text)

	}

	return page
}

// Checks if a *MenuEntry exists in a []*MenuEntry (MenuEntries)
func HasEntry(checkEntry *MenuEntry, menuEntries MenuEntries) bool {
	for _, menuEntry := range menuEntries {
		if menuEntry.url == checkEntry.url {
			return true
		}
	}
	return false
}

func AddIfNotAdded(url string, filteredMenuEntries *MenuEntries, menuEntry *MenuEntry) {
	//if currentMenuURL != url {
	if menuEntry.url == url {
		if !HasEntry(menuEntry, *filteredMenuEntries) {
			*filteredMenuEntries = append(*filteredMenuEntries, menuEntry)
		}
	}
	//}
}

/*
 * Functions that generate functions that generate content that can be used in templates.
 * type TemplateValues map[string]string
 * type TemplateValueGenerator func(*web.Context) TemplateValues
 * type TemplateValueGeneratorFactory func(*UserState) TemplateValueGenerator
 */
// TODO: Take the same parameters as the old menu generating code
// TODO: Put one if these in each engine then combine them somehow
// TODO: Check for the menyEntry.url first, then check the rights, not the other way around
// TODO: Fix and refactor this one
// TODO: Check the user status _once_, and the admin status _once_, then generate the menu
func DynamicMenuFactoryGenerator(menuEntries MenuEntries) TemplateValueGeneratorFactory {
	return func(state *UserState) TemplateValueGenerator {
		return func(ctx *web.Context) TemplateValues {

			var filteredMenuEntries MenuEntries
			var logoutEntry *MenuEntry = nil

			// Build up filteredMenuEntries based on what should be shown or not
			for _, menuEntry := range menuEntries {

				// Don't add duplicates
				if HasEntry(menuEntry, filteredMenuEntries) {
					continue
				}

				// Add this one last
				if menuEntry.url == "/logout" {
					if state.UserRights(ctx) {
						logoutEntry = menuEntry
					}
					continue
				}

				// Always show the Overview menu
				AddIfNotAdded("/", &filteredMenuEntries, menuEntry)
				//if menuEntry.url == "/" {
				//	if !HasEntry(menuEntry, filteredMenuEntries) {
				//		filteredMenuEntries = append(filteredMenuEntries, menuEntry)
				//	}
				//}

				// If logged in, show Logout and the content
				if state.UserRights(ctx) {

					// Add every link except the current page we're on
					//if menuEntry.url != currentMenuURL {
					if !HasEntry(menuEntry, filteredMenuEntries) {
						if (menuEntry.url != "/login") && (menuEntry.url != "/register") && (menuEntry.url != "/admin") {
							filteredMenuEntries = append(filteredMenuEntries, menuEntry)
						}
					}
					//}

					// Show admin content
					if state.AdminRights(ctx) {
						AddIfNotAdded("/admin", &filteredMenuEntries, menuEntry)
					}
				} else {
					// Only show Login and Register
					AddIfNotAdded("/login", &filteredMenuEntries, menuEntry)
					AddIfNotAdded("/register", &filteredMenuEntries, menuEntry)
				}

			}

			if logoutEntry != nil {
				AddIfNotAdded("/logout", &filteredMenuEntries, logoutEntry)
			}

			page := MenuSnippet(filteredMenuEntries)
			retval := page.String()

			// TODO: Return the CSS as well somehow
			//css := page.CSS()

			return TemplateValues{"menu": retval}
		}
	}
}

// Combines two TemplateValueGenerators into one TemplateValueGenerator by adding the strings per key
func TemplateValueGeneratorCombinator(tvg1, tvg2 TemplateValueGenerator) TemplateValueGenerator {
	return func(ctx *web.Context) TemplateValues {
		tv1 := tvg1(ctx)
		tv2 := tvg2(ctx)
		for key, value := range tv2 {
			// TODO: Check if key exists in tv1 first
			tv1[key] += value
		}
		return tv1
	}
}
<commit_msg>Cached user rights lookups<commit_after>package genericsite

import (
	"strings"

	. "github.com/xyproto/browserspeak"
	"github.com/xyproto/web"
)

type MenuEntry struct {
	id string
	text string
	url string
}

type MenuEntries []*MenuEntry

// Generate a menu ID based on the first word in the menu text
func (me *MenuEntry) AutoId() {
	firstword := me.text
	if strings.Contains(me.text, " ") {
		// Get the first word of the menu text
		firstword = strings.SplitN(me.text, " ", 2)[0]
	}
	me.id = firstword
}

// Takes something like "Admin:/admin" and returns a *MenuEntry
func NewMenuEntry(text_and_url string) *MenuEntry {
	var me MenuEntry
	me.text, me.url = ColonSplit(text_and_url)
	me.AutoId()
	return &me
}

func Links2menuEntries(links []string) MenuEntries {
	menuEntries := make(MenuEntries, len(links))
	for i, text_and_url := range links {
		menuEntries[i] = NewMenuEntry(text_and_url)
	}
	return menuEntries
}

// Generate tags for the menu based on a list of "MenuDescription:/menu/url"
func MenuSnippet(menuEntries MenuEntries) *Page {
	var a, li, sep *Tag

	page, ul := CowboyTag("ul")
	ul.AddAttr("class", "menuList")
	//ul.AddStyle("list-style-type", "none")
	//ul.AddStyle("float", "left")
	//ul.AddStyle("margin", "0")

	for i, menuEntry := range menuEntries {

		li = ul.AddNewTag("li")
		li.AddAttr("class", "menuEntry")

		// TODO: Make sure not duplicate ids are added for two menu entries named "Hi there" and "Hi you"
		menuId := "menu" + menuEntry.id
		li.AddAttr("id", menuId)

		// All menu entries are now hidden by default!
		//li.AddStyle("display", "none")
		//li.AddStyle("display", "inline")
		li.SansSerif()
		//li.CustomSansSerif("Armata")

		// For every element, but not the first one
		if i > 0 {
			// Insert a '|' character in a div
			sep = li.AddNewTag("div")
			sep.AddContent("|")
			sep.AddAttr("class", "separator")
		}

		a = li.AddNewTag("a")
		a.AddAttr("class", "menulink")
		a.AddAttr("href", menuEntry.url)
		a.AddContent(menuEntry.text)

	}

	return page
}

// Checks if a *MenuEntry exists in a []*MenuEntry (MenuEntries)
func HasEntry(checkEntry *MenuEntry, menuEntries MenuEntries) bool {
	for _, menuEntry := range menuEntries {
		if menuEntry.url == checkEntry.url {
			return true
		}
	}
	return false
}

func AddIfNotAdded(url string, filteredMenuEntries *MenuEntries, menuEntry *MenuEntry) {
	//if currentMenuURL != url {
	if menuEntry.url == url {
		if !HasEntry(menuEntry, *filteredMenuEntries) {
			*filteredMenuEntries = append(*filteredMenuEntries, menuEntry)
		}
	}
	//}
}

/*
 * Functions that generate functions that generate content that can be used in templates.
 * type TemplateValues map[string]string
 * type TemplateValueGenerator func(*web.Context) TemplateValues
 * type TemplateValueGeneratorFactory func(*UserState) TemplateValueGenerator
 */
// TODO: Take the same parameters as the old menu generating code
// TODO: Put one if these in each engine then combine them somehow
// TODO: Check for the menyEntry.url first, then check the rights, not the other way around
// TODO: Fix and refactor this one
// TODO: Check the user status _once_, and the admin status _once_, then generate the menu
func DynamicMenuFactoryGenerator(menuEntries MenuEntries) TemplateValueGeneratorFactory {
	return func(state *UserState) TemplateValueGenerator {
		return func(ctx *web.Context) TemplateValues {

			userRights := state.UserRights(ctx)
			adminRights := state.AdminRights(ctx)

			var filteredMenuEntries MenuEntries
			var logoutEntry *MenuEntry = nil

			// Build up filteredMenuEntries based on what should be shown or not
			for _, menuEntry := range menuEntries {

				// Don't add duplicates
				if HasEntry(menuEntry, filteredMenuEntries) {
					continue
				}

				// Add this one last
				if menuEntry.url == "/logout" {
					if userRights {
						logoutEntry = menuEntry
					}
					continue
				}

				// Always show the Overview menu
				AddIfNotAdded("/", &filteredMenuEntries, menuEntry)
				//if menuEntry.url == "/" {
				//	if !HasEntry(menuEntry, filteredMenuEntries) {
				//		filteredMenuEntries = append(filteredMenuEntries, menuEntry)
				//	}
				//}

				// If logged in, show Logout and the content
				if userRights {

					// Add every link except the current page we're on
					//if menuEntry.url != currentMenuURL {
					if !HasEntry(menuEntry, filteredMenuEntries) {
						if (menuEntry.url != "/login") && (menuEntry.url != "/register") && (menuEntry.url != "/admin") {
							filteredMenuEntries = append(filteredMenuEntries, menuEntry)
						}
					}
					//}

					// Show admin content
					if adminRights {
						AddIfNotAdded("/admin", &filteredMenuEntries, menuEntry)
					}
				} else {
					// Only show Login and Register
					AddIfNotAdded("/login", &filteredMenuEntries, menuEntry)
					AddIfNotAdded("/register", &filteredMenuEntries, menuEntry)
				}

			}

			if logoutEntry != nil {
				AddIfNotAdded("/logout", &filteredMenuEntries, logoutEntry)
			}

			page := MenuSnippet(filteredMenuEntries)
			retval := page.String()

			// TODO: Return the CSS as well somehow
			//css := page.CSS()

			return TemplateValues{"menu": retval}
		}
	}
}

// Combines two TemplateValueGenerators into one TemplateValueGenerator by adding the strings per key
func TemplateValueGeneratorCombinator(tvg1, tvg2 TemplateValueGenerator) TemplateValueGenerator {
	return func(ctx *web.Context) TemplateValues {
		tv1 := tvg1(ctx)
		tv2 := tvg2(ctx)
		for key, value := range tv2 {
			// TODO: Check if key exists in tv1 first
			tv1[key] += value
		}
		return tv1
	}
}
<|endoftext|>


<commit_before>package nsq

import (
	"bytes"
	"encoding/binary"
	"io"
	"io/ioutil"
	"time"
)

const MsgIdLength = 16

// Message is the fundamental data type containing
// the id, body, and meta-data
type Message struct {
	Id        []byte
	Body      []byte
	Timestamp int64
	Attempts  uint16
}

// NewMessage creates a Message, initializes some meta-data,
// and returns a pointer
func NewMessage(id []byte, body []byte) *Message {
	return &Message{
		Id:        id,
		Body:      body,
		Timestamp: time.Now().Unix(),
	}
}

// EncodeBytes serializes the message into a new []byte
func (m *Message) EncodeBytes() ([]byte, error) {
	var buf bytes.Buffer
	err := m.Encode(&buf)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// Encode serializes the message into the supplied writer
func (m *Message) Encode(w io.Writer) error {
	err := binary.Write(w, binary.BigEndian, &m.Timestamp)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, &m.Attempts)
	if err != nil {
		return err
	}

	_, err = w.Write(m.Id)
	if err != nil {
		return err
	}

	_, err = w.Write(m.Body)
	if err != nil {
		return err
	}

	return nil
}

// DecodeMessage deseralizes data (as []byte) and creates/returns
// a pointer to a new Message
func DecodeMessage(byteBuf []byte) (*Message, error) {
	var timestamp int64
	var attempts uint16

	buf := bytes.NewBuffer(byteBuf)

	err := binary.Read(buf, binary.BigEndian, &timestamp)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &attempts)
	if err != nil {
		return nil, err
	}

	id := make([]byte, MsgIdLength)
	_, err = io.ReadFull(buf, id)
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(buf)
	if err != nil {
		return nil, err
	}

	msg := NewMessage(id, body)
	msg.Timestamp = timestamp
	msg.Attempts = attempts

	return msg, nil
}
<commit_msg>nsqd: rename msg.Encode -> msg.Write<commit_after>package nsq

import (
	"bytes"
	"encoding/binary"
	"io"
	"io/ioutil"
	"time"
)

const MsgIdLength = 16

// Message is the fundamental data type containing
// the id, body, and meta-data
type Message struct {
	Id        []byte
	Body      []byte
	Timestamp int64
	Attempts  uint16
}

// NewMessage creates a Message, initializes some meta-data,
// and returns a pointer
func NewMessage(id []byte, body []byte) *Message {
	return &Message{
		Id:        id,
		Body:      body,
		Timestamp: time.Now().Unix(),
	}
}

// EncodeBytes serializes the message into a new []byte
func (m *Message) EncodeBytes() ([]byte, error) {
	var buf bytes.Buffer
	err := m.Write(&buf)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// Write serializes the message into the supplied writer
func (m *Message) Write(w io.Writer) error {
	err := binary.Write(w, binary.BigEndian, &m.Timestamp)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, &m.Attempts)
	if err != nil {
		return err
	}

	_, err = w.Write(m.Id)
	if err != nil {
		return err
	}

	_, err = w.Write(m.Body)
	if err != nil {
		return err
	}

	return nil
}

// DecodeMessage deseralizes data (as []byte) and creates/returns
// a pointer to a new Message
func DecodeMessage(byteBuf []byte) (*Message, error) {
	var timestamp int64
	var attempts uint16

	buf := bytes.NewBuffer(byteBuf)

	err := binary.Read(buf, binary.BigEndian, &timestamp)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &attempts)
	if err != nil {
		return nil, err
	}

	id := make([]byte, MsgIdLength)
	_, err = io.ReadFull(buf, id)
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(buf)
	if err != nil {
		return nil, err
	}

	msg := NewMessage(id, body)
	msg.Timestamp = timestamp
	msg.Attempts = attempts

	return msg, nil
}
<|endoftext|>