<commit_before>package synthetictests

import (
	"fmt"
	"strings"
	"time"

	"github.com/openshift/origin/pkg/test/ginkgo/junitapi"

	"github.com/openshift/origin/pkg/monitor/intervalcreation"
	"github.com/openshift/origin/pkg/monitor/monitorapi"
)

type testCategorizer struct {
	by        string
	substring string
}

func testPodSandboxCreation(events monitorapi.Intervals) []*junitapi.JUnitTestCase {
	const testName = "[sig-network] pods should successfully create sandboxes"
	// we can further refine this signal by subdividing different failure modes if it is pertinent.  Right now I'm seeing
	// 1. error reading container (probably exited) json message: EOF
	// 2. dial tcp 10.0.76.225:6443: i/o timeout
	// 3. error getting pod: pods "terminate-cmd-rpofb45fa14c-96bb-40f7-bd9e-346721740cac" not found
	// 4. write child: broken pipe
	bySubStrings := []testCategorizer{
		{by: " by reading container", substring: "error reading container (probably exited) json message: EOF"},
		{by: " by not timing out", substring: "i/o timeout"},
		{by: " by writing network status", substring: "error setting the networks status"},
		{by: " by getting pod", substring: " error getting pod: pods"},
		{by: " by writing child", substring: "write child: broken pipe"},
		{by: " by other", substring: " "}, // always matches
	}

	failures := []string{}
	flakes := []string{}
	operatorsProgressing := intervalcreation.IntervalsFromEvents_OperatorProgressing(events, time.Time{}, time.Time{})
	networkOperatorProgressing := operatorsProgressing.Filter(func(ev monitorapi.EventInterval) bool {
		return ev.Locator == "clusteroperator/network" || ev.Locator == "clusteroperator/machine-config"
	})
	eventsForPods := getEventsByPod(events)
	for _, event := range events {
		if !strings.Contains(event.Message, "reason/FailedCreatePodSandBox Failed to create pod sandbox") {
			continue
		}
		if strings.Contains(event.Message, "Multus") && strings.Contains(event.Message, "error getting pod") && (strings.Contains(event.Message, "connection refused") || strings.Contains(event.Message, "i/o timeout")) {
			flakes = append(flakes, fmt.Sprintf("%v - multus is unable to get pods due to LB disruption https://bugzilla.redhat.com/show_bug.cgi?id=1927264 - %v", event.Locator, event.Message))
			continue
		}
		if strings.Contains(event.Message, "Multus") && strings.Contains(event.Message, "error getting pod: Unauthorized") {
			flakes = append(flakes, fmt.Sprintf("%v - multus is unable to get pods due to authorization https://bugzilla.redhat.com/show_bug.cgi?id=1972490 - %v", event.Locator, event.Message))
			continue
		}
		deletionTime := getPodDeletionTime(eventsForPods[event.Locator], event.Locator)
		if deletionTime == nil {
			// mark sandboxes errors as flakes if networking is being updated
			match := -1
			for i := range networkOperatorProgressing {
				matchesFrom := event.From.After(networkOperatorProgressing[i].From)
				matchesTo := event.To.Before(networkOperatorProgressing[i].To)
				if matchesFrom && matchesTo {
					match = i
					break
				}
			}
			if match != -1 {
				flakes = append(flakes, fmt.Sprintf("%v - never deleted - network rollout - %v", event.Locator, event.Message))
			} else {
				failures = append(failures, fmt.Sprintf("%v - never deleted - %v", event.Locator, event.Message))
			}
		} else {
			timeBetweenDeleteAndFailure := event.From.Sub(*deletionTime)
			switch {
			case timeBetweenDeleteAndFailure < 1*time.Second:
				// nothing here, one second is close enough to be ok, the kubelet and CNI just didn't know
			case timeBetweenDeleteAndFailure < 5*time.Second:
				// withing five seconds, it ought to be long enough to know, but it's close enough to flake and not fail
				flakes = append(flakes, fmt.Sprintf("%v - %0.2f seconds after deletion - %v", event.Locator, timeBetweenDeleteAndFailure.Seconds(), event.Message))
			case deletionTime.Before(event.From):
				// something went wrong.  More than five seconds after the pod ws deleted, the CNI is trying to set up pod sandboxes and can't
				failures = append(failures, fmt.Sprintf("%v - %0.2f seconds after deletion - %v", event.Locator, timeBetweenDeleteAndFailure.Seconds(), event.Message))
			default:
				// something went wrong.  deletion happend after we had a failure to create the pod sandbox
				failures = append(failures, fmt.Sprintf("%v - deletion came AFTER sandbox failure - %v", event.Locator, event.Message))
			}
		}
	}
	failuresBySubtest, flakesBySubtest := categorizeBySubset(bySubStrings, failures, flakes)
	successes := []*junitapi.JUnitTestCase{}
	for _, by := range bySubStrings {
		if _, ok := failuresBySubtest[by.by]; ok {
			continue
		}
		if _, ok := flakesBySubtest[by.by]; ok {
			continue
		}

		successes = append(successes, &junitapi.JUnitTestCase{Name: testName + by.by})
	}

	if len(failures) == 0 && len(flakes) == 0 {
		return successes
	}

	ret := []*junitapi.JUnitTestCase{}
	// now iterate the individual failures to create failure entries
	for by, subFailures := range failuresBySubtest {
		failure := &junitapi.JUnitTestCase{
			Name:      testName + by,
			SystemOut: strings.Join(subFailures, "\n"),
			FailureOutput: &junitapi.FailureOutput{
				Output: fmt.Sprintf("%d failures to create the sandbox\n\n%v", len(subFailures), strings.Join(subFailures, "\n")),
			},
		}
		ret = append(ret, failure)
	}
	for by, subFlakes := range flakesBySubtest {
		flake := &junitapi.JUnitTestCase{
			Name:      testName + by,
			SystemOut: strings.Join(subFlakes, "\n"),
			FailureOutput: &junitapi.FailureOutput{
				Output: fmt.Sprintf("%d failures to create the sandbox\n\n%v", len(subFlakes), strings.Join(subFlakes, "\n")),
			},
		}
		ret = append(ret, flake)
		// write a passing test to trigger detection of this issue as a flake. Doing this first to try to see how frequent the issue actually is
		success := &junitapi.JUnitTestCase{
			Name: testName + by,
		}
		ret = append(ret, success)
	}

	// add our successes
	ret = append(ret, successes...)

	return append(ret)
}

// categorizeBySubset returns a map keyed by category for failures and flakes.  If a category is present in both failures and flakes, all are listed under failures.
func categorizeBySubset(categorizers []testCategorizer, failures, flakes []string) (map[string][]string, map[string][]string) {
	failuresBySubtest := map[string][]string{}
	flakesBySubtest := map[string][]string{}
	for _, failure := range failures {
		for _, by := range categorizers {
			if strings.Contains(failure, by.substring) {
				failuresBySubtest[by.by] = append(failuresBySubtest[by.by], failure)
				break // break after first match so we only add each failure one bucket
			}
		}
	}

	for _, flake := range flakes {
		for _, by := range categorizers {
			if strings.Contains(flake, by.substring) {
				if _, isFailure := failuresBySubtest[by.by]; isFailure {
					failuresBySubtest[by.by] = append(failuresBySubtest[by.by], flake)
				} else {
					flakesBySubtest[by.by] = append(flakesBySubtest[by.by], flake)
				}
				break // break after first match so we only add each failure one bucket
			}
		}
	}
	return failuresBySubtest, flakesBySubtest
}

// getEventsByPod returns map keyed by pod locator with all events associated with it.
func getEventsByPod(events monitorapi.Intervals) map[string]monitorapi.Intervals {
	eventsByPods := map[string]monitorapi.Intervals{}
	for _, event := range events {
		if !strings.Contains(event.Locator, "pod/") {
			continue
		}
		eventsByPods[event.Locator] = append(eventsByPods[event.Locator], event)
	}
	return eventsByPods
}

func getPodDeletionTime(events monitorapi.Intervals, podLocator string) *time.Time {
	for _, event := range events {
		if event.Locator == podLocator && event.Message == "reason/Deleted" {
			return &event.From
		}
	}
	return nil
}
<commit_msg>Flake failed sandboxes from bug in new guard pods<commit_after>package synthetictests

import (
	"fmt"
	"strings"
	"time"

	"github.com/openshift/origin/pkg/test/ginkgo/junitapi"

	"github.com/openshift/origin/pkg/monitor/intervalcreation"
	"github.com/openshift/origin/pkg/monitor/monitorapi"
)

type testCategorizer struct {
	by        string
	substring string
}

func testPodSandboxCreation(events monitorapi.Intervals) []*junitapi.JUnitTestCase {
	const testName = "[sig-network] pods should successfully create sandboxes"
	// we can further refine this signal by subdividing different failure modes if it is pertinent.  Right now I'm seeing
	// 1. error reading container (probably exited) json message: EOF
	// 2. dial tcp 10.0.76.225:6443: i/o timeout
	// 3. error getting pod: pods "terminate-cmd-rpofb45fa14c-96bb-40f7-bd9e-346721740cac" not found
	// 4. write child: broken pipe
	bySubStrings := []testCategorizer{
		{by: " by reading container", substring: "error reading container (probably exited) json message: EOF"},
		{by: " by not timing out", substring: "i/o timeout"},
		{by: " by writing network status", substring: "error setting the networks status"},
		{by: " by getting pod", substring: " error getting pod: pods"},
		{by: " by writing child", substring: "write child: broken pipe"},
		{by: " by other", substring: " "}, // always matches
	}

	failures := []string{}
	flakes := []string{}
	operatorsProgressing := intervalcreation.IntervalsFromEvents_OperatorProgressing(events, time.Time{}, time.Time{})
	networkOperatorProgressing := operatorsProgressing.Filter(func(ev monitorapi.EventInterval) bool {
		return ev.Locator == "clusteroperator/network" || ev.Locator == "clusteroperator/machine-config"
	})
	eventsForPods := getEventsByPod(events)
	for _, event := range events {
		if !strings.Contains(event.Message, "reason/FailedCreatePodSandBox Failed to create pod sandbox") {
			continue
		}
		if strings.Contains(event.Message, "Multus") && strings.Contains(event.Message, "error getting pod") && (strings.Contains(event.Message, "connection refused") || strings.Contains(event.Message, "i/o timeout")) {
			flakes = append(flakes, fmt.Sprintf("%v - multus is unable to get pods due to LB disruption https://bugzilla.redhat.com/show_bug.cgi?id=1927264 - %v", event.Locator, event.Message))
			continue
		}
		if strings.Contains(event.Message, "Multus") && strings.Contains(event.Message, "error getting pod: Unauthorized") {
			flakes = append(flakes, fmt.Sprintf("%v - multus is unable to get pods due to authorization https://bugzilla.redhat.com/show_bug.cgi?id=1972490 - %v", event.Locator, event.Message))
			continue
		}
		deletionTime := getPodDeletionTime(eventsForPods[event.Locator], event.Locator)
		if deletionTime == nil {
			// mark sandboxes errors as flakes if networking is being updated
			match := -1
			for i := range networkOperatorProgressing {
				matchesFrom := event.From.After(networkOperatorProgressing[i].From)
				matchesTo := event.To.Before(networkOperatorProgressing[i].To)
				if matchesFrom && matchesTo {
					match = i
					break
				}
			}
			if match != -1 {
				flakes = append(flakes, fmt.Sprintf("%v - never deleted - network rollout - %v", event.Locator, event.Message))
			} else {
				failures = append(failures, fmt.Sprintf("%v - never deleted - %v", event.Locator, event.Message))
			}
		} else {
			timeBetweenDeleteAndFailure := event.From.Sub(*deletionTime)
			nodeRebootTime := getNodeRebootTime(events, monitorapi.LocatorParts(event.Locator)["node"])
			switch {
			case timeBetweenDeleteAndFailure < 1*time.Second:
				// nothing here, one second is close enough to be ok, the kubelet and CNI just didn't know
			case timeBetweenDeleteAndFailure < 5*time.Second:
				// withing five seconds, it ought to be long enough to know, but it's close enough to flake and not fail
				flakes = append(flakes, fmt.Sprintf("%v - %0.2f seconds after deletion - %v", event.Locator, timeBetweenDeleteAndFailure.Seconds(), event.Message))
			case nodeRebootTime != nil && nodeRebootTime.After(*deletionTime) && strings.Contains(event.Locator, "guard"):
				flakes = append(flakes, fmt.Sprintf("the deletion time %v came before a reboot at %v and error is coming "+
					"from a guard pod. see https://bugzilla.redhat.com/show_bug.cgi?id=2038481", deletionTime, nodeRebootTime))
			case deletionTime.Before(event.From):
				// something went wrong.  More than five seconds after the pod ws deleted, the CNI is trying to set up pod sandboxes and can't
				failures = append(failures, fmt.Sprintf("%v - %0.2f seconds after deletion - %v", event.Locator, timeBetweenDeleteAndFailure.Seconds(), event.Message))
			default:
				// something went wrong.  deletion happend after we had a failure to create the pod sandbox
				failures = append(failures, fmt.Sprintf("%v - deletion came AFTER sandbox failure - %v", event.Locator, event.Message))
			}
		}
	}
	failuresBySubtest, flakesBySubtest := categorizeBySubset(bySubStrings, failures, flakes)
	successes := []*junitapi.JUnitTestCase{}
	for _, by := range bySubStrings {
		if _, ok := failuresBySubtest[by.by]; ok {
			continue
		}
		if _, ok := flakesBySubtest[by.by]; ok {
			continue
		}

		successes = append(successes, &junitapi.JUnitTestCase{Name: testName + by.by})
	}

	if len(failures) == 0 && len(flakes) == 0 {
		return successes
	}

	ret := []*junitapi.JUnitTestCase{}
	// now iterate the individual failures to create failure entries
	for by, subFailures := range failuresBySubtest {
		failure := &junitapi.JUnitTestCase{
			Name:      testName + by,
			SystemOut: strings.Join(subFailures, "\n"),
			FailureOutput: &junitapi.FailureOutput{
				Output: fmt.Sprintf("%d failures to create the sandbox\n\n%v", len(subFailures), strings.Join(subFailures, "\n")),
			},
		}
		ret = append(ret, failure)
	}
	for by, subFlakes := range flakesBySubtest {
		flake := &junitapi.JUnitTestCase{
			Name:      testName + by,
			SystemOut: strings.Join(subFlakes, "\n"),
			FailureOutput: &junitapi.FailureOutput{
				Output: fmt.Sprintf("%d failures to create the sandbox\n\n%v", len(subFlakes), strings.Join(subFlakes, "\n")),
			},
		}
		ret = append(ret, flake)
		// write a passing test to trigger detection of this issue as a flake. Doing this first to try to see how frequent the issue actually is
		success := &junitapi.JUnitTestCase{
			Name: testName + by,
		}
		ret = append(ret, success)
	}

	// add our successes
	ret = append(ret, successes...)

	return append(ret)
}

// categorizeBySubset returns a map keyed by category for failures and flakes.  If a category is present in both failures and flakes, all are listed under failures.
func categorizeBySubset(categorizers []testCategorizer, failures, flakes []string) (map[string][]string, map[string][]string) {
	failuresBySubtest := map[string][]string{}
	flakesBySubtest := map[string][]string{}
	for _, failure := range failures {
		for _, by := range categorizers {
			if strings.Contains(failure, by.substring) {
				failuresBySubtest[by.by] = append(failuresBySubtest[by.by], failure)
				break // break after first match so we only add each failure one bucket
			}
		}
	}

	for _, flake := range flakes {
		for _, by := range categorizers {
			if strings.Contains(flake, by.substring) {
				if _, isFailure := failuresBySubtest[by.by]; isFailure {
					failuresBySubtest[by.by] = append(failuresBySubtest[by.by], flake)
				} else {
					flakesBySubtest[by.by] = append(flakesBySubtest[by.by], flake)
				}
				break // break after first match so we only add each failure one bucket
			}
		}
	}
	return failuresBySubtest, flakesBySubtest
}

// getEventsByPod returns map keyed by pod locator with all events associated with it.
func getEventsByPod(events monitorapi.Intervals) map[string]monitorapi.Intervals {
	eventsByPods := map[string]monitorapi.Intervals{}
	for _, event := range events {
		if !strings.Contains(event.Locator, "pod/") {
			continue
		}
		eventsByPods[event.Locator] = append(eventsByPods[event.Locator], event)
	}
	return eventsByPods
}

func getPodDeletionTime(events monitorapi.Intervals, podLocator string) *time.Time {
	for _, event := range events {
		if event.Locator == podLocator && event.Message == "reason/Deleted" {
			return &event.From
		}
	}
	return nil
}

func getNodeRebootTime(events monitorapi.Intervals, node string) *time.Time {

	for _, event := range events {
		eventNodeName, _ := monitorapi.NodeFromLocator(event.Locator)
		if eventNodeName == node && strings.Contains(event.Message, "reason/Rebooted") {
			return &event.From
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package builder

import "fmt"

// Between
type Between struct {
	col     string
	lessVal interface{}
	moreVal interface{}
}

var _ Cond = Between{}

func (between Between) WriteTo(w Writer) error {
	if _, err := fmt.Fprintf(w, "%s BETWEEN ? AND ?", between.col); err != nil {
		return err
	}
	w.Append(between.lessVal, between.moreVal)
	return nil
}

func (between Between) And(conds ...Cond) Cond {
	return And(between, And(conds...))
}

func (between Between) Or(conds ...Cond) Cond {
	return Or(between, Or(conds...))
}

func (between Between) IsValid() bool {
	return len(between.col) > 0
}
<commit_msg>bug fixed for lower struct fields of Between<commit_after>package builder

import "fmt"

// Between
type Between struct {
	Col     string
	LessVal interface{}
	MoreVal interface{}
}

var _ Cond = Between{}

func (between Between) WriteTo(w Writer) error {
	if _, err := fmt.Fprintf(w, "%s BETWEEN ? AND ?", between.Col); err != nil {
		return err
	}
	w.Append(between.LessVal, between.MoreVal)
	return nil
}

func (between Between) And(conds ...Cond) Cond {
	return And(between, And(conds...))
}

func (between Between) Or(conds ...Cond) Cond {
	return Or(between, Or(conds...))
}

func (between Between) IsValid() bool {
	return len(between.Col) > 0
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/hut8/tumblr-go"
	"regexp"
	"strconv"
)

var (
	tumblrDataRegexp *regexp.Regexp = regexp.MustCompile("http://([^/]+)/post/(\\d+)(?:/.+)?")
)

// http://lacecard.tumblr.com/post/76803575816/emacs-in-tron -> (lacecard.tumblr.com, 76803575816)
func extractPostId(u string) (string, int64, error) {
	m := tumblrDataRegexp.FindStringSubmatch(u)
	if m == nil {
		return "", 0, fmt.Errorf("Could not extract base hostname and post ID")
	}
	bh := m[1]
	pid, err := strconv.ParseInt(m[2], 10, 64)
	ensureNil(err) // For 2^64+
	return bh, pid, nil
}

// Return a slice of blog names who like the given post
func blogsLikingPost(baseHostname string, postId int64) []string {
	client := tumblr.Tumblr{
		Credentials: getCredentials(),
	}
	blog := client.NewBlog(baseHostname)
	params := tumblr.PostRequestParams{
		Id:        postId,
		NotesInfo: true,
	}
	posts, err := blog.Posts(params)
	ensureNil(err)

	// Filter out only "likes" and "reblogs"
	return nil
}

func getCredentials() tumblr.APICredentials {
	return tumblr.APICredentials{
		Key:    os.Getenv("ALIKER_KEY"),
		Secret: os.Getenv("ALIKER_SECRET"),
	}
}
<commit_msg>This is really ugly, but surprisingly it works!  It now gets the blog names of a liked post.<commit_after>package main

import (
	"fmt"
	"github.com/hut8/tumblr-go"
	"os"
	"regexp"
	"strconv"
)

var (
	tumblrDataRegexp *regexp.Regexp = regexp.MustCompile("http://([^/]+)/post/(\\d+)(?:/.+)?")
)

// http://lacecard.tumblr.com/post/76803575816/emacs-in-tron -> (lacecard.tumblr.com, 76803575816)
func extractPostId(u string) (string, int64, error) {
	m := tumblrDataRegexp.FindStringSubmatch(u)
	if m == nil {
		return "", 0, fmt.Errorf("Could not extract base hostname and post ID")
	}
	bh := m[1]
	pid, err := strconv.ParseInt(m[2], 10, 64)
	ensureNil(err) // For 2^64+
	return bh, pid, nil
}

// Return a slice of blog names who like the given post
func blogsLikingPost(baseHostname string, postId int64) []string {
	client := tumblr.Tumblr{
		Credentials: getCredentials(),
	}
	blog := client.NewBlog(baseHostname)
	params := tumblr.PostRequestParams{
		Id:        postId,
		NotesInfo: true,
	}
	posts, err := blog.Posts(params)
	ensureNil(err)
	// posts must be of length 1 because we specified an ID
	p := posts[0].(map[string]interface{})
	notes := p["notes"].([]interface{})
	var blogNames []string
	for _, rawNote := range notes {
		note := rawNote.(map[string]interface{})
		blogNames = append(blogNames, note["blog_name"].(string))
	}

	// Filter out only "likes" and "reblogs"
	return blogNames
}

func getCredentials() tumblr.APICredentials {
	return tumblr.APICredentials{
		Key:    os.Getenv("ALIKER_KEY"),
		Secret: os.Getenv("ALIKER_SECRET"),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/andygrunwald/TrendingGithub/storage"
	"github.com/andygrunwald/go-trending"
	"github.com/google/go-github/github"
	"log"
	"strconv"
	"strings"
	"time"
)

type TweetSearch struct {
	Channel   chan *Tweet
	Trending  *Trend
	Storage   storage.Pool
	URLLength int
}

// Tweet is a structure to store the tweet and the project name based on the tweet.
type Tweet struct {
	Tweet       string
	ProjectName string
}

// GenerateNewTweet is responsible to search a new project / repository
// and build a new tweet based on this.
// The generated tweet will be sent to tweetChan.
func (ts *TweetSearch) GenerateNewTweet() {
	var projectToTweet trending.Project

	// Get timeframes and randomize them
	timeFrames := ts.Trending.GetTimeFrames()
	ShuffleStringSlice(timeFrames)

	// First get the timeframes without any languages
	projectToTweet = ts.TimeframeLoopToSearchAProject(timeFrames, "")

	// Check if we found a project. If yes tweet it.
	if ts.IsProjectEmpty(projectToTweet) == false {
		ts.SendProject(projectToTweet)
		return
	}

	// If not, keep going and try to get some (trending) languages
	languages := ts.Trending.GetTrendingLanguages()
	ShuffleStringSlice(languages)
	ShuffleStringSlice(timeFrames)

	for _, language := range languages {
		projectToTweet = ts.TimeframeLoopToSearchAProject(timeFrames, language)

		// If we found a project, break this loop again.
		if ts.IsProjectEmpty(projectToTweet) == false {
			ts.SendProject(projectToTweet)
			break
		}
	}
}

// timeframeLoopToSearchAProject provides basicly a loop over incoming timeFrames (+ language)
// to try to find a new tweet.
// You can say that this is nearly the <3 of this bot.
func (ts *TweetSearch) TimeframeLoopToSearchAProject(timeFrames []string, language string) trending.Project {
	var projectToTweet trending.Project

	for _, timeFrame := range timeFrames {
		if len(language) > 0 {
			log.Printf("Getting projects for timeframe %s and language %s", timeFrame, language)
		} else {
			log.Printf("Getting projects for timeframe %s", timeFrame)
		}

		getProject := ts.Trending.GetRandomProjectGenerator(timeFrame, language)
		projectToTweet = ts.FindProjectWithRandomProjectGenerator(getProject)

		// Check if we found a project.
		// If yes we can leave the loop and keep on rockin
		if ts.IsProjectEmpty(projectToTweet) == false {
			break
		}
	}

	return projectToTweet
}

// sendProject puts the project we want to tweet into the tweet queue
// If the queue is ready to receive a new project, this will be tweeted
func (ts *TweetSearch) SendProject(p trending.Project) {
	text := ""
	// Only build tweet if necessary
	if len(p.Name) > 0 {
		// This is a really hack here ...
		// We have to abstract this a little bit.
		// Eieieieiei
		repository, _ := GetRepositoryDetails(p.Owner, p.RepositoryName)

		text = ts.BuildTweet(p, repository)
	}

	tweet := &Tweet{
		Tweet:       text,
		ProjectName: p.Name,
	}
	ts.Channel <- tweet
}

// isProjectEmpty checks if the incoming project is empty
func (ts *TweetSearch) IsProjectEmpty(p trending.Project) bool {
	if len(p.Name) > 0 {
		return false
	}

	return true
}

// FindProjectWithRandomProjectGenerator retrieves a new project and checks if this was already tweeted.
func (ts *TweetSearch) FindProjectWithRandomProjectGenerator(getProject func() (trending.Project, error)) trending.Project {
	var projectToTweet trending.Project
	var project trending.Project
	var projectErr error

	storageConn := ts.Storage.Get()
	defer storageConn.Close()

	for project, projectErr = getProject(); projectErr == nil; project, projectErr = getProject() {
		// Check if the project was already tweeted
		alreadyTweeted, err := storageConn.IsRepositoryAlreadyTweeted(project.Name)
		if err != nil {
			log.Println(err)
			continue
		}

		// If the project was already tweeted
		// we will skip this project and go to the next one
		if alreadyTweeted == true {
			continue
		}

		// This project wasn`t tweeted yet, so we will take over this job
		projectToTweet = project
		break
	}

	return projectToTweet
}

// buildTweet is responsible to build a 140 length string based on the project we found.
func (ts *TweetSearch) BuildTweet(p trending.Project, repo *github.Repository) string {
	tweet := ""
	// Base length of a tweet
	tweetLen := 140

	// Number of letters for the url (+ 1 character for a whitespace)
	// As URL shortener t.co from twitter is used
	// URLLength will be constantly refreshed
	tweetLen -= ts.URLLength + 1

	// Check if the length of the project name is bigger than the space in the tweet
	// BUG(andygrunwald): If a name of a project got more chars as a tweet, we will generate a tweet without project name
	if nameLen := len(p.Name); nameLen < tweetLen {
		tweetLen -= len(p.Name)
		tweet += p.Name
	}

	// We only post a description if we got more than 20 charactes available
	// We have to add 2 chars more, because of the prefix ": "
	if tweetLen > 22 && len(p.Description) > 0 {
		tweetLen -= 2
		tweet += ": "

		projectDescription := ""
		if len(p.Description) < tweetLen {
			projectDescription = p.Description
		} else {
			projectDescription = Crop(p.Description, (tweetLen - 4), "...", true)
		}

		tweetLen -= len(projectDescription)
		tweet += projectDescription
	}

	stars := strconv.Itoa(*repo.StargazersCount)
	if starsLen := len(stars) + 2; tweetLen >= starsLen {
		tweet += " ★" + stars
		tweetLen -= starsLen
	}

	// Lets add the URL, but we don`t need to substract the chars
	// because we have done this before
	if p.URL != nil {
		tweet += " "
		tweet += p.URL.String()
	}

	// Lets check if we got space left to add the language as hashtag
	language := strings.Replace(p.Language, " ", "", -1)
	// len + 2, because of " #" in front of the hashtag
	hashTagLen := (len(language) + 2)
	if len(language) > 0 && tweetLen >= hashTagLen {
		tweet += " #" + language
		tweetLen -= hashTagLen
	}

	return tweet
}

// markTweetAsAlreadyTweeted adds a projectName to the global blacklist of already tweeted projects.
// For this we use a Sorted Set where the score is the timestamp of the tweet.
func (ts *TweetSearch) MarkTweetAsAlreadyTweeted(projectName string) (bool, error) {
	storageConn := ts.Storage.Get()
	defer storageConn.Close()

	// Generate score in format YYYYMMDDHHiiss
	now := time.Now()
	score := now.Format("20060102150405")

	res, err := storageConn.MarkRepositoryAsTweeted(projectName, score)
	if err != nil || res != true {
		log.Printf("Error during adding project %s to tweeted list: %s (%d)", projectName, err, res)
	}

	return res, err
}
<commit_msg>Getting rid of "res for printf verb %d of wrong type: bool"<commit_after>package main

import (
	"github.com/andygrunwald/TrendingGithub/storage"
	"github.com/andygrunwald/go-trending"
	"github.com/google/go-github/github"
	"log"
	"strconv"
	"strings"
	"time"
)

type TweetSearch struct {
	Channel   chan *Tweet
	Trending  *Trend
	Storage   storage.Pool
	URLLength int
}

// Tweet is a structure to store the tweet and the project name based on the tweet.
type Tweet struct {
	Tweet       string
	ProjectName string
}

// GenerateNewTweet is responsible to search a new project / repository
// and build a new tweet based on this.
// The generated tweet will be sent to tweetChan.
func (ts *TweetSearch) GenerateNewTweet() {
	var projectToTweet trending.Project

	// Get timeframes and randomize them
	timeFrames := ts.Trending.GetTimeFrames()
	ShuffleStringSlice(timeFrames)

	// First get the timeframes without any languages
	projectToTweet = ts.TimeframeLoopToSearchAProject(timeFrames, "")

	// Check if we found a project. If yes tweet it.
	if ts.IsProjectEmpty(projectToTweet) == false {
		ts.SendProject(projectToTweet)
		return
	}

	// If not, keep going and try to get some (trending) languages
	languages := ts.Trending.GetTrendingLanguages()
	ShuffleStringSlice(languages)
	ShuffleStringSlice(timeFrames)

	for _, language := range languages {
		projectToTweet = ts.TimeframeLoopToSearchAProject(timeFrames, language)

		// If we found a project, break this loop again.
		if ts.IsProjectEmpty(projectToTweet) == false {
			ts.SendProject(projectToTweet)
			break
		}
	}
}

// timeframeLoopToSearchAProject provides basicly a loop over incoming timeFrames (+ language)
// to try to find a new tweet.
// You can say that this is nearly the <3 of this bot.
func (ts *TweetSearch) TimeframeLoopToSearchAProject(timeFrames []string, language string) trending.Project {
	var projectToTweet trending.Project

	for _, timeFrame := range timeFrames {
		if len(language) > 0 {
			log.Printf("Getting projects for timeframe %s and language %s", timeFrame, language)
		} else {
			log.Printf("Getting projects for timeframe %s", timeFrame)
		}

		getProject := ts.Trending.GetRandomProjectGenerator(timeFrame, language)
		projectToTweet = ts.FindProjectWithRandomProjectGenerator(getProject)

		// Check if we found a project.
		// If yes we can leave the loop and keep on rockin
		if ts.IsProjectEmpty(projectToTweet) == false {
			break
		}
	}

	return projectToTweet
}

// sendProject puts the project we want to tweet into the tweet queue
// If the queue is ready to receive a new project, this will be tweeted
func (ts *TweetSearch) SendProject(p trending.Project) {
	text := ""
	// Only build tweet if necessary
	if len(p.Name) > 0 {
		// This is a really hack here ...
		// We have to abstract this a little bit.
		// Eieieieiei
		repository, _ := GetRepositoryDetails(p.Owner, p.RepositoryName)

		text = ts.BuildTweet(p, repository)
	}

	tweet := &Tweet{
		Tweet:       text,
		ProjectName: p.Name,
	}
	ts.Channel <- tweet
}

// isProjectEmpty checks if the incoming project is empty
func (ts *TweetSearch) IsProjectEmpty(p trending.Project) bool {
	if len(p.Name) > 0 {
		return false
	}

	return true
}

// FindProjectWithRandomProjectGenerator retrieves a new project and checks if this was already tweeted.
func (ts *TweetSearch) FindProjectWithRandomProjectGenerator(getProject func() (trending.Project, error)) trending.Project {
	var projectToTweet trending.Project
	var project trending.Project
	var projectErr error

	storageConn := ts.Storage.Get()
	defer storageConn.Close()

	for project, projectErr = getProject(); projectErr == nil; project, projectErr = getProject() {
		// Check if the project was already tweeted
		alreadyTweeted, err := storageConn.IsRepositoryAlreadyTweeted(project.Name)
		if err != nil {
			log.Println(err)
			continue
		}

		// If the project was already tweeted
		// we will skip this project and go to the next one
		if alreadyTweeted == true {
			continue
		}

		// This project wasn`t tweeted yet, so we will take over this job
		projectToTweet = project
		break
	}

	return projectToTweet
}

// buildTweet is responsible to build a 140 length string based on the project we found.
func (ts *TweetSearch) BuildTweet(p trending.Project, repo *github.Repository) string {
	tweet := ""
	// Base length of a tweet
	tweetLen := 140

	// Number of letters for the url (+ 1 character for a whitespace)
	// As URL shortener t.co from twitter is used
	// URLLength will be constantly refreshed
	tweetLen -= ts.URLLength + 1

	// Check if the length of the project name is bigger than the space in the tweet
	// BUG(andygrunwald): If a name of a project got more chars as a tweet, we will generate a tweet without project name
	if nameLen := len(p.Name); nameLen < tweetLen {
		tweetLen -= len(p.Name)
		tweet += p.Name
	}

	// We only post a description if we got more than 20 charactes available
	// We have to add 2 chars more, because of the prefix ": "
	if tweetLen > 22 && len(p.Description) > 0 {
		tweetLen -= 2
		tweet += ": "

		projectDescription := ""
		if len(p.Description) < tweetLen {
			projectDescription = p.Description
		} else {
			projectDescription = Crop(p.Description, (tweetLen - 4), "...", true)
		}

		tweetLen -= len(projectDescription)
		tweet += projectDescription
	}

	stars := strconv.Itoa(*repo.StargazersCount)
	if starsLen := len(stars) + 2; tweetLen >= starsLen {
		tweet += " ★" + stars
		tweetLen -= starsLen
	}

	// Lets add the URL, but we don`t need to substract the chars
	// because we have done this before
	if p.URL != nil {
		tweet += " "
		tweet += p.URL.String()
	}

	// Lets check if we got space left to add the language as hashtag
	language := strings.Replace(p.Language, " ", "", -1)
	// len + 2, because of " #" in front of the hashtag
	hashTagLen := (len(language) + 2)
	if len(language) > 0 && tweetLen >= hashTagLen {
		tweet += " #" + language
		tweetLen -= hashTagLen
	}

	return tweet
}

// markTweetAsAlreadyTweeted adds a projectName to the global blacklist of already tweeted projects.
// For this we use a Sorted Set where the score is the timestamp of the tweet.
func (ts *TweetSearch) MarkTweetAsAlreadyTweeted(projectName string) (bool, error) {
	storageConn := ts.Storage.Get()
	defer storageConn.Close()

	// Generate score in format YYYYMMDDHHiiss
	now := time.Now()
	score := now.Format("20060102150405")

	res, err := storageConn.MarkRepositoryAsTweeted(projectName, score)
	if err != nil || res != true {
		log.Printf("Error during adding project %s to tweeted list: %s (%v)", projectName, err, res)
	}

	return res, err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"github.com/jzipfler/htw-ava/filehandler"
	"github.com/jzipfler/htw-ava/server"
	"log"
	"os"
	"os/signal"
	"strconv"
	"syscall"
)

const (
	ERROR_HEADER = "-------------ERROR-------------"
	ERROR_FOOTER = "^^^^^^^^^^^^^ERROR^^^^^^^^^^^^^"
)

var (
	loggingBuffer bytes.Buffer
	logger        *log.Logger
	loggingPrefix string
	logFile       string
	id            int
	ipAddress     string
	port          int
	nodeListFile  string
	isController  bool
	allNodes      map[int]server.NetworkServer
	neighbor      map[int]server.NetworkServer
	thisNode      server.NetworkServer
)

// The ini function is called before the main function is started.
// It is used to do some stuff that should be done before the rest
// of the application starts and on what they may depend on.
func init() {
	flag.StringVar(&nodeListFile, "nodeList", "path/to/nodeList.txt", "A file where nodes are defined as follows: \"ID IP_ADDR:PORT\"")
	flag.IntVar(&id, "id", 1, "The if of the actual starting node.")
	flag.StringVar(&ipAddress, "ipAddress", "127.0.0.1", "The ip address of the actual starting node.")
	flag.IntVar(&port, "port", 15108, "The port of the actual starting node.")
	flag.StringVar(&loggingPrefix, "loggingPrefix", "LOGGING --> ", "This can be used to define which prefix the logger should use to print his messages.")
	flag.StringVar(&logFile, "logFile", "path/to/logfile.txt", "This parameter can be used to print the logging output to the given file.")
	flag.BoolVar(&isController, "isController", false, "Tell the node if he should act as controller or as independent node.")
}

// The main function is used when the programm is called / executed.
func main() {
	if len(os.Args) == 1 {
		flag.Usage()
		os.Exit(0)
	}
	flag.Parse()

	if nodeListFile == "path/to/nodeList.txt" {
		log.Fatalf("The nodeListFile is required.\n%s\n", ERROR_FOOTER)
		os.Exit(1)
	}
	var readFromNodeListError error
	allNodes, readFromNodeListError = filehandler.CollectAllFromNodeListFile(nodeListFile)
	if readFromNodeListError != nil {
		log.Fatalf("%s\n%s\n", readFromNodeListError.Error(), ERROR_FOOTER)
	}

	go signalHandler() // Handle CTRL-C signals
	initializeLogger(loggingPrefix)

	if isController {
		startController()
	} else {
		startIndependentNode()
	}
}

func startIndependentNode() {
	quit := false
	printMessage("Start current instance as independent node.")
	thisNode = allNodes[id]
	printMessage("This node has the folowing settings: ")
	printMessage(thisNode)

	for !quit {
		quit = shouldRestartProgram()
	}
}

func startController() {
	quit := false
	printMessage("Start current instance as controller.")

	for !quit {
		quit = shouldRestartProgram()
	}
}

// Asks the user if he want to exit the program.
// Returns true if and only if the user types y or j. False otherwise.
func shouldRestartProgram() bool {
	var input string
	printMessage("Would you like to exit the program? (y/j/n)")
	fmt.Print("\nInput: ")
	if _, err := fmt.Scanln(&input); err == nil {
		switch input {
		case "y", "j":
			printMessage("Program exists.")
			return true
		case "n":
			printMessage(input)
			return false
		default:
			printMessage("Please only insert y/j for \"YES\" or n for \"NO\".\n" + ERROR_FOOTER)
			printMessage("Assume a \"n\" as input.")
			return false
		}
	} else {
		printMessage("Please only insert y/j for \"YES\" or n for \"NO\".\n" + ERROR_HEADER)
	}
	return false
}

// Creates a new logger which uses a buffer where he collects the messages.
func initializeLogger(preface string) {
	if logFile == "path/to/logfile.txt" {
		logger = log.New(os.Stdout, preface, log.Ldate|log.Ltime|log.Lshortfile)
	} else {
		logger = log.New(&loggingBuffer, preface, log.Ldate|log.Ltime|log.Lshortfile)
	}
}

func printMessage(message interface{}) {
	if logger == nil {
		switch typeValue := message.(type) {
		case fmt.Stringer:
			log.Println(typeValue.String())
		case string:
			log.Println(message)
		case int:
			log.Println(strconv.Itoa(typeValue))
		}
	} else {
		switch typeValue := message.(type) {
		case fmt.Stringer:
			logger.Println(typeValue.String())
		case string:
			logger.Println(message)
		case int:
			logger.Println(strconv.Itoa(typeValue))
		}
	}

}

func printAndClearLoggerContent() {
	if loggingBuffer.Len() != 0 {
		fmt.Println(&loggingBuffer)
		loggingBuffer.Reset()
	}
}

func signalHandler() {
	c := make(chan os.Signal, 1)
	// Signal für CTRL-C abfangen...
	signal.Notify(c, syscall.SIGINT)

	// foreach signal received
	for signal := range c {
		fmt.Println("\nSignal empfangen...")
		fmt.Println(signal.String())
		switch signal {
		case syscall.SIGINT:
			os.Exit(0)
		}
	}
}
<commit_msg>Changed the printMessage method because i do not need to check for other types as stringer and default.<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"github.com/jzipfler/htw-ava/filehandler"
	"github.com/jzipfler/htw-ava/server"
	"log"
	"os"
	"os/signal"
	"syscall"
)

const (
	ERROR_HEADER = "-------------ERROR-------------"
	ERROR_FOOTER = "^^^^^^^^^^^^^ERROR^^^^^^^^^^^^^"
)

var (
	loggingBuffer bytes.Buffer
	logger        *log.Logger
	loggingPrefix string
	logFile       string
	id            int
	ipAddress     string
	port          int
	nodeListFile  string
	isController  bool
	allNodes      map[int]server.NetworkServer
	neighbor      map[int]server.NetworkServer
	thisNode      server.NetworkServer
)

// The ini function is called before the main function is started.
// It is used to do some stuff that should be done before the rest
// of the application starts and on what they may depend on.
func init() {
	flag.StringVar(&nodeListFile, "nodeList", "path/to/nodeList.txt", "A file where nodes are defined as follows: \"ID IP_ADDR:PORT\"")
	flag.IntVar(&id, "id", 1, "The if of the actual starting node.")
	flag.StringVar(&ipAddress, "ipAddress", "127.0.0.1", "The ip address of the actual starting node.")
	flag.IntVar(&port, "port", 15108, "The port of the actual starting node.")
	flag.StringVar(&loggingPrefix, "loggingPrefix", "LOGGING --> ", "This can be used to define which prefix the logger should use to print his messages.")
	flag.StringVar(&logFile, "logFile", "path/to/logfile.txt", "This parameter can be used to print the logging output to the given file.")
	flag.BoolVar(&isController, "isController", false, "Tell the node if he should act as controller or as independent node.")
}

// The main function is used when the programm is called / executed.
func main() {
	if len(os.Args) == 1 {
		flag.Usage()
		os.Exit(0)
	}
	flag.Parse()

	if nodeListFile == "path/to/nodeList.txt" {
		log.Fatalf("The nodeListFile is required.\n%s\n", ERROR_FOOTER)
		os.Exit(1)
	}
	var readFromNodeListError error
	allNodes, readFromNodeListError = filehandler.CollectAllFromNodeListFile(nodeListFile)
	if readFromNodeListError != nil {
		log.Fatalf("%s\n%s\n", readFromNodeListError.Error(), ERROR_FOOTER)
	}

	go signalHandler() // Handle CTRL-C signals
	initializeLogger(loggingPrefix)

	if isController {
		startController()
	} else {
		startIndependentNode()
	}
}

func startIndependentNode() {
	quit := false
	printMessage("Start current instance as independent node.")
	thisNode = allNodes[id]
	printMessage("This node has the folowing settings: ")
	printMessage(thisNode)

	for !quit {
		quit = shouldRestartProgram()
	}
}

func startController() {
	quit := false
	printMessage("Start current instance as controller.")

	for !quit {
		quit = shouldRestartProgram()
	}
}

// Asks the user if he want to exit the program.
// Returns true if and only if the user types y or j. False otherwise.
func shouldRestartProgram() bool {
	var input string
	printMessage("Would you like to exit the program? (y/j/n)")
	fmt.Print("\nInput: ")
	if _, err := fmt.Scanln(&input); err == nil {
		switch input {
		case "y", "j":
			printMessage("Program exists.")
			return true
		case "n":
			printMessage(input)
			return false
		default:
			printMessage("Please only insert y/j for \"YES\" or n for \"NO\".\n" + ERROR_FOOTER)
			printMessage("Assume a \"n\" as input.")
			return false
		}
	} else {
		printMessage("Please only insert y/j for \"YES\" or n for \"NO\".\n" + ERROR_HEADER)
	}
	return false
}

// Creates a new logger which uses a buffer where he collects the messages.
func initializeLogger(preface string) {
	if logFile == "path/to/logfile.txt" {
		logger = log.New(os.Stdout, preface, log.Ldate|log.Ltime|log.Lshortfile)
	} else {
		logger = log.New(&loggingBuffer, preface, log.Ldate|log.Ltime|log.Lshortfile)
	}
}

func printMessage(message interface{}) {
	if logger == nil {
		switch typeValue := message.(type) {
		case fmt.Stringer:
			log.Println(typeValue.String())
		//case string:
		//	log.Println(message)
		//case int:
		//	log.Println(strconv.Itoa(typeValue))
		default:
			log.Println(typeValue)
		}
	} else {
		switch typeValue := message.(type) {
		case fmt.Stringer:
			logger.Println(typeValue.String())
		//case string:
		//	logger.Println(message)
		//case int:
		//	logger.Println(strconv.Itoa(typeValue))
		default:
			logger.Println(typeValue)
		}
	}
}

func printAndClearLoggerContent() {
	if loggingBuffer.Len() != 0 {
		fmt.Println(&loggingBuffer)
		loggingBuffer.Reset()
	}
}

func signalHandler() {
	c := make(chan os.Signal, 1)
	// Signal für CTRL-C abfangen...
	signal.Notify(c, syscall.SIGINT)

	// foreach signal received
	for signal := range c {
		fmt.Println("\nSignal empfangen...")
		fmt.Println(signal.String())
		switch signal {
		case syscall.SIGINT:
			os.Exit(0)
		}
	}
}
<|endoftext|>


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

package config

type Etcd2 struct {
	AdvertiseClientURLs      string `yaml:"advertise_client_urls"         env:"ETCD_ADVERTISE_CLIENT_URLS"`
	CAFile                   string `yaml:"ca_file"                       env:"ETCD_CA_FILE"`
	CertFile                 string `yaml:"cert_file"                     env:"ETCD_CERT_FILE"`
	CorsOrigins              string `yaml:"cors"                          env:"ETCD_CORS"`
	DataDir                  string `yaml:"data_dir"                      env:"ETCD_DATA_DIR"`
	Discovery                string `yaml:"discovery"                     env:"ETCD_DISCOVERY"`
	DiscoveryFallback        string `yaml:"discovery_fallback"            env:"ETCD_DISCOVERY_FALLBACK"`
	DiscoverySRV             string `yaml:"discovery_srv"                 env:"ETCD_DISCOVERY_SRV"`
	DiscoveryProxy           string `yaml:"discovery_proxy"               env:"ETCD_DISCOVERY_PROXY"`
	ElectionTimeout          int    `yaml:"election_timeout"              env:"ETCD_ELECTION_TIMEOUT"`
	HeartbeatInterval        int    `yaml:"heartbeat_interval"            env:"ETCD_HEARTBEAT_INTERVAL"`
	InitialAdvertisePeerURLs string `yaml:"initial_advertise_peer_urls"   env:"ETCD_INITIAL_ADVERTISE_PEER_URLS"`
	InitialCluster           string `yaml:"initial_cluster"               env:"ETCD_INITIAL_CLUSTER"`
	InitialClusterState      string `yaml:"initial_cluster_state"         env:"ETCD_INITIAL_CLUSTER_STATE"`
	InitialClusterToken      string `yaml:"initial_cluster_token"         env:"ETCD_INITIAL_CLUSTER_TOKEN"`
	KeyFile                  string `yaml:"key_file"                      env:"ETCD_KEY_FILE"`
	ListenClientURLs         string `yaml:"listen_client_urls"            env:"ETCD_LISTEN_CLIENT_URLS"`
	ListenPeerURLs           string `yaml:"listen_peer_urls"              env:"ETCD_LISTEN_PEER_URLS"`
	MaxSnapshots             int    `yaml:"max_snapshots"                 env:"ETCD_MAX_SNAPSHOTS"`
	MaxWALs                  int    `yaml:"max_wals"                      env:"ETCD_MAX_WALS"`
	Name                     string `yaml:"name"                          env:"ETCD_NAME"`
	PeerCAFile               string `yaml:"peer_ca_file"                  env:"ETCD_PEER_CA_FILE"`
	PeerCertFile             string `yaml:"peer_cert_file"                env:"ETCD_PEER_CERT_FILE"`
	PeerKeyFile              string `yaml:"peer_key_file"                 env:"ETCD_PEER_KEY_FILE"`
	Proxy                    string `yaml:"proxy"                         env:"ETCD_PROXY" valid:"^(on|off|readonly)$"`
	SnapshotCount            int    `yaml:"snapshot_count"                env:"ETCD_SNAPSHOTCOUNT"`
}
<commit_msg>config: update flags for etcd 2.1<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

type Etcd2 struct {
	AdvertiseClientURLs      string `yaml:"advertise_client_urls"         env:"ETCD_ADVERTISE_CLIENT_URLS"`
	CAFile                   string `yaml:"ca_file"                       env:"ETCD_CA_FILE"                     deprecated:"ca_file obsoleted by trusted_ca_file and client_cert_auth"`
	CertFile                 string `yaml:"cert_file"                     env:"ETCD_CERT_FILE"`
	ClientCertAuth           bool   `yaml:"client_cert_auth"              env:"ETCD_CLIENT_CERT_AUTH"`
	CorsOrigins              string `yaml:"cors"                          env:"ETCD_CORS"`
	DataDir                  string `yaml:"data_dir"                      env:"ETCD_DATA_DIR"`
	Debug                    bool   `yaml:"debug"                         env:"ETCD_DEBUG"`
	Discovery                string `yaml:"discovery"                     env:"ETCD_DISCOVERY"`
	DiscoveryFallback        string `yaml:"discovery_fallback"            env:"ETCD_DISCOVERY_FALLBACK"`
	DiscoverySRV             string `yaml:"discovery_srv"                 env:"ETCD_DISCOVERY_SRV"`
	DiscoveryProxy           string `yaml:"discovery_proxy"               env:"ETCD_DISCOVERY_PROXY"`
	ElectionTimeout          int    `yaml:"election_timeout"              env:"ETCD_ELECTION_TIMEOUT"`
	ForceNewCluster          bool   `yaml:"force_new_cluster"             env:"ETCD_FORCE_NEW_CLUSTER"`
	HeartbeatInterval        int    `yaml:"heartbeat_interval"            env:"ETCD_HEARTBEAT_INTERVAL"`
	InitialAdvertisePeerURLs string `yaml:"initial_advertise_peer_urls"   env:"ETCD_INITIAL_ADVERTISE_PEER_URLS"`
	InitialCluster           string `yaml:"initial_cluster"               env:"ETCD_INITIAL_CLUSTER"`
	InitialClusterState      string `yaml:"initial_cluster_state"         env:"ETCD_INITIAL_CLUSTER_STATE"`
	InitialClusterToken      string `yaml:"initial_cluster_token"         env:"ETCD_INITIAL_CLUSTER_TOKEN"`
	KeyFile                  string `yaml:"key_file"                      env:"ETCD_KEY_FILE"`
	ListenClientURLs         string `yaml:"listen_client_urls"            env:"ETCD_LISTEN_CLIENT_URLS"`
	ListenPeerURLs           string `yaml:"listen_peer_urls"              env:"ETCD_LISTEN_PEER_URLS"`
	LogPackageLevels         string `yaml:"log_package_levels"            env:"ETCD_LOG_PACKAGE_LEVELS"`
	MaxSnapshots             int    `yaml:"max_snapshots"                 env:"ETCD_MAX_SNAPSHOTS"`
	MaxWALs                  int    `yaml:"max_wals"                      env:"ETCD_MAX_WALS"`
	Name                     string `yaml:"name"                          env:"ETCD_NAME"`
	PeerCAFile               string `yaml:"peer_ca_file"                  env:"ETCD_PEER_CA_FILE"                deprecated:"peer_ca_file obsoleted peer_trusted_ca_file and peer_client_cert_auth"`
	PeerCertFile             string `yaml:"peer_cert_file"                env:"ETCD_PEER_CERT_FILE"`
	PeerKeyFile              string `yaml:"peer_key_file"                 env:"ETCD_PEER_KEY_FILE"`
	PeerClientCertAuth       bool   `yaml:"peer_client_cert_auth"         env:"ETCD_PEER_CLIENT_CERT_AUTH"`
	PeerTrustedCAFile        string `yaml:"peer_trusted_ca_file"          env:"ETCD_PEER_TRUSTED_CA_FILE"`
	Proxy                    string `yaml:"proxy"                         env:"ETCD_PROXY"                       valid:"^(on|off|readonly)$"`
	ProxyDialTimeout         int    `yaml:"proxy_dial_timeout"            env:"ETCD_PROXY_DIAL_TIMEOUT"`
	ProxyFailureWait         int    `yaml:"proxy_failure_wait"            env:"ETCD_PROXY_FAILURE_WAIT"`
	ProxyReadTimeout         int    `yaml:"proxy_read_timeout"            env:"ETCD_PROXY_READ_TIMEOUT"`
	ProxyRefreshInterval     int    `yaml:"proxy_refresh_interval"        env:"ETCD_PROXY_REFRESH_INTERVAL"`
	ProxyWriteTimeout        int    `yaml:"proxy_write_timeout"           env:"ETCD_PROXY_WRITE_TIMEOUT"`
	SnapshotCount            int    `yaml:"snapshot_count"                env:"ETCD_SNAPSHOT_COUNT"`
	TrustedCAFile            string `yaml:"trusted_ca_file"               env:"ETCD_TRUSTED_CA_FILE"`
}
<|endoftext|>


<commit_before>package render_test

import (
	"bytes"
	"html/template"
	"os"
	"testing"

	"github.com/chilledoj/render"
)

func TestManager(t *testing.T) {
	tm := render.NewTM()
	if tm == nil {
		t.Fatal("render.NewTM does not return an instance of TemplateManager")
	}
	validTemplate, err := template.New("test").Parse(`<one>{{.Test}}</one>`)
	if err != nil {
		t.Fatalf("Invalid Test template", err)
	}
	err = tm.AddTemplate("test", validTemplate)
	if err != nil {
		t.Errorf("Template can not be added to TemplateManager map", err)
	}
	data := struct {
		Test string
	}{"TEST"}
	b := new(bytes.Buffer)

	err = tm.Render(b, "test", data)
	if err != nil {
		t.Fatalf("Render returned an error ", err, b)
	}
	returnedString := b.String()
	if returnedString != "<one>TEST</one>" {
		t.Fatalf("Invalid returned string (%s)", returnedString)
	}
	err = tm.Render(b, "NOTAVAILABLE", data)
	if err == nil {
		t.Fatal("Invalid template does not result in error")
	}

	invalidData := "TEST"
	err = tm.Render(b, "test", invalidData)
	if err == nil {
		t.Fatal("No error on supplying invalid data")
	}
}

// ExampleTemplateManager
func ExampleTemplateManager() {
	tm := render.NewTM()
	validTemplate, err := template.New("").Parse(`<one>{{.Test}}</one>`)
	if err != nil {
		panic(err)
	}
	err = tm.AddTemplate("one", validTemplate)
	if err != nil {
		panic(err)
	}
	data := struct {
		Test string
	}{"Template One"}

	err = tm.Render(os.Stdout, "one", data)
	if err != nil {
		panic(err)
	}
	// Output: <one>Template One</one>
}
<commit_msg>Remove unnessary new line if in test + added silly benchmark tests.<commit_after>package render_test

import (
	"bytes"
	"html/template"
	"os"
	"sync"
	"testing"

	"github.com/chilledoj/render"
)

func TestManager(t *testing.T) {
	tm := render.NewTM()
	if tm == nil {
		t.Fatal("render.NewTM does not return an instance of TemplateManager")
	}
	validTemplate, err := template.New("test").Parse(`<one>{{.Test}}</one>`)
	if err != nil {
		t.Fatalf("Invalid Test template", err)
	}
	if err = tm.AddTemplate("test", validTemplate); err != nil {
		t.Errorf("Template can not be added to TemplateManager map", err)
	}
	data := struct {
		Test string
	}{"TEST"}
	b := new(bytes.Buffer)

	if err = tm.Render(b, "test", data); err != nil {
		t.Fatalf("Render returned an error ", err, b)
	}
	returnedString := b.String()
	if returnedString != "<one>TEST</one>" {
		t.Fatalf("Invalid returned string (%s)", returnedString)
	}
	if err = tm.Render(b, "NOTAVAILABLE", data); err == nil {
		t.Fatal("Invalid template does not result in error")
	}

	invalidData := "TEST"
	if err = tm.Render(b, "test", invalidData); err == nil {
		t.Fatal("No error on supplying invalid data")
	}
}

// ExampleTemplateManager
func ExampleTemplateManager() {
	tm := render.NewTM()
	validTemplate, err := template.New("").Parse(`<one>{{.Test}}</one>`)
	if err != nil {
		panic(err)
	}
	if err = tm.AddTemplate("one", validTemplate); err != nil {
		panic(err)
	}
	data := struct {
		Test string
	}{"Template One"}

	if err = tm.Render(os.Stdout, "one", data); err != nil {
		panic(err)
	}
	// Output: <one>Template One</one>
}

func BenchmarkSequential(b *testing.B) {
	tm := render.NewTM()
	validTemplate, _ := template.New("").Parse(`<one>{{.Test}}</one>`)
	if err := tm.AddTemplate("test", validTemplate); err != nil {
		b.Errorf("Template can not be added to TemplateManager map", err)
	}
	data := struct {
		Test string
	}{"TEST"}
	buf := new(bytes.Buffer)

	for i := 0; i < b.N; i++ {
		if err := tm.Render(buf, "test", data); err != nil {
			b.Fatalf("Render returned an error ", err, b)
		}
	}
}

func BenchmarkGoRoutine_AllocBuf(b *testing.B) {
	tm := render.NewTM()
	validTemplate, _ := template.New("").Parse(`<one>{{.Test}}</one>`)
	if err := tm.AddTemplate("test", validTemplate); err != nil {
		b.Errorf("Template can not be added to TemplateManager map", err)
	}
	data := struct {
		Test string
	}{"TEST"}

	for i := 0; i < b.N; i++ {
		go func() {
			buf := new(bytes.Buffer)
			if err := tm.Render(buf, "test", data); err != nil {
				b.Fatalf("Render returned an error ", err, b)
			}
		}()
	}
}

func BenchmarkGoRoutine_SingleBuf(b *testing.B) {
	tm := render.NewTM()
	validTemplate, _ := template.New("").Parse(`<one>{{.Test}}</one>`)
	if err := tm.AddTemplate("test", validTemplate); err != nil {
		b.Errorf("Template can not be added to TemplateManager map", err)
	}
	data := struct {
		Test string
	}{"TEST"}

	buf := new(bytes.Buffer)
	var lock sync.Mutex
	for i := 0; i < b.N; i++ {
		go func() {
			lock.Lock()
			if err := tm.Render(buf, "test", data); err != nil {
				b.Fatalf("Render returned an error ", err, b)
			}
			lock.Unlock()
		}()
	}
}
<|endoftext|>


<commit_before>package braintree

import (
	"errors"
	"log"
	"os"
)

// Braintree client
type Braintree struct {
	Logger *log.Logger

	environment string
	merchantID  string
	publicKey   string
	privateKey  string

	addressGW       AddressGW
	clientTokenGW   ClientTokenGW
	customerGW      CustomerGW
	paymentMethodGW PaymentMethodGW
	planGW          PlanGW
	subscriptionGW  SubscriptionGW
	transactionGW   TransactionGW
}

// New returns a braintree client with credentials from env.
//
// BRAINTREE_MERCH_ID, BRAINTREE_PUB_KEY and BRAINTREE_PRIV_KEY
// have to be set.
func New() (*Braintree, error) {

	bt := &Braintree{
		environment: "sandbox",
		merchantID:  os.Getenv("BRAINTREE_MERCH_ID"),
		publicKey:   os.Getenv("BRAINTREE_PUB_KEY"),
		privateKey:  os.Getenv("BRAINTREE_PRIV_KEY"),
	}
	bt.addressGW = AddressGW{bt: bt}
	bt.clientTokenGW = ClientTokenGW{bt: bt}
	bt.customerGW = CustomerGW{bt: bt}
	bt.paymentMethodGW = PaymentMethodGW{bt: bt}
	bt.planGW = PlanGW{bt: bt}
	bt.subscriptionGW = SubscriptionGW{bt: bt}
	bt.transactionGW = TransactionGW{bt: bt}

	if bt.merchantID == "" {
		return nil, errors.New("env BRAINTREE_MERCH_ID not set")
	}
	if bt.publicKey == "" {
		return nil, errors.New("env BRAINTREE_PUB_KEY not set")
	}
	if bt.privateKey == "" {
		return nil, errors.New("env BRAINTREE_PRIV_KEY not set")
	}

	return bt, nil
}

// Address provides the address gateway for this braintree client.
func (bt *Braintree) Address() AddressGW {
	return bt.addressGW
}

// ClientToken provides the client token gateway for this braintree client.
func (bt *Braintree) ClientToken() ClientTokenGW {
	return bt.clientTokenGW
}

// Customer provides the customer gateway for this braintree client.
func (bt *Braintree) Customer() CustomerGW {
	return bt.customerGW
}

// PaymentMethod provides the payment method gateway for this braintree client.
func (bt *Braintree) PaymentMethod() PaymentMethodGW {
	return bt.paymentMethodGW
}

// Plan provides the plan gateway for this braintree client.
func (bt *Braintree) Plan() PlanGW {
	return bt.planGW
}

// Subscription provides the subscription gateway for this braintree client.
func (bt *Braintree) Subscription() SubscriptionGW {
	return bt.subscriptionGW
}

// Transaction provides the transaction gateway for this braintree client.
func (bt *Braintree) Transaction() TransactionGW {
	return bt.transactionGW
}
<commit_msg>change environment variable names to long form<commit_after>package braintree

import (
	"errors"
	"log"
	"os"
)

// Braintree client
type Braintree struct {
	Logger *log.Logger

	environment string
	merchantID  string
	publicKey   string
	privateKey  string

	addressGW       AddressGW
	clientTokenGW   ClientTokenGW
	customerGW      CustomerGW
	paymentMethodGW PaymentMethodGW
	planGW          PlanGW
	subscriptionGW  SubscriptionGW
	transactionGW   TransactionGW
}

// New returns a braintree client with credentials from env.
//
// BRAINTREE_MERCH_ID, BRAINTREE_PUB_KEY and BRAINTREE_PRIV_KEY
// have to be set.
func New() (*Braintree, error) {

	bt := &Braintree{
		environment: "sandbox",
		merchantID:  os.Getenv("BRAINTREE_MERCHANT_ID"),
		publicKey:   os.Getenv("BRAINTREE_PUBLIC_KEY"),
		privateKey:  os.Getenv("BRAINTREE_PRIVATE_KEY"),
	}
	bt.addressGW = AddressGW{bt: bt}
	bt.clientTokenGW = ClientTokenGW{bt: bt}
	bt.customerGW = CustomerGW{bt: bt}
	bt.paymentMethodGW = PaymentMethodGW{bt: bt}
	bt.planGW = PlanGW{bt: bt}
	bt.subscriptionGW = SubscriptionGW{bt: bt}
	bt.transactionGW = TransactionGW{bt: bt}

	if bt.merchantID == "" {
		return nil, errors.New("env BRAINTREE_MERCHANT_ID not set")
	}
	if bt.publicKey == "" {
		return nil, errors.New("env BRAINTREE_PUBLIC_KEY not set")
	}
	if bt.privateKey == "" {
		return nil, errors.New("env BRAINTREE_PRIVATE_KEY not set")
	}

	return bt, nil
}

// Address provides the address gateway for this braintree client.
func (bt *Braintree) Address() AddressGW {
	return bt.addressGW
}

// ClientToken provides the client token gateway for this braintree client.
func (bt *Braintree) ClientToken() ClientTokenGW {
	return bt.clientTokenGW
}

// Customer provides the customer gateway for this braintree client.
func (bt *Braintree) Customer() CustomerGW {
	return bt.customerGW
}

// PaymentMethod provides the payment method gateway for this braintree client.
func (bt *Braintree) PaymentMethod() PaymentMethodGW {
	return bt.paymentMethodGW
}

// Plan provides the plan gateway for this braintree client.
func (bt *Braintree) Plan() PlanGW {
	return bt.planGW
}

// Subscription provides the subscription gateway for this braintree client.
func (bt *Braintree) Subscription() SubscriptionGW {
	return bt.subscriptionGW
}

// Transaction provides the transaction gateway for this braintree client.
func (bt *Braintree) Transaction() TransactionGW {
	return bt.transactionGW
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/howeyc/gopass"
)

func configSetup(c *cli.Context) error {
	log.Print("Starting runtime config initialization")

	// try loading a configuration file
	configFile := os.ExpandEnv(c.GlobalString("config"))
	err := Cfg.populateFromFile(configFile)
	if err != nil {
		if c.GlobalIsSet("config") {
			// missing cli argument file is fatal error
			log.Fatal(err)
		}
		log.Print(fmt.Sprintf("No configuration file found: %s", c.GlobalString("config")))
	}

	// finish setting up runtime configuration
	params := []string{"host", "port", "database", "user", "timeout", "tls"}

	for p := range params {
		// update configuration with cli argument overrides
		if c.GlobalIsSet(params[p]) {
			log.Printf("Setting cli value override for %s", params[p])
			switch params[p] {
			case "host":
				Cfg.Database.Host = c.GlobalString(params[p])
			case "port":
				Cfg.Database.Port = strconv.Itoa(c.GlobalInt(params[p]))
			case "database":
				Cfg.Database.Name = c.GlobalString(params[p])
			case "user":
				Cfg.Database.User = c.GlobalString(params[p])
			case "timeout":
				Cfg.Timeout = strconv.Itoa(c.GlobalInt(params[p]))
			case "tls":
				Cfg.TlsMode = c.GlobalString(params[p])
			}
			continue
		}
		// set default values for unset configuration parameters
		switch params[p] {
		case "host":
			if Cfg.Database.Host == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Database.Host = "localhost"
			}
		case "port":
			if Cfg.Database.Port == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Database.Port = strconv.Itoa(5432)
			}
		case "database":
			if Cfg.Database.Name == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Database.Name = "soma"
			}
		case "user":
			if Cfg.Database.User == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Database.User = "soma_dba"
			}
		case "timeout":
			if Cfg.Timeout == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Timeout = strconv.Itoa(3)
			}
		case "tls":
			if Cfg.TlsMode == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.TlsMode = "verify-full"
			}
		}
	}

	// prompt for password if the cli flag was set
	if c.GlobalBool("password") {
		fmt.Printf("Enter password: ")
		pass := gopass.GetPasswd()
		Cfg.Database.Pass = string(pass)
	}
	// abort if we have no connection password at this point
	if Cfg.Database.Pass == "" {
		log.Fatal("Can not continue without database connection password")
	}
	return nil
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Vendor imports + cleanup<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/howeyc/gopass"
)

func configSetup(c *cli.Context) error {
	log.Print("Starting runtime config initialization")

	// try loading a configuration file
	configFile := os.ExpandEnv(c.GlobalString("config"))
	err := Cfg.populateFromFile(configFile)
	if err != nil {
		if c.GlobalIsSet("config") {
			// missing cli argument file is fatal error
			log.Fatal(err)
		}
		log.Print(fmt.Sprintf("No configuration file found: %s", c.GlobalString("config")))
	}

	// finish setting up runtime configuration
	params := []string{"host", "port", "database", "user", "timeout", "tls"}

	for p := range params {
		// update configuration with cli argument overrides
		if c.GlobalIsSet(params[p]) {
			log.Printf("Setting cli value override for %s", params[p])
			switch params[p] {
			case "host":
				Cfg.Database.Host = c.GlobalString(params[p])
			case "port":
				Cfg.Database.Port = strconv.Itoa(c.GlobalInt(params[p]))
			case "database":
				Cfg.Database.Name = c.GlobalString(params[p])
			case "user":
				Cfg.Database.User = c.GlobalString(params[p])
			case "timeout":
				Cfg.Timeout = strconv.Itoa(c.GlobalInt(params[p]))
			case "tls":
				Cfg.TlsMode = c.GlobalString(params[p])
			}
			continue
		}
		// set default values for unset configuration parameters
		switch params[p] {
		case "host":
			if Cfg.Database.Host == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Database.Host = "localhost"
			}
		case "port":
			if Cfg.Database.Port == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Database.Port = strconv.Itoa(5432)
			}
		case "database":
			if Cfg.Database.Name == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Database.Name = "soma"
			}
		case "user":
			if Cfg.Database.User == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Database.User = "soma_dba"
			}
		case "timeout":
			if Cfg.Timeout == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.Timeout = strconv.Itoa(3)
			}
		case "tls":
			if Cfg.TlsMode == "" {
				log.Printf("Setting default value for %s", params[p])
				Cfg.TlsMode = "verify-full"
			}
		}
	}

	// prompt for password if the cli flag was set
	if c.GlobalBool("password") {
		fmt.Printf("Enter password: ")
		pass, err := gopass.GetPasswd()
		if err != nil {
			return err
		}
		Cfg.Database.Pass = string(pass)
	}
	// abort if we have no connection password at this point
	if Cfg.Database.Pass == "" {
		log.Fatal("Can not continue without database connection password")
	}
	return nil
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package conn

import (
	"bytes"
	"fmt"
	"net"
	"os"
	"strconv"
	"sync"
	"time"

	"github.com/getgauge/common"
	"github.com/getgauge/gauge/gauge_messages"
	"github.com/golang/protobuf/proto"
)

type response struct {
	result chan *gauge_messages.Message
	err    chan error
	timer  *time.Timer
}

func (r *response) stopTimer() {
	if r.timer != nil {
		r.timer.Stop()
	}
}

func (r *response) addTimer(timeout time.Duration, message *gauge_messages.Message) {
	if timeout > 0 {
		r.timer = time.AfterFunc(timeout, func() {
			r.err <- fmt.Errorf("Request timed out for Message with ID => %v and Type => %s", message.GetMessageId(), message.GetMessageType().String())
		})
	}
}

type messages struct {
	m map[int64]response
	sync.Mutex
}

func (m *messages) get(k int64) response {
	m.Lock()
	defer m.Unlock()
	return m.m[k]
}

func (m *messages) put(k int64, res response) {
	m.Lock()
	defer m.Unlock()
	m.m[k] = res
}

func (m *messages) delete(k int64) {
	m.Lock()
	defer m.Unlock()
	delete(m.m, k)
}

var m = &messages{m: make(map[int64]response)}

func writeDataAndGetResponse(conn net.Conn, messageBytes []byte) ([]byte, error) {
	if err := Write(conn, messageBytes); err != nil {
		return nil, err
	}
	return readResponse(conn)
}

func readResponse(conn net.Conn) ([]byte, error) {
	buffer := new(bytes.Buffer)
	data := make([]byte, 8192)
	for {
		n, err := conn.Read(data)
		if err != nil {
			conn.Close()
			return nil, fmt.Errorf("Connection closed [%s] cause: %s", conn.RemoteAddr(), err.Error())
		}

		buffer.Write(data[0:n])
		messageLength, bytesRead := proto.DecodeVarint(buffer.Bytes())
		if messageLength > 0 && messageLength < uint64(buffer.Len()) {
			return buffer.Bytes()[bytesRead : messageLength+uint64(bytesRead)], nil
		}
	}
}

func Write(conn net.Conn, messageBytes []byte) error {
	messageLen := proto.EncodeVarint(uint64(len(messageBytes)))
	data := append(messageLen, messageBytes...)
	_, err := conn.Write(data)
	return err
}

func WriteGaugeMessage(message *gauge_messages.Message, conn net.Conn) error {
	messageID := common.GetUniqueID()
	message.MessageId = messageID

	data, err := proto.Marshal(message)
	if err != nil {
		return err
	}
	return Write(conn, data)
}

func getResponseForGaugeMessage(message *gauge_messages.Message, conn net.Conn, res response, timeout time.Duration) {
	message.MessageId = common.GetUniqueID()
	res.addTimer(timeout, message)
	handle := func(err error) {
		if err != nil {
			res.stopTimer()
			res.err <- err
		}
	}

	data, err := proto.Marshal(message)

	handle(err)
	m.put(message.GetMessageId(), res)

	responseBytes, err := writeDataAndGetResponse(conn, data)
	handle(err)

	responseMessage := &gauge_messages.Message{}
	err = proto.Unmarshal(responseBytes, responseMessage)
	handle(err)

	err = checkUnsupportedResponseMessage(responseMessage)
	handle(err)

	responseRes := m.get(responseMessage.GetMessageId())
	responseRes.stopTimer()
	responseRes.result <- responseMessage
	m.delete(responseMessage.GetMessageId())
}

func checkUnsupportedResponseMessage(message *gauge_messages.Message) error {
	if message.GetMessageType() == gauge_messages.Message_UnsupportedMessageResponse {
		return fmt.Errorf("Unsupported Message response received. Message not supported. %s", message.GetUnsupportedMessageResponse().GetMessage())
	}
	return nil
}

// Sends request to plugin for a message. If response is not received for the given message within the configured timeout, an error is thrown
// To wait indefinitely for the response from the plugin, set timeout value as 0.
func GetResponseForMessageWithTimeout(message *gauge_messages.Message, conn net.Conn, timeout time.Duration) (*gauge_messages.Message, error) {
	res := response{result: make(chan *gauge_messages.Message), err: make(chan error)}
	go getResponseForGaugeMessage(message, conn, res, timeout)
	select {
	case err := <-res.err:
		return nil, err
	case res := <-res.result:
		return res, nil
	}
}

func GetPortFromEnvironmentVariable(portEnvVariable string) (int, error) {
	if port := os.Getenv(portEnvVariable); port != "" {
		gport, err := strconv.Atoi(port)
		if err != nil {
			return 0, fmt.Errorf("%s is not a valid port", port)
		}
		return gport, nil
	}
	return 0, fmt.Errorf("%s Environment variable not set", portEnvVariable)
}

// SendProcessKillMessage sends a KillProcessRequest message through the connection.
func SendProcessKillMessage(connection net.Conn) {
	id := common.GetUniqueID()
	message := &gauge_messages.Message{MessageId: id, MessageType: gauge_messages.Message_KillProcessRequest,
		KillProcessRequest: &gauge_messages.KillProcessRequest{}}

	WriteGaugeMessage(message, connection)
}
<commit_msg>add handling of corner case (#1117)<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package conn

import (
	"bytes"
	"fmt"
	"net"
	"os"
	"strconv"
	"sync"
	"time"

	"github.com/getgauge/common"
	"github.com/getgauge/gauge/gauge_messages"
	"github.com/golang/protobuf/proto"
)

type response struct {
	result chan *gauge_messages.Message
	err    chan error
	timer  *time.Timer
}

func (r *response) stopTimer() {
	if r.timer != nil {
		r.timer.Stop()
	}
}

func (r *response) addTimer(timeout time.Duration, message *gauge_messages.Message) {
	if timeout > 0 {
		r.timer = time.AfterFunc(timeout, func() {
			r.err <- fmt.Errorf("Request timed out for Message with ID => %v and Type => %s", message.GetMessageId(), message.GetMessageType().String())
		})
	}
}

type messages struct {
	m map[int64]response
	sync.Mutex
}

func (m *messages) get(k int64) response {
	m.Lock()
	defer m.Unlock()
	return m.m[k]
}

func (m *messages) put(k int64, res response) {
	m.Lock()
	defer m.Unlock()
	m.m[k] = res
}

func (m *messages) delete(k int64) {
	m.Lock()
	defer m.Unlock()
	delete(m.m, k)
}

var m = &messages{m: make(map[int64]response)}

func writeDataAndGetResponse(conn net.Conn, messageBytes []byte) ([]byte, error) {
	if err := Write(conn, messageBytes); err != nil {
		return nil, err
	}
	return readResponse(conn)
}

func readResponse(conn net.Conn) ([]byte, error) {
	buffer := new(bytes.Buffer)
	data := make([]byte, 8192)
	for {
		n, err := conn.Read(data)
		if err != nil {
			conn.Close()
			return nil, fmt.Errorf("Connection closed [%s] cause: %s", conn.RemoteAddr(), err.Error())
		}

		buffer.Write(data[0:n])
		messageLength, bytesRead := proto.DecodeVarint(buffer.Bytes())
		if (messageLength > 0 && messageLength < uint64(buffer.Len())) && ((messageLength + uint64(bytesRead)) <= uint64(buffer.Len())) {
			return buffer.Bytes()[bytesRead : messageLength+uint64(bytesRead)], nil
		}
	}
}

func Write(conn net.Conn, messageBytes []byte) error {
	messageLen := proto.EncodeVarint(uint64(len(messageBytes)))
	data := append(messageLen, messageBytes...)
	_, err := conn.Write(data)
	return err
}

func WriteGaugeMessage(message *gauge_messages.Message, conn net.Conn) error {
	messageID := common.GetUniqueID()
	message.MessageId = messageID

	data, err := proto.Marshal(message)
	if err != nil {
		return err
	}
	return Write(conn, data)
}

func getResponseForGaugeMessage(message *gauge_messages.Message, conn net.Conn, res response, timeout time.Duration) {
	message.MessageId = common.GetUniqueID()
	res.addTimer(timeout, message)
	handle := func(err error) {
		if err != nil {
			res.stopTimer()
			res.err <- err
		}
	}

	data, err := proto.Marshal(message)

	handle(err)
	m.put(message.GetMessageId(), res)

	responseBytes, err := writeDataAndGetResponse(conn, data)
	handle(err)

	responseMessage := &gauge_messages.Message{}
	err = proto.Unmarshal(responseBytes, responseMessage)
	handle(err)

	err = checkUnsupportedResponseMessage(responseMessage)
	handle(err)

	responseRes := m.get(responseMessage.GetMessageId())
	responseRes.stopTimer()
	responseRes.result <- responseMessage
	m.delete(responseMessage.GetMessageId())
}

func checkUnsupportedResponseMessage(message *gauge_messages.Message) error {
	if message.GetMessageType() == gauge_messages.Message_UnsupportedMessageResponse {
		return fmt.Errorf("Unsupported Message response received. Message not supported. %s", message.GetUnsupportedMessageResponse().GetMessage())
	}
	return nil
}

// Sends request to plugin for a message. If response is not received for the given message within the configured timeout, an error is thrown
// To wait indefinitely for the response from the plugin, set timeout value as 0.
func GetResponseForMessageWithTimeout(message *gauge_messages.Message, conn net.Conn, timeout time.Duration) (*gauge_messages.Message, error) {
	res := response{result: make(chan *gauge_messages.Message), err: make(chan error)}
	go getResponseForGaugeMessage(message, conn, res, timeout)
	select {
	case err := <-res.err:
		return nil, err
	case res := <-res.result:
		return res, nil
	}
}

func GetPortFromEnvironmentVariable(portEnvVariable string) (int, error) {
	if port := os.Getenv(portEnvVariable); port != "" {
		gport, err := strconv.Atoi(port)
		if err != nil {
			return 0, fmt.Errorf("%s is not a valid port", port)
		}
		return gport, nil
	}
	return 0, fmt.Errorf("%s Environment variable not set", portEnvVariable)
}

// SendProcessKillMessage sends a KillProcessRequest message through the connection.
func SendProcessKillMessage(connection net.Conn) {
	id := common.GetUniqueID()
	message := &gauge_messages.Message{MessageId: id, MessageType: gauge_messages.Message_KillProcessRequest,
		KillProcessRequest: &gauge_messages.KillProcessRequest{}}

	WriteGaugeMessage(message, connection)
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"path/filepath"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
)

type KBFSHandler struct {
	*BaseHandler
	libkb.Contextified
}

func NewKBFSHandler(xp rpc.Transporter, g *libkb.GlobalContext) *KBFSHandler {
	return &KBFSHandler{
		BaseHandler:  NewBaseHandler(xp),
		Contextified: libkb.NewContextified(g),
	}
}

func (h *KBFSHandler) FSEvent(_ context.Context, arg keybase1.FSNotification) error {
	h.G().NotifyRouter.HandleFSActivity(arg)

	h.checkConversationRekey(arg)

	return nil
}

func (h *KBFSHandler) FSEditList(ctx context.Context, arg keybase1.FSEditListArg) error {
	h.G().NotifyRouter.HandleFSEditListResponse(ctx, arg)
	return nil
}

func (h *KBFSHandler) FSEditListRequest(ctx context.Context, arg keybase1.FSEditListRequest) error {
	h.G().NotifyRouter.HandleFSEditListRequest(ctx, arg)
	return nil
}

func (h *KBFSHandler) FSSyncStatus(ctx context.Context, arg keybase1.FSSyncStatusArg) (err error) {
	h.G().NotifyRouter.HandleFSSyncStatus(ctx, arg)
	return nil
}

func (h *KBFSHandler) FSSyncEvent(ctx context.Context, arg keybase1.FSPathSyncStatus) (err error) {
	h.G().NotifyRouter.HandleFSSyncEvent(ctx, arg)
	return nil
}

// checkConversationRekey looks for rekey finished notifications and tries to
// find any conversations associated with the rekeyed TLF.  If it finds any,
// it will send ChatThreadsStale notifcations for them.
func (h *KBFSHandler) checkConversationRekey(arg keybase1.FSNotification) {
	if arg.NotificationType != keybase1.FSNotificationType_REKEYING {
		return
	}
	if arg.StatusCode == keybase1.FSStatusCode_FINISH {
		return
	}

	uid := h.G().Env.GetUID()
	if uid.IsNil() {
		h.G().Log.Debug("received rekey finished notification for %s, but have no UID", arg.Filename)
		return
	}

	h.G().Log.Debug("received rekey finished notification for %s, checking for conversations", arg.Filename)

	go h.notifyConversation(uid, arg.Filename, arg.PublicTopLevelFolder)
}

func (h *KBFSHandler) notifyConversation(uid keybase1.UID, filename string, public bool) {
	tlf := filepath.Base(filename)
	convIDs, err := h.conversationIDs(uid, tlf, public)
	if err != nil {
		h.G().Log.Debug("error getting conversation IDs for tlf %q: %s", tlf, err)
		return
	}

	if len(convIDs) == 0 {
		h.G().Log.Debug("no conversations for tlf %s (public: %v)", tlf, public)
		return
	}

	h.G().Log.Debug("sending ChatThreadsStale notification (conversations: %d)", len(convIDs))
	h.G().NotifyRouter.HandleChatThreadsStale(context.Background(), uid, convIDs)
}

func (h *KBFSHandler) conversationIDs(uid keybase1.UID, tlf string, public bool) ([]chat1.ConversationID, error) {
	vis := chat1.TLFVisibility_PRIVATE
	if public {
		vis = chat1.TLFVisibility_PUBLIC
	}

	toptype := chat1.TopicType_CHAT
	query := chat1.GetInboxLocalQuery{
		TlfName:       &tlf,
		TlfVisibility: &vis,
		TopicType:     &toptype,
	}

	ib, _, err := h.G().InboxSource.Read(context.Background(), uid.ToBytes(), nil, true, &query, nil)
	if err != nil {
		return nil, err
	}
	ids := make([]chat1.ConversationID, len(ib.Convs))
	for i, c := range ib.Convs {
		ids[i] = c.Info.Id
	}

	return ids, nil
}
<commit_msg>Fix status code check<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"path/filepath"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
)

type KBFSHandler struct {
	*BaseHandler
	libkb.Contextified
}

func NewKBFSHandler(xp rpc.Transporter, g *libkb.GlobalContext) *KBFSHandler {
	return &KBFSHandler{
		BaseHandler:  NewBaseHandler(xp),
		Contextified: libkb.NewContextified(g),
	}
}

func (h *KBFSHandler) FSEvent(_ context.Context, arg keybase1.FSNotification) error {
	h.G().NotifyRouter.HandleFSActivity(arg)

	h.checkConversationRekey(arg)

	return nil
}

func (h *KBFSHandler) FSEditList(ctx context.Context, arg keybase1.FSEditListArg) error {
	h.G().NotifyRouter.HandleFSEditListResponse(ctx, arg)
	return nil
}

func (h *KBFSHandler) FSEditListRequest(ctx context.Context, arg keybase1.FSEditListRequest) error {
	h.G().NotifyRouter.HandleFSEditListRequest(ctx, arg)
	return nil
}

func (h *KBFSHandler) FSSyncStatus(ctx context.Context, arg keybase1.FSSyncStatusArg) (err error) {
	h.G().NotifyRouter.HandleFSSyncStatus(ctx, arg)
	return nil
}

func (h *KBFSHandler) FSSyncEvent(ctx context.Context, arg keybase1.FSPathSyncStatus) (err error) {
	h.G().NotifyRouter.HandleFSSyncEvent(ctx, arg)
	return nil
}

// checkConversationRekey looks for rekey finished notifications and tries to
// find any conversations associated with the rekeyed TLF.  If it finds any,
// it will send ChatThreadsStale notifcations for them.
func (h *KBFSHandler) checkConversationRekey(arg keybase1.FSNotification) {
	if arg.NotificationType != keybase1.FSNotificationType_REKEYING {
		return
	}
	h.G().Log.Debug("received rekey notification for %s, code: %v", arg.Filename, arg.StatusCode)
	if arg.StatusCode != keybase1.FSStatusCode_FINISH {
		return
	}

	uid := h.G().Env.GetUID()
	if uid.IsNil() {
		h.G().Log.Debug("received rekey finished notification for %s, but have no UID", arg.Filename)
		return
	}

	h.G().Log.Debug("received rekey finished notification for %s, checking for conversations", arg.Filename)

	go h.notifyConversation(uid, arg.Filename, arg.PublicTopLevelFolder)
}

func (h *KBFSHandler) notifyConversation(uid keybase1.UID, filename string, public bool) {
	tlf := filepath.Base(filename)
	convIDs, err := h.conversationIDs(uid, tlf, public)
	if err != nil {
		h.G().Log.Debug("error getting conversation IDs for tlf %q: %s", tlf, err)
		return
	}

	if len(convIDs) == 0 {
		h.G().Log.Debug("no conversations for tlf %s (public: %v)", tlf, public)
		return
	}

	h.G().Log.Debug("sending ChatThreadsStale notification (conversations: %d)", len(convIDs))
	h.G().NotifyRouter.HandleChatThreadsStale(context.Background(), uid, convIDs)
}

func (h *KBFSHandler) conversationIDs(uid keybase1.UID, tlf string, public bool) ([]chat1.ConversationID, error) {
	vis := chat1.TLFVisibility_PRIVATE
	if public {
		vis = chat1.TLFVisibility_PUBLIC
	}

	toptype := chat1.TopicType_CHAT
	query := chat1.GetInboxLocalQuery{
		TlfName:       &tlf,
		TlfVisibility: &vis,
		TopicType:     &toptype,
	}

	ib, _, err := h.G().InboxSource.Read(context.Background(), uid.ToBytes(), nil, true, &query, nil)
	if err != nil {
		return nil, err
	}
	ids := make([]chat1.ConversationID, len(ib.Convs))
	for i, c := range ib.Convs {
		ids[i] = c.Info.Id
	}

	return ids, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"runtime"
)

const (
	VERSION = "0.32"
)

var cmdVersion = &Command{
	Run:       runVersion,
	UsageLine: "version",
	Short:     "print Weed File System version",
	Long:      `Version prints the Weed File System version`,
}

func runVersion(cmd *Command, args []string) bool {
	if len(args) != 0 {
		cmd.Usage()
	}

	fmt.Printf("version %s %s %s\n", VERSION, runtime.GOOS, runtime.GOARCH)
	return true
}
<commit_msg>bump up to 0.33<commit_after>package main

import (
	"fmt"
	"runtime"
)

const (
	VERSION = "0.33"
)

var cmdVersion = &Command{
	Run:       runVersion,
	UsageLine: "version",
	Short:     "print Weed File System version",
	Long:      `Version prints the Weed File System version`,
}

func runVersion(cmd *Command, args []string) bool {
	if len(args) != 0 {
		cmd.Usage()
	}

	fmt.Printf("version %s %s %s\n", VERSION, runtime.GOOS, runtime.GOARCH)
	return true
}
<|endoftext|>


<commit_before>package rat

import (
	"io"
	"os"
	"os/exec"
	"syscall"
)

type ShellCommand interface {
	io.ReadCloser
}

type shellCommand struct {
	cmd *exec.Cmd
	io.Reader
}

func NewShellCommand(c string) (ShellCommand, error) {
	sc := &shellCommand{}

	sc.cmd = exec.Command(os.Getenv("SHELL"), "-c", c)
	sc.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	var (
		stdout io.Reader
		stderr io.Reader
		err    error
	)

	if stdout, err = sc.cmd.StdoutPipe(); err != nil {
		return sc, err
	}

	if stderr, err = sc.cmd.StderrPipe(); err != nil {
		return sc, err
	}

	sc.Reader = io.MultiReader(stdout, stderr)

	return sc, sc.cmd.Start()
}

func (sc *shellCommand) Close() error {
	return syscall.Kill(-sc.cmd.Process.Pid, syscall.SIGTERM)
}
<commit_msg>Have to wait for the process to exit for it to be properly released<commit_after>package rat

import (
	"io"
	"os"
	"os/exec"
	"syscall"
)

type ShellCommand interface {
	io.ReadCloser
}

type shellCommand struct {
	cmd *exec.Cmd
	io.Reader
}

func NewShellCommand(c string) (ShellCommand, error) {
	sc := &shellCommand{}

	sc.cmd = exec.Command(os.Getenv("SHELL"), "-c", c)
	sc.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	var (
		stdout io.Reader
		stderr io.Reader
		err    error
	)

	if stdout, err = sc.cmd.StdoutPipe(); err != nil {
		return sc, err
	}

	if stderr, err = sc.cmd.StderrPipe(); err != nil {
		return sc, err
	}

	sc.Reader = io.MultiReader(stdout, stderr)

	err = sc.cmd.Start()

	return sc, err
}

func (sc *shellCommand) Close() error {
	sc.cmd.Wait()
	return syscall.Kill(-sc.cmd.Process.Pid, syscall.SIGTERM)
}
<|endoftext|>


<commit_before>package log

import (
	"encoding/json"
	"fmt"
	"runtime"
	"strings"
	"time"

	"github.com/sirupsen/logrus"
)

type Logger interface {
	Log(request interface{}, response interface{}, err error, duration time.Duration)
}

type logger struct {
	*logrus.Entry
}

func NewLogger(service string) Logger {
	//	logrus.SetFormatter(new(PrettyFormatter))
	l := logrus.New()
	l.Formatter = new(PrettyFormatter)
	return &logger{
		l.WithFields(logrus.Fields{"service": service}),
	}
}

func (l *logger) Log(request interface{}, response interface{}, err error, duration time.Duration) {
	depth := 2
	pc := make([]uintptr, 2+depth)
	runtime.Callers(2+depth, pc)
	split := strings.Split(runtime.FuncForPC(pc[0]).Name(), ".")
	method := split[len(split)-1]

	entry := l.WithFields(
		logrus.Fields{
			"method":   method,
			"request":  request,
			"response": response,
			"error":    err,
			"duration": duration,
		},
	)

	if err != nil {
		entry.Error(err)
	} else {
		entry.Info()
	}
}

type PrettyFormatter struct {
}

func (f *PrettyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	serialized := []byte(
		fmt.Sprintf(
			"%v %v ",
			entry.Time.Format(logrus.DefaultTimestampFormat),
			strings.ToUpper(entry.Level.String()),
		),
	)
	if entry.Data["service"] != nil {
		serialized = append(serialized, []byte(fmt.Sprintf(" %v.%v ", entry.Data["service"], entry.Data["method"]))...)
	}
	if len(entry.Data) > 2 {
		delete(entry.Data, "service")
		delete(entry.Data, "method")
		if entry.Data["duration"] != nil {
			entry.Data["duration"] = entry.Data["duration"].(time.Duration).Seconds()
		}
		data, err := json.Marshal(entry.Data)
		if err != nil {
			return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
		}
		serialized = append(serialized, []byte(string(data))...)
		serialized = append(serialized, ' ')
	}

	serialized = append(serialized, []byte(entry.Message)...)
	serialized = append(serialized, '\n')
	return serialized, nil
}
<commit_msg>Finalize the method name fetching for logging<commit_after>package log

import (
	"encoding/json"
	"fmt"
	"runtime"
	"strings"
	"time"

	"github.com/sirupsen/logrus"
)

type Logger interface {
	Log(request interface{}, response interface{}, err error, duration time.Duration)
}

type logger struct {
	*logrus.Entry
}

func NewLogger(service string) Logger {
	//	logrus.SetFormatter(new(PrettyFormatter))
	l := logrus.New()
	l.Formatter = new(PrettyFormatter)
	return &logger{
		l.WithFields(logrus.Fields{"service": service}),
	}
}

func (l *logger) Log(request interface{}, response interface{}, err error, duration time.Duration) {
	depth := 1
	pc := make([]uintptr, 2+depth)
	runtime.Callers(2+depth, pc)
	split := strings.Split(runtime.FuncForPC(pc[0]).Name(), ".")
	method := split[len(split)-1]

	entry := l.WithFields(
		logrus.Fields{
			"method":   method,
			"request":  request,
			"response": response,
			"error":    err,
			"duration": duration,
		},
	)

	if err != nil {
		entry.Error(err)
	} else {
		entry.Info()
	}
}

type PrettyFormatter struct {
}

func (f *PrettyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	serialized := []byte(
		fmt.Sprintf(
			"%v %v ",
			entry.Time.Format(logrus.DefaultTimestampFormat),
			strings.ToUpper(entry.Level.String()),
		),
	)
	if entry.Data["service"] != nil {
		serialized = append(serialized, []byte(fmt.Sprintf("%v.%v ", entry.Data["service"], entry.Data["method"]))...)
	}
	if len(entry.Data) > 2 {
		delete(entry.Data, "service")
		delete(entry.Data, "method")
		if entry.Data["duration"] != nil {
			entry.Data["duration"] = entry.Data["duration"].(time.Duration).Seconds()
		}
		data, err := json.Marshal(entry.Data)
		if err != nil {
			return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
		}
		serialized = append(serialized, []byte(string(data))...)
		serialized = append(serialized, ' ')
	}

	serialized = append(serialized, []byte(entry.Message)...)
	serialized = append(serialized, '\n')
	return serialized, nil
}
<|endoftext|>