<commit_before>package vault

import (
	"fmt"
	"github.com/armon/go-radix"
	"github.com/hashicorp/vault/logical"
)

// ACL is used to wrap a set of policies to provide
// an efficient interface for access control.
type ACL struct {
	// exactRules contains the path policies that are exact
	exactRules *radix.Tree

	// globRules contains the path policies that glob
	globRules *radix.Tree

	// root is enabled if the "root" named policy is present.
	root bool
}

// New is used to construct a policy based ACL from a set of policies.
func NewACL(policies []*Policy) (*ACL, error) {
	// Initialize
	a := &ACL{
		exactRules: radix.New(),
		globRules:  radix.New(),
		root:       false,
	}

	// Inject each policy
	for _, policy := range policies {
		// Ignore a nil policy object
		if policy == nil {
			continue
		}
		// Check if this is root
		if policy.Name == "root" {
			a.root = true
		}
		for _, pc := range policy.Paths {
			// Check which tree to use
			tree := a.exactRules
			if pc.Glob {
				tree = a.globRules
			}

			// Check for an existing policy
			raw, ok := tree.Get(pc.Prefix)
			if !ok {
				tree.Insert(pc.Prefix, pc.Permissions)
				continue
			}

			// these are the ones already in the tree
			permissions := raw.(*Permissions)
			existing := permissions.CapabilitiesBitmap

			switch {
			case existing&DenyCapabilityInt > 0:
				// If we are explicitly denied in the existing capability set,
				// don't save anything else

			case pc.Permissions.CapabilitiesBitmap&DenyCapabilityInt > 0:
				// If this new policy explicitly denies, only save the deny value
				pc.Permissions.CapabilitiesBitmap = DenyCapabilityInt
				tree.Insert(pc.Prefix, pc.Permissions)

			default:
				// Insert the capabilities in this new policy into the existing
				// value
				pc.Permissions.CapabilitiesBitmap = existing | pc.Permissions.CapabilitiesBitmap
				tree.Insert(pc.Prefix, pc.Permissions)
			}

			// look for a * in allowed parameters for the node already in the tree
			if _, ok := permissions.AllowedParameters["*"]; ok {
				pc.Permissions.AllowedParameters = make(map[string]struct{})
				pc.Permissions.AllowedParameters["*"] = nil
				goto CHECK_DENIED
			}

			// look for a * in allowed parameters for the path capability we are merging
			if _, ok := pc.Permissions.AllowedParameters["*"]; ok {
				pc.Permissions.AllowedParameters = make(map[string]struct{})
				pc.Permissions.AllowedParameters["*"] = nil
				goto CHECK_DENIED
			}

			// Merge allowed parameters
			for key, _ := range permissions.AllowedParameters {
				// Add new parameter
				if _, ok := pc.Permissions.AllowedParameters[key]; !ok {
					pc.Permissions.AllowedParameters[key] = permissions.AllowedParameters[key]
					continue
				}
			}

		CHECK_DENIED:

			// look for a * in denied parameters for the node already in the tree
			if _, ok := permissions.DeniedParameters["*"]; ok {
				pc.Permissions.DeniedParameters = make(map[string]struct{})
				pc.Permissions.DeniedParameters["*"] = nil
				goto INSERT
			}

			// look for a * in denied parameters for the path capability we are merging
			if _, ok := pc.Permissions.DeniedParameters["*"]; ok {
				pc.Permissions.DeniedParameters = make(map[string]struct{})
				pc.Permissions.DeniedParameters["*"] = nil
				goto INSERT
			}

			// Merge denied parameters
			for key, _ := range permissions.DeniedParameters {
				// Add new parameter
				if _, ok := pc.Permissions.DeniedParameters[key]; !ok {
					pc.Permissions.DeniedParameters[key] = permissions.DeniedParameters[key]
					continue
				}

			}

		INSERT:

			tree.Insert(pc.Prefix, pc.Permissions)

		}
	}
	return a, nil
}

func (a *ACL) Capabilities(path string) (pathCapabilities []string) {
	// Fast-path root
	if a.root {
		return []string{RootCapability}
	}

	// Find an exact matching rule, look for glob if no match
	var capabilities uint32
	raw, ok := a.exactRules.Get(path)

	if ok {
		perm := raw.(*Permissions)
		capabilities = perm.CapabilitiesBitmap
		goto CHECK
	}

	// Find a glob rule, default deny if no match
	_, raw, ok = a.globRules.LongestPrefix(path)
	if !ok {
		return []string{DenyCapability}
	} else {
		perm := raw.(*Permissions)
		capabilities = perm.CapabilitiesBitmap
	}

CHECK:
	if capabilities&SudoCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, SudoCapability)
	}
	if capabilities&ReadCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, ReadCapability)
	}
	if capabilities&ListCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, ListCapability)
	}
	if capabilities&UpdateCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, UpdateCapability)
	}
	if capabilities&DeleteCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, DeleteCapability)
	}
	if capabilities&CreateCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, CreateCapability)
	}

	// If "deny" is explicitly set or if the path has no capabilities at all,
	// set the path capabilities to "deny"
	if capabilities&DenyCapabilityInt > 0 || len(pathCapabilities) == 0 {
		pathCapabilities = []string{DenyCapability}
	}
	return
}

// AllowOperation is used to check if the given operation is permitted. The
// first bool indicates if an op is allowed, the second whether sudo priviliges
// exist for that op and path.
func (a *ACL) AllowOperation(req *logical.Request) (allowed bool, sudo bool) {
	// Fast-path root
	if a.root {
		return true, true
	}
	op := req.Operation
	path := req.Path

	// Help is always allowed
	if op == logical.HelpOperation {
		return true, false
	}

	var permissions *Permissions

	// Find an exact matching rule, look for glob if no match
	var capabilities uint32
	raw, ok := a.exactRules.Get(path)
	if ok {
		permissions = raw.(*Permissions)
		capabilities = permissions.CapabilitiesBitmap
		goto CHECK
	}

	// Find a glob rule, default deny if no match
	_, raw, ok = a.globRules.LongestPrefix(path)
	if !ok {
		return false, false
	} else {
		permissions = raw.(*Permissions)
		capabilities = permissions.CapabilitiesBitmap
	}

CHECK:
	// Check if the minimum permissions are met
	// If "deny" has been explicitly set, only deny will be in the map, so we
	// only need to check for the existence of other values
	sudo = capabilities&SudoCapabilityInt > 0
	operationAllowed := false
	switch op {
	case logical.ReadOperation:
		operationAllowed = capabilities&ReadCapabilityInt > 0
	case logical.ListOperation:
		operationAllowed = capabilities&ListCapabilityInt > 0
	case logical.UpdateOperation:
		operationAllowed = capabilities&UpdateCapabilityInt > 0
	case logical.DeleteOperation:
		operationAllowed = capabilities&DeleteCapabilityInt > 0
	case logical.CreateOperation:
		operationAllowed = capabilities&CreateCapabilityInt > 0

	// These three re-use UpdateCapabilityInt since that's the most appropriate capability/operation mapping
	case logical.RevokeOperation, logical.RenewOperation, logical.RollbackOperation:
		operationAllowed = capabilities&UpdateCapabilityInt > 0

	default:
		return false, false
	}

	if !operationAllowed {
		return false, sudo
	}

	// Only check parameter permissions for operations that can modify parameters.
	if op == logical.UpdateOperation || op == logical.DeleteOperation || op == logical.CreateOperation {
		// Check if all parameters have been denied
		if _, ok := permissions.DeniedParameters["*"]; ok {
			return false, sudo
		}

		for parameter, _ := range req.Data {
			// Check if parameter has explictly denied
			if _, ok := permissions.DeniedParameters[parameter]; ok {
				return false, sudo
			}
			// Specfic parameters have been allowed
			if len(permissions.AllowedParameters) > 0 {
				// Requested parameter is not in allowed list
				if _, ok := permissions.AllowedParameters[parameter]; !ok {
					return false, sudo
				}
			}
		}
		return true, sudo
	}

	return operationAllowed, sudo
}
<commit_msg>Had to change what a wildcard value in a parameter mapped to, from a nil value to an empty struct<commit_after>package vault

import (
	"github.com/armon/go-radix"
	"github.com/hashicorp/vault/logical"
)

// ACL is used to wrap a set of policies to provide
// an efficient interface for access control.
type ACL struct {
	// exactRules contains the path policies that are exact
	exactRules *radix.Tree

	// globRules contains the path policies that glob
	globRules *radix.Tree

	// root is enabled if the "root" named policy is present.
	root bool
}

// New is used to construct a policy based ACL from a set of policies.
func NewACL(policies []*Policy) (*ACL, error) {
	// Initialize
	a := &ACL{
		exactRules: radix.New(),
		globRules:  radix.New(),
		root:       false,
	}

	// Inject each policy
	for _, policy := range policies {
		// Ignore a nil policy object
		if policy == nil {
			continue
		}
		// Check if this is root
		if policy.Name == "root" {
			a.root = true
		}
		for _, pc := range policy.Paths {
			// Check which tree to use
			tree := a.exactRules
			if pc.Glob {
				tree = a.globRules
			}

			// Check for an existing policy
			raw, ok := tree.Get(pc.Prefix)
			if !ok {
				tree.Insert(pc.Prefix, pc.Permissions)
				continue
			}

			// these are the ones already in the tree
			permissions := raw.(*Permissions)
			existing := permissions.CapabilitiesBitmap

			switch {
			case existing&DenyCapabilityInt > 0:
				// If we are explicitly denied in the existing capability set,
				// don't save anything else

			case pc.Permissions.CapabilitiesBitmap&DenyCapabilityInt > 0:
				// If this new policy explicitly denies, only save the deny value
				pc.Permissions.CapabilitiesBitmap = DenyCapabilityInt
				tree.Insert(pc.Prefix, pc.Permissions)

			default:
				// Insert the capabilities in this new policy into the existing
				// value
				pc.Permissions.CapabilitiesBitmap = existing | pc.Permissions.CapabilitiesBitmap
				tree.Insert(pc.Prefix, pc.Permissions)
			}

			// look for a * in allowed parameters for the node already in the tree
			if _, ok := permissions.AllowedParameters["*"]; ok {
				pc.Permissions.AllowedParameters = make(map[string]struct{})
				pc.Permissions.AllowedParameters["*"] = struct{}{}
				goto CHECK_DENIED
			}

			// look for a * in allowed parameters for the path capability we are merging
			if _, ok := pc.Permissions.AllowedParameters["*"]; ok {
				pc.Permissions.AllowedParameters = make(map[string]struct{})
				pc.Permissions.AllowedParameters["*"] = struct{}{}
				goto CHECK_DENIED
			}

			// Merge allowed parameters
			for key, _ := range permissions.AllowedParameters {
				// Add new parameter
				if _, ok := pc.Permissions.AllowedParameters[key]; !ok {
					pc.Permissions.AllowedParameters[key] = permissions.AllowedParameters[key]
					continue
				}
			}

		CHECK_DENIED:

			// look for a * in denied parameters for the node already in the tree
			if _, ok := permissions.DeniedParameters["*"]; ok {
				pc.Permissions.DeniedParameters = make(map[string]struct{})
				pc.Permissions.DeniedParameters["*"] = struct{}{}
				goto INSERT
			}

			// look for a * in denied parameters for the path capability we are merging
			if _, ok := pc.Permissions.DeniedParameters["*"]; ok {
				pc.Permissions.DeniedParameters = make(map[string]struct{})
				pc.Permissions.DeniedParameters["*"] = struct{}{}
				goto INSERT
			}

			// Merge denied parameters
			for key, _ := range permissions.DeniedParameters {
				// Add new parameter
				if _, ok := pc.Permissions.DeniedParameters[key]; !ok {
					pc.Permissions.DeniedParameters[key] = permissions.DeniedParameters[key]
					continue
				}

			}

		INSERT:

			tree.Insert(pc.Prefix, pc.Permissions)

		}
	}
	return a, nil
}

func (a *ACL) Capabilities(path string) (pathCapabilities []string) {
	// Fast-path root
	if a.root {
		return []string{RootCapability}
	}

	// Find an exact matching rule, look for glob if no match
	var capabilities uint32
	raw, ok := a.exactRules.Get(path)

	if ok {
		perm := raw.(*Permissions)
		capabilities = perm.CapabilitiesBitmap
		goto CHECK
	}

	// Find a glob rule, default deny if no match
	_, raw, ok = a.globRules.LongestPrefix(path)
	if !ok {
		return []string{DenyCapability}
	} else {
		perm := raw.(*Permissions)
		capabilities = perm.CapabilitiesBitmap
	}

CHECK:
	if capabilities&SudoCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, SudoCapability)
	}
	if capabilities&ReadCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, ReadCapability)
	}
	if capabilities&ListCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, ListCapability)
	}
	if capabilities&UpdateCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, UpdateCapability)
	}
	if capabilities&DeleteCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, DeleteCapability)
	}
	if capabilities&CreateCapabilityInt > 0 {
		pathCapabilities = append(pathCapabilities, CreateCapability)
	}

	// If "deny" is explicitly set or if the path has no capabilities at all,
	// set the path capabilities to "deny"
	if capabilities&DenyCapabilityInt > 0 || len(pathCapabilities) == 0 {
		pathCapabilities = []string{DenyCapability}
	}
	return
}

// AllowOperation is used to check if the given operation is permitted. The
// first bool indicates if an op is allowed, the second whether sudo priviliges
// exist for that op and path.
func (a *ACL) AllowOperation(req *logical.Request) (allowed bool, sudo bool) {
	// Fast-path root
	if a.root {
		return true, true
	}
	op := req.Operation
	path := req.Path

	// Help is always allowed
	if op == logical.HelpOperation {
		return true, false
	}

	var permissions *Permissions

	// Find an exact matching rule, look for glob if no match
	var capabilities uint32
	raw, ok := a.exactRules.Get(path)
	if ok {
		permissions = raw.(*Permissions)
		capabilities = permissions.CapabilitiesBitmap
		goto CHECK
	}

	// Find a glob rule, default deny if no match
	_, raw, ok = a.globRules.LongestPrefix(path)
	if !ok {
		return false, false
	} else {
		permissions = raw.(*Permissions)
		capabilities = permissions.CapabilitiesBitmap
	}

CHECK:
	// Check if the minimum permissions are met
	// If "deny" has been explicitly set, only deny will be in the map, so we
	// only need to check for the existence of other values
	sudo = capabilities&SudoCapabilityInt > 0
	operationAllowed := false
	switch op {
	case logical.ReadOperation:
		operationAllowed = capabilities&ReadCapabilityInt > 0
	case logical.ListOperation:
		operationAllowed = capabilities&ListCapabilityInt > 0
	case logical.UpdateOperation:
		operationAllowed = capabilities&UpdateCapabilityInt > 0
	case logical.DeleteOperation:
		operationAllowed = capabilities&DeleteCapabilityInt > 0
	case logical.CreateOperation:
		operationAllowed = capabilities&CreateCapabilityInt > 0

	// These three re-use UpdateCapabilityInt since that's the most appropriate capability/operation mapping
	case logical.RevokeOperation, logical.RenewOperation, logical.RollbackOperation:
		operationAllowed = capabilities&UpdateCapabilityInt > 0

	default:
		return false, false
	}

	if !operationAllowed {
		return false, sudo
	}

	// Only check parameter permissions for operations that can modify parameters.
	if op == logical.UpdateOperation || op == logical.DeleteOperation || op == logical.CreateOperation {
		// Check if all parameters have been denied
		if _, ok := permissions.DeniedParameters["*"]; ok {
			return false, sudo
		}

		for parameter, _ := range req.Data {
			// Check if parameter has explictly denied
			if _, ok := permissions.DeniedParameters[parameter]; ok {
				return false, sudo
			}
			// Specfic parameters have been allowed
			if len(permissions.AllowedParameters) > 0 {
				// Requested parameter is not in allowed list
				if _, ok := permissions.AllowedParameters[parameter]; !ok {
					return false, sudo
				}
			}
		}
		return true, sudo
	}

	return operationAllowed, sudo
}
<|endoftext|>


<commit_before>package plugins

import (
	"bytes"
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"time"

	"cloud.google.com/go/translate"
	"github.com/Jeffail/gabs"
	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/bwmarrin/discordgo"
	"golang.org/x/text/language"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/option"
)

type Translator struct {
	ctx    context.Context
	client *translate.Client
}

const (
	googleTranslateHexColor = "#4285f4"
	naverTranslateEndpoint  = "https://papago.naver.com/apis/n2mt/translate"
)

func (t *Translator) Commands() []string {
	return []string{
		"translator",
		"translate",
		"t",
	}
}

func (t *Translator) Init(session *discordgo.Session) {
	t.ctx = context.Background()

	client, err := translate.NewClient(
		t.ctx,
		option.WithAPIKey(helpers.GetConfig().Path("google.api_key").Data().(string)),
	)
	helpers.Relax(err)
	t.client = client
}

func (t *Translator) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) {
	if !helpers.ModuleIsAllowed(msg.ChannelID, msg.ID, msg.Author.ID, helpers.ModulePermTranslator) {
		return
	}

	session.ChannelTyping(msg.ChannelID)
	// Assumed format: <lang_in> <lang_out> <text>
	parts := strings.Fields(content)

	if len(parts) < 3 {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.translator.check_format"))
		return
	}

	source, err := language.Parse(parts[0])
	if err != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.translator.unknown_lang_specific", parts[0]))
		return
	}

	target, err := language.Parse(parts[1])
	if err != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.translator.unknown_lang_specific", parts[1]))
		return
	}

	translations, err := t.client.Translate(
		t.ctx,
		parts[2:],
		target,
		&translate.Options{
			Format: translate.Text,
			Source: source,
		},
	)

	if err != nil {
		if err, ok := err.(*googleapi.Error); ok {
			if err.Code == 400 {
				helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.translator.unknown_lang"))
				return
			}
		}
		//helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.translator.error"))
		helpers.SendError(msg, err)
		return
	}

	m := ""
	for _, piece := range translations {
		m += piece.Text + " "
	}

	translatedNaverResult := ""
	if (strings.ToLower(source.String()) == "en" || strings.ToLower(source.String()) == "ko") && (strings.ToLower(target.String()) == "en" || strings.ToLower(target.String()) == "ko") {
		fullInputText := ""
		for _, partInputText := range parts[2:] {
			fullInputText += " " + partInputText
		}
		fullInputText = strings.TrimSpace(strings.Replace(fullInputText, "\n", " ", -1))
		targetInput := ""
		var targetInputs []string
		for _, word := range strings.Fields(fullInputText) {
			if len(targetInput)+len(word)+1 < 200 {
				targetInput += " " + word
			} else {
				targetInputs = append(targetInputs, strings.TrimSpace(targetInput))
				targetInput = ""
				if len(word) < 200 {
					targetInput = word
				}
			}
		}
		targetInputs = append(targetInputs, strings.TrimSpace(targetInput))

		for _, partToTranslaste := range targetInputs {
			data := url.Values{}
			decoded, err := base64.StdEncoding.DecodeString("rlWxnJA0VwczLJkmZSwiZGljdERpc3BsYXkiOjUsInNvdXJjZSI6ImVuIiwidGFyZ2V0Ijoia28iLCJ0ZXh0IjoiQUFBQUFBQUFBQSJ9")
			helpers.Relax(err)
			jsonData := string(decoded)
			jsonData = strings.Replace(jsonData, "\"dictDisplay\":5", "\"dictDisplay\":0", -1)
			jsonData = strings.Replace(jsonData, "\"source\":\"en\"", fmt.Sprintf("\"source\":\"%s\"", source.String()), -1)
			jsonData = strings.Replace(jsonData, "\"target\":\"ko\"", fmt.Sprintf("\"target\":\"%s\"", target.String()), -1)
			jsonData = strings.Replace(jsonData, "\"text\":\"AAAAAAAAAA\"", fmt.Sprintf("\"text\":\"%s\"", strings.Replace(partToTranslaste, "\"", "'", -1)), -1)
			data.Set("data", base64.StdEncoding.EncodeToString([]byte(jsonData)))

			client := &http.Client{
				Timeout: time.Duration(10 * time.Second),
			}
			request, err := http.NewRequest("POST", naverTranslateEndpoint, bytes.NewBufferString(data.Encode()))
			if err != nil {
				helpers.SendError(msg, err)
				continue
			}
			request.Header.Set("User-Agent", helpers.DEFAULT_UA)
			request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			response, err := client.Do(request)
			if err != nil {
				helpers.SendError(msg, err)
				continue
			}
			if response.StatusCode == 200 {
				defer response.Body.Close()

				resultParsed, err := gabs.ParseJSONBuffer(response.Body)
				if err != nil {
					helpers.SendError(msg, err)
					continue
				}
				translatedNaverResult += " " + resultParsed.Path("translatedText").Data().(string)
			} else {
				helpers.SendError(msg, errors.New(fmt.Sprintf("Unexpected status code from Naver API: %d", response.StatusCode)))
			}
		}
	}

	translateEmbed := &discordgo.MessageEmbed{
		Title:       helpers.GetTextF("plugins.translator.translation-embed-title", strings.ToUpper(source.String()), strings.ToUpper(target.String())),
		Footer:      &discordgo.MessageEmbedFooter{Text: helpers.GetText("plugins.translator.embed-footer")},
		Description: m,
		Color:       helpers.GetDiscordColorFromHex(googleTranslateHexColor),
		Fields:      []*discordgo.MessageEmbedField{},
	}
	if translatedNaverResult != "" {
		translateEmbed.Fields = append(translateEmbed.Fields, &discordgo.MessageEmbedField{
			Name:  helpers.GetText("plugins.translator.embed-title-alternative-naver"),
			Value: translatedNaverResult})
		translateEmbed.Footer = &discordgo.MessageEmbedFooter{Text: helpers.GetText("plugins.translator.embed-footer-plus-naver")}
	}

	_, err = helpers.SendEmbed(msg.ChannelID, translateEmbed)
	helpers.RelaxEmbed(err, msg.ChannelID, msg.ID)
}
<commit_msg>[translator] improves google translate translation quality<commit_after>package plugins

import (
	"bytes"
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"time"

	"cloud.google.com/go/translate"
	"github.com/Jeffail/gabs"
	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/bwmarrin/discordgo"
	"golang.org/x/text/language"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/option"
)

type Translator struct {
	ctx    context.Context
	client *translate.Client
}

const (
	googleTranslateHexColor = "#4285f4"
	naverTranslateEndpoint  = "https://papago.naver.com/apis/n2mt/translate"
)

func (t *Translator) Commands() []string {
	return []string{
		"translator",
		"translate",
		"t",
	}
}

func (t *Translator) Init(session *discordgo.Session) {
	t.ctx = context.Background()

	client, err := translate.NewClient(
		t.ctx,
		option.WithAPIKey(helpers.GetConfig().Path("google.api_key").Data().(string)),
	)
	helpers.Relax(err)
	t.client = client
}

func (t *Translator) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) {
	if !helpers.ModuleIsAllowed(msg.ChannelID, msg.ID, msg.Author.ID, helpers.ModulePermTranslator) {
		return
	}

	session.ChannelTyping(msg.ChannelID)
	// Assumed format: <lang_in> <lang_out> <text>
	parts := strings.Fields(content)

	if len(parts) < 3 {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.translator.check_format"))
		return
	}

	source, err := language.Parse(parts[0])
	if err != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.translator.unknown_lang_specific", parts[0]))
		return
	}

	target, err := language.Parse(parts[1])
	if err != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.translator.unknown_lang_specific", parts[1]))
		return
	}

	translations, err := t.client.Translate(
		t.ctx,
		parts[2:],
		target,
		&translate.Options{
			Format: translate.Text,
			Source: source,
			Model:  "nmt",
		},
	)

	if err != nil {
		if err, ok := err.(*googleapi.Error); ok {
			if err.Code == 400 {
				helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.translator.unknown_lang"))
				return
			}
		}
		//helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.translator.error"))
		helpers.SendError(msg, err)
		return
	}

	m := ""
	for _, piece := range translations {
		m += piece.Text + " "
	}

	translatedNaverResult := ""
	if (strings.ToLower(source.String()) == "en" || strings.ToLower(source.String()) == "ko") && (strings.ToLower(target.String()) == "en" || strings.ToLower(target.String()) == "ko") {
		fullInputText := ""
		for _, partInputText := range parts[2:] {
			fullInputText += " " + partInputText
		}
		fullInputText = strings.TrimSpace(strings.Replace(fullInputText, "\n", " ", -1))
		targetInput := ""
		var targetInputs []string
		for _, word := range strings.Fields(fullInputText) {
			if len(targetInput)+len(word)+1 < 200 {
				targetInput += " " + word
			} else {
				targetInputs = append(targetInputs, strings.TrimSpace(targetInput))
				targetInput = ""
				if len(word) < 200 {
					targetInput = word
				}
			}
		}
		targetInputs = append(targetInputs, strings.TrimSpace(targetInput))

		for _, partToTranslaste := range targetInputs {
			data := url.Values{}
			decoded, err := base64.StdEncoding.DecodeString("rlWxnJA0VwczLJkmZSwiZGljdERpc3BsYXkiOjUsInNvdXJjZSI6ImVuIiwidGFyZ2V0Ijoia28iLCJ0ZXh0IjoiQUFBQUFBQUFBQSJ9")
			helpers.Relax(err)
			jsonData := string(decoded)
			jsonData = strings.Replace(jsonData, "\"dictDisplay\":5", "\"dictDisplay\":0", -1)
			jsonData = strings.Replace(jsonData, "\"source\":\"en\"", fmt.Sprintf("\"source\":\"%s\"", source.String()), -1)
			jsonData = strings.Replace(jsonData, "\"target\":\"ko\"", fmt.Sprintf("\"target\":\"%s\"", target.String()), -1)
			jsonData = strings.Replace(jsonData, "\"text\":\"AAAAAAAAAA\"", fmt.Sprintf("\"text\":\"%s\"", strings.Replace(partToTranslaste, "\"", "'", -1)), -1)
			data.Set("data", base64.StdEncoding.EncodeToString([]byte(jsonData)))

			client := &http.Client{
				Timeout: time.Duration(10 * time.Second),
			}
			request, err := http.NewRequest("POST", naverTranslateEndpoint, bytes.NewBufferString(data.Encode()))
			if err != nil {
				helpers.SendError(msg, err)
				continue
			}
			request.Header.Set("User-Agent", helpers.DEFAULT_UA)
			request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			response, err := client.Do(request)
			if err != nil {
				helpers.SendError(msg, err)
				continue
			}
			if response.StatusCode == 200 {
				defer response.Body.Close()

				resultParsed, err := gabs.ParseJSONBuffer(response.Body)
				if err != nil {
					helpers.SendError(msg, err)
					continue
				}
				translatedNaverResult += " " + resultParsed.Path("translatedText").Data().(string)
			} else {
				helpers.SendError(msg, errors.New(fmt.Sprintf("Unexpected status code from Naver API: %d", response.StatusCode)))
			}
		}
	}

	translateEmbed := &discordgo.MessageEmbed{
		Title:       helpers.GetTextF("plugins.translator.translation-embed-title", strings.ToUpper(source.String()), strings.ToUpper(target.String())),
		Footer:      &discordgo.MessageEmbedFooter{Text: helpers.GetText("plugins.translator.embed-footer")},
		Description: m,
		Color:       helpers.GetDiscordColorFromHex(googleTranslateHexColor),
		Fields:      []*discordgo.MessageEmbedField{},
	}
	if translatedNaverResult != "" {
		translateEmbed.Fields = append(translateEmbed.Fields, &discordgo.MessageEmbedField{
			Name:  helpers.GetText("plugins.translator.embed-title-alternative-naver"),
			Value: translatedNaverResult})
		translateEmbed.Footer = &discordgo.MessageEmbedFooter{Text: helpers.GetText("plugins.translator.embed-footer-plus-naver")}
	}

	_, err = helpers.SendEmbed(msg.ChannelID, translateEmbed)
	helpers.RelaxEmbed(err, msg.ChannelID, msg.ID)
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"flag"
	"log"
	"os"
	"runtime"
	"time"
)

const (
	VERSION = "0.0.1"
)

// config cruft
type Config struct {
	Target  string
	Clients int
	Sleep   string
}

func parseConfig(filename string) (config *Config) {
	config = new(Config)
	file, err := os.Open(filename)
	if err != nil {
		log.Fatal("unable to open file: " + err.Error())
	}
	defer file.Close()
	fileInfo, err := file.Stat()
	fsize := fileInfo.Size()
	rawBytes := make([]byte, fsize)
	_, err = file.Read(rawBytes)
	if err != nil {
		log.Fatal("unable to read file: " + err.Error())
	}
	if err = json.Unmarshal(rawBytes, config); err != nil {
		log.Fatal("Unable to parse file: " + err.Error())
	}

	return config
}

func poundSock(target string, config *Config, cmd chan int, ctrl chan int, id int) (err error) {
	hostname, err := os.Hostname()
	log.Printf("INFO : (%d) Connecting to %s\n", id, target)
	ws, err := websocket.Dial(config.Target, "", "http://"+hostname)
	if err != nil {
		log.Printf("ERROR: (%d) Unable to open websocket: %s\n",
			id, err.Error())
		cmd <- id
		return err
	}
	duration, err := time.ParseDuration(config.Sleep)
	for {
		_, err = ws.Write([]byte("{\"messageType\":\"ping\"}"))
		if err != nil {
			log.Printf("ERROR: (%d) Unable to write ping to websocket %s\n",
				id, err.Error())
			cmd <- id
			return err
		}
		var msg = make([]byte, 512)
		_, err := ws.Read(msg)
		if err != nil {
			log.Printf("WARN : (%d) Bad response %s\n", id, err.Error())
			cmd <- id
			return err
		}
		time.Sleep(duration)
		select {
		case cc := <-ctrl:
			if cc == 0 {
				break
			}
		default:
		}
	}
	log.Printf("INFO : (%d) Shutting down...\n", id)
	return err
}

func main() {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("PANIC! %s\n", r)
		}
	}()
	configFile := flag.String("config", "config.json", "Config file")
	flag.Parse()

	config := parseConfig(*configFile)
	if config == nil {
		log.Fatal("No config")
		return
	}

	runtime.GOMAXPROCS(config.Clients)

	chans := make(map[int]chan int)
	cmd := make(chan int, config.Clients)

	// run as many clients as specified
	totalClients := config.Clients
	for cli := 0; cli < totalClients; cli++ {

		ctrl := make(chan int)
		chans[cli] = ctrl
		// open a socket to the Target
		log.Printf("Spawning %d\n", cli)

		go func(cli int) {
			poundSock(config.Target, config, cmd, ctrl, cli)
		}(cli)
	}
	lastTot := runtime.NumGoroutine()
	for {
		select {
		case x := <-cmd:
			log.Printf("Exiting %d \n", x)
			totalClients = runtime.NumGoroutine()
		default:
			if totalClients != lastTot {
				log.Printf("Info: Active Clients: %d \n", totalClients)
				lastTot = totalClients
			}
		}
	}
}
<commit_msg>Correct the MAX PROCs to number of CPUs<commit_after>package main

import (
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"flag"
	"log"
	"os"
	"runtime"
	"time"
)

const (
	VERSION = "0.0.1"
)

// config cruft
type Config struct {
	Target  string
	Clients int
	Sleep   string
}

func parseConfig(filename string) (config *Config) {
	config = new(Config)
	file, err := os.Open(filename)
	if err != nil {
		log.Fatal("unable to open file: " + err.Error())
	}
	defer file.Close()
	fileInfo, err := file.Stat()
	fsize := fileInfo.Size()
	rawBytes := make([]byte, fsize)
	_, err = file.Read(rawBytes)
	if err != nil {
		log.Fatal("unable to read file: " + err.Error())
	}
	if err = json.Unmarshal(rawBytes, config); err != nil {
		log.Fatal("Unable to parse file: " + err.Error())
	}

	return config
}

func poundSock(target string, config *Config, cmd chan int, ctrl chan int, id int) (err error) {
	hostname, err := os.Hostname()
	log.Printf("INFO : (%d) Connecting to %s\n", id, target)
	ws, err := websocket.Dial(config.Target, "", "http://"+hostname)
	if err != nil {
		log.Printf("ERROR: (%d) Unable to open websocket: %s\n",
			id, err.Error())
		cmd <- id
		return err
	}
	duration, err := time.ParseDuration(config.Sleep)
	for {
		_, err = ws.Write([]byte("{\"messageType\":\"ping\"}"))
		if err != nil {
			log.Printf("ERROR: (%d) Unable to write ping to websocket %s\n",
				id, err.Error())
			cmd <- id
			return err
		}
		var msg = make([]byte, 512)
		_, err := ws.Read(msg)
		if err != nil {
			log.Printf("WARN : (%d) Bad response %s\n", id, err.Error())
			cmd <- id
			return err
		}
		time.Sleep(duration)
		select {
		case cc := <-ctrl:
			if cc == 0 {
				break
			}
		default:
		}
	}
	log.Printf("INFO : (%d) Shutting down...\n", id)
	return err
}

func main() {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("PANIC! %s\n", r)
		}
	}()
	configFile := flag.String("config", "config.json", "Config file")
	flag.Parse()

	config := parseConfig(*configFile)
	if config == nil {
		log.Fatal("No config")
		return
	}

	// Limit to number of available CPUs
	runtime.GOMAXPROCS(runtime.NumCPU())

	chans := make(map[int]chan int)
	cmd := make(chan int, config.Clients)

	// run as many clients as specified
	totalClients := config.Clients
	for cli := 0; cli < totalClients; cli++ {

		ctrl := make(chan int)
		chans[cli] = ctrl
		// open a socket to the Target
		log.Printf("Spawning %d\n", cli)

		go func(cli int) {
			poundSock(config.Target, config, cmd, ctrl, cli)
		}(cli)
	}
	lastTot := runtime.NumGoroutine()
	for {
		select {
		case x := <-cmd:
			log.Printf("Exiting %d \n", x)
			totalClients = runtime.NumGoroutine()
		default:
			if totalClients != lastTot {
				log.Printf("Info: Active Clients: %d \n", totalClients)
				lastTot = totalClients
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"appengine"
	"appengine/urlfetch"
	"sync"
	"io/ioutil"
	"encoding/json"
	"log"
	"net/http"
	"sort"
	"strings"
	"strconv"
	"time"
)

var (
	location, locationErr = time.LoadLocation("America/Chicago")
	url_base string
	meetup_key string
	url_suffix string
)

/// models
type membersResult struct {
	Results []member `json:"results"`
}
type groupsResult struct {
	Results []Group `json:"results"`
}

/// keep primary object private
type member struct{
	ID       int `json:"id"`
	Joined   int64 `json:"joined"`
	Bio      string `json:"bio"`
	Lat      float32 `json:"lat"`
	Lon      float32 `json:"lon"`
	Link     string `json:"link"`
	Name     string `json:"name"`
	City     string `json:"city"`
	State    string `json:"state"`
	Photo    Photo `json:"photo"`
	Topics   []Topic `json:"topics"`
	Other    Other `json:"other_services"`
}

type Member struct{
	ID       int `json:"id"`
	Joined   int64 `json:"joined"`
	Bio      string `json:"bio"`
	Link     string `json:"link"`
	Name     string `json:"name"`
	City     string `json:"city"`
	State    string `json:"state"`
	Photo    Photo `json:"photo"`
	Other    Other `json:"other_services"`
}

/// member sorting
type ByJoined []member

func (a ByJoined) Len() int { return len(a) }
func (a ByJoined) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByJoined) Less(i, j int) bool { return a[i].Joined < a[j].Joined }

/// end sorting

type Other struct {
	Flickr   Social `json:"flickr"`
	Tumblr   Social `json:"tumblr"`
	Twitter  Social `json:"twitter"`
	Linkedin Social `json:"linkedin"`
	Facebook SocialInt `json:"facebook"`
}

/// json eoncoder could not decode a json int into a string...whoa?
type SocialInt struct {
	Identifier int `json:"identifier"`
}

type Social struct {
	Identifier string `json:"identifier"`
}

/// end whoa

type Photo struct{
	ID    int `json:"photo_id"`
	Thumb string `json:"thumb_link"`
	Full  string `json:"photo_link"`
}

type Topic struct {
	ID     int `json:"id"`
	Name   string  `json:"name"`
	URLKey string  `json:"urlkey"`
}

type Group struct {
	ID        int `json:"id"`
	Name      string `json:"name"`
	NextEvent Event `json:"next_event"`
	URLName   string `json:"urlname"`
}

type Event struct{
	ID           string `json:"id"`
	Name         string `json:"name"`
	GroupName    string `json:"groupName"`
	GroupURLName string `json:"groupURLName"`
	GroupID      int `json:"groupID"`
	Timestamp    int `json:"time"`
	Date         time.Time `json:"date"`
	compareDate  time.Time
	FromNow      int64 `json:"utc_offset"`
	YearDay      int
}

/// event sorting
type ByTimestamp []*Event

func (a ByTimestamp) Len() int { return len(a) }
func (a ByTimestamp) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByTimestamp) Less(i, j int) bool { return a[i].Timestamp < a[j].Timestamp }

/// end sorting

type Calendar struct{
	Months []*Month `json:"months"`
	Events []*Event `json:"events"`
}
type Month struct {
	Name     string `json:"name"`
	StartPos int `json:"startPos"`
	Days     []*Day `json:"days"`
}
type Day struct {
	Date    time.Time `json:"date"`
	Number  int `json:"number"`
	WeekPos int `json:"weekPos"`
	YearDay int
	History bool `json:"history"`
	Events  []Event `json:"events"`
}

func newCalendar(month time.Month, year int) Calendar {
	c := Calendar{}
	context := time.Date(year, month, 1, 0, 0, 0, 0, location).Local()
	next := context.AddDate(0, 1, 0)

	c.Months = append(c.Months, buildMonth(month, year))
	c.Months = append(c.Months, buildMonth(next.Month(), next.Year()))

	return c
}
func buildMonth(month time.Month, year int) *Month {
	log.Println("building month", month)
	n := time.Now().Local()
	m := Month{}
	m.Name = month.String()
	days := time.Date(year, month+1, 0, 0, 0, 0, 0, location).Day()
	start := time.Date(year, month, 1, 0, 0, 0, 0, location)
	m.StartPos = int(start.Weekday())
	for i := 1; i <= days; i++ {
		d := time.Date(year, month, i, 0, 0, 0, 0, location)
		day := Day{
			d,
			i,
			int(d.Weekday()),
			d.YearDay(),
				n.YearDay() > d.YearDay(),
			[]Event{},
		}
		m.Days = append(m.Days, &day)
	}
	return &m
}

/// optimize
func (c *Calendar) plotCalendarEvent(e Event) {
	for _, m := range c.Months {
		for _, d := range m.Days {
			if e.compareDate == d.Date {
				d.Events = append(d.Events, e)
				break
			}
		}
	}
}
func (svc * meetupService) getMembersCalendar(members []Member) (Calendar, error) {
	n := time.Now()
	c := newCalendar(n.Month(), n.Year())
	var ids []int
	for _, m := range members {
		ids = append(ids, m.ID)
	}
	groups, err := svc.getMemberGroups(ids)

	if err != nil {
		log.Printf("error: retrieving member groups: %v\n", err)
		return c, err
	}

	for _, g := range groups {
		if g.NextEvent.Timestamp > 0 {
			g.NextEvent.Date = time.Unix(0, int64(g.NextEvent.Timestamp)*int64(time.Millisecond)).Local()
			g.NextEvent.YearDay = g.NextEvent.Date.YearDay()
			g.NextEvent.GroupName = g.Name
			g.NextEvent.GroupID = g.ID
			g.NextEvent.GroupURLName = g.URLName
			y, m, d := g.NextEvent.Date.Date();
			g.NextEvent.compareDate = time.Date(y, m, d, 0, 0, 0, 0, location)

			c.Events = append(c.Events, &g.NextEvent)
			c.plotCalendarEvent(g.NextEvent)
		}
	}
	log.Printf("success: found member groups: %v\n", len(groups))
	sort.Sort(ByTimestamp(c.Events))
	return c, nil
}

/// called on module initialization
func init() {
	initialize()
	log.Println("location", location)
}

func initialize() {
	url_base = config.Meetup.BaseUrl
	meetup_key = config.Meetup.Key
	url_suffix = "sign=true&key="+meetup_key
}

///
/// api below
///

type meetupService struct{
	context     appengine.Context
	HttpRequest http.Request
}

func (svc *meetupService) SetContext(c appengine.Context) {
	svc.context = c;
}

func (svc * meetupService) getMembers() ([]member, error) {
	if meetup_key == "" {
		initialize()
	}

	url := url_base + "members?group_urlname=golangmn&" + url_suffix

	client := urlfetch.Client(svc.context)

	resp, err := client.Get(url)

	if err != nil {
		return []member{}, err
	}

	var mr membersResult
	err = json.NewDecoder(resp.Body).Decode(&mr)

	if err != nil {
		log.Printf("members decode error: %v", err)
		return []member{}, err
	}
	sort.Sort(ByJoined(mr.Results))
	return mr.Results, err
}

func (svc * meetupService) getMember(id int) (*[]byte, error) {
	if meetup_key == "" {
		initialize()
	}
	url := url_base + "member/" + strconv.Itoa(id) + "?" + url_suffix

	client := urlfetch.Client(svc.context)

	resp, err := client.Get(url)

	if err != nil {
		log.Fatal(err)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return &body, err
	}

	return &body, err
}

func (svc * meetupService) getMemberGroups(ids []int) ([]Group, error) {
	totalGroups := groupsResult{}
	var err error
	max := 40
	var wg sync.WaitGroup
	if meetup_key == "" {
		initialize()
	}
	var strids []string
	for _, value := range ids {
		strids = append(strids, strconv.Itoa(value))
	}

	l := len(strids) / max

	for i := 0; i < l; i +=1 {
		wg.Add(1)
		num := max
		if (max*i)+40 > len(strids) {
			num = len(strids)-1
		}
		cids := strids[max*i:num]
		go func(g *groupsResult, ids []string) {
			defer wg.Done()
			url := url_base + "groups/?member_id=" + strings.Join(ids, ",") + "&fields=next_event&" + url_suffix
			client := urlfetch.Client(svc.context)
			resp, err := client.Get(url)
			var gr groupsResult
			err = json.NewDecoder(resp.Body).Decode(&gr)
			if err != nil{
				log.Println("error retrieving groups", err)
			}else{
				g.Results = append(g.Results, gr.Results...)
			}
		}(&totalGroups, cids)

	}
	wg.Wait()

	return totalGroups.Results, err

}
<commit_msg>- fixed : determining page size for member groups paging<commit_after>package main

import (
	"appengine"
	"appengine/urlfetch"
	"sync"
	"io/ioutil"
	"encoding/json"
	"log"
	"net/http"
	"sort"
	"strings"
	"strconv"
	"time"
)

var (
	location, locationErr = time.LoadLocation("America/Chicago")
	url_base string
	meetup_key string
	url_suffix string
)

/// models
type membersResult struct {
	Results []member `json:"results"`
}
type groupsResult struct {
	Results []Group `json:"results"`
}

/// keep primary object private
type member struct{
	ID       int `json:"id"`
	Joined   int64 `json:"joined"`
	Bio      string `json:"bio"`
	Lat      float32 `json:"lat"`
	Lon      float32 `json:"lon"`
	Link     string `json:"link"`
	Name     string `json:"name"`
	City     string `json:"city"`
	State    string `json:"state"`
	Photo    Photo `json:"photo"`
	Topics   []Topic `json:"topics"`
	Other    Other `json:"other_services"`
}

type Member struct{
	ID       int `json:"id"`
	Joined   int64 `json:"joined"`
	Bio      string `json:"bio"`
	Link     string `json:"link"`
	Name     string `json:"name"`
	City     string `json:"city"`
	State    string `json:"state"`
	Photo    Photo `json:"photo"`
	Other    Other `json:"other_services"`
}

/// member sorting
type ByJoined []member

func (a ByJoined) Len() int { return len(a) }
func (a ByJoined) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByJoined) Less(i, j int) bool { return a[i].Joined < a[j].Joined }

/// end sorting

type Other struct {
	Flickr   Social `json:"flickr"`
	Tumblr   Social `json:"tumblr"`
	Twitter  Social `json:"twitter"`
	Linkedin Social `json:"linkedin"`
	Facebook SocialInt `json:"facebook"`
}

/// json eoncoder could not decode a json int into a string...whoa?
type SocialInt struct {
	Identifier int `json:"identifier"`
}

type Social struct {
	Identifier string `json:"identifier"`
}

/// end whoa

type Photo struct{
	ID    int `json:"photo_id"`
	Thumb string `json:"thumb_link"`
	Full  string `json:"photo_link"`
}

type Topic struct {
	ID     int `json:"id"`
	Name   string  `json:"name"`
	URLKey string  `json:"urlkey"`
}

type Group struct {
	ID        int `json:"id"`
	Name      string `json:"name"`
	NextEvent Event `json:"next_event"`
	URLName   string `json:"urlname"`
}

type Event struct{
	ID           string `json:"id"`
	Name         string `json:"name"`
	GroupName    string `json:"groupName"`
	GroupURLName string `json:"groupURLName"`
	GroupID      int `json:"groupID"`
	Timestamp    int `json:"time"`
	Date         time.Time `json:"date"`
	compareDate  time.Time
	FromNow      int64 `json:"utc_offset"`
	YearDay      int
}

/// event sorting
type ByTimestamp []*Event

func (a ByTimestamp) Len() int { return len(a) }
func (a ByTimestamp) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByTimestamp) Less(i, j int) bool { return a[i].Timestamp < a[j].Timestamp }

/// end sorting

type Calendar struct{
	Months []*Month `json:"months"`
	Events []*Event `json:"events"`
}
type Month struct {
	Name     string `json:"name"`
	StartPos int `json:"startPos"`
	Days     []*Day `json:"days"`
}
type Day struct {
	Date    time.Time `json:"date"`
	Number  int `json:"number"`
	WeekPos int `json:"weekPos"`
	YearDay int
	History bool `json:"history"`
	Events  []Event `json:"events"`
}

func newCalendar(month time.Month, year int) Calendar {
	c := Calendar{}
	context := time.Date(year, month, 1, 0, 0, 0, 0, location).Local()
	next := context.AddDate(0, 1, 0)

	c.Months = append(c.Months, buildMonth(month, year))
	c.Months = append(c.Months, buildMonth(next.Month(), next.Year()))

	return c
}
func buildMonth(month time.Month, year int) *Month {
	log.Println("building month", month)
	n := time.Now().Local()
	m := Month{}
	m.Name = month.String()
	days := time.Date(year, month+1, 0, 0, 0, 0, 0, location).Day()
	start := time.Date(year, month, 1, 0, 0, 0, 0, location)
	m.StartPos = int(start.Weekday())
	for i := 1; i <= days; i++ {
		d := time.Date(year, month, i, 0, 0, 0, 0, location)
		day := Day{
			d,
			i,
			int(d.Weekday()),
			d.YearDay(),
				n.YearDay() > d.YearDay(),
			[]Event{},
		}
		m.Days = append(m.Days, &day)
	}
	return &m
}

/// optimize
func (c *Calendar) plotCalendarEvent(e Event) {
	for _, m := range c.Months {
		for _, d := range m.Days {
			if e.compareDate == d.Date {
				d.Events = append(d.Events, e)
				break
			}
		}
	}
}
func (svc * meetupService) getMembersCalendar(members []Member) (Calendar, error) {
	n := time.Now()
	c := newCalendar(n.Month(), n.Year())
	var ids []int
	for _, m := range members {
		ids = append(ids, m.ID)
	}
	groups, err := svc.getMemberGroups(ids)

	if err != nil {
		log.Printf("error: retrieving member groups: %v\n", err)
		return c, err
	}

	for _, g := range groups {
		if g.NextEvent.Timestamp > 0 {
			g.NextEvent.Date = time.Unix(0, int64(g.NextEvent.Timestamp)*int64(time.Millisecond)).Local()
			g.NextEvent.YearDay = g.NextEvent.Date.YearDay()
			g.NextEvent.GroupName = g.Name
			g.NextEvent.GroupID = g.ID
			g.NextEvent.GroupURLName = g.URLName
			y, m, d := g.NextEvent.Date.Date();
			g.NextEvent.compareDate = time.Date(y, m, d, 0, 0, 0, 0, location)

			c.Events = append(c.Events, &g.NextEvent)
			c.plotCalendarEvent(g.NextEvent)
		}
	}
	log.Printf("success: found member groups: %v\n", len(groups))
	sort.Sort(ByTimestamp(c.Events))
	return c, nil
}

/// called on module initialization
func init() {
	initialize()
	log.Println("location", location)
}

func initialize() {
	url_base = config.Meetup.BaseUrl
	meetup_key = config.Meetup.Key
	url_suffix = "sign=true&key="+meetup_key
}

///
/// api below
///

type meetupService struct{
	context     appengine.Context
	HttpRequest http.Request
}

func (svc *meetupService) SetContext(c appengine.Context) {
	svc.context = c;
}

func (svc * meetupService) getMembers() ([]member, error) {
	if meetup_key == "" {
		initialize()
	}

	url := url_base + "members?group_urlname=golangmn&" + url_suffix

	client := urlfetch.Client(svc.context)

	resp, err := client.Get(url)

	if err != nil {
		return []member{}, err
	}

	var mr membersResult
	err = json.NewDecoder(resp.Body).Decode(&mr)

	if err != nil {
		log.Printf("members decode error: %v", err)
		return []member{}, err
	}
	sort.Sort(ByJoined(mr.Results))
	return mr.Results, err
}

func (svc * meetupService) getMember(id int) (*[]byte, error) {
	if meetup_key == "" {
		initialize()
	}
	url := url_base + "member/" + strconv.Itoa(id) + "?" + url_suffix

	client := urlfetch.Client(svc.context)

	resp, err := client.Get(url)

	if err != nil {
		log.Fatal(err)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return &body, err
	}

	return &body, err
}

func (svc * meetupService) getMemberGroups(ids []int) ([]Group, error) {
	totalGroups := groupsResult{}
	var err error
	max := 40
	var wg sync.WaitGroup
	if meetup_key == "" {
		initialize()
	}
	var strids []string
	for _, value := range ids {
		strids = append(strids, strconv.Itoa(value))
	}

	l := len(strids) / max

	for i := 0; i < l; i +=1 {
		wg.Add(1)
		num := (i * max) + max
		if (num > (len(strids)-1)) {
			num = len(strids)-1
		}
		cids := strids[max*i:num]
		go func(g *groupsResult, ids []string) {
			defer wg.Done()
			url := url_base + "groups/?member_id=" + strings.Join(ids, ",") + "&fields=next_event&" + url_suffix
			client := urlfetch.Client(svc.context)
			resp, err := client.Get(url)
			var gr groupsResult
			err = json.NewDecoder(resp.Body).Decode(&gr)
			if err != nil{
				log.Println("error retrieving groups", err)
			}else{
				g.Results = append(g.Results, gr.Results...)
			}
		}(&totalGroups, cids)

	}
	wg.Wait()

	return totalGroups.Results, err

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"net/http"

	"github.com/gorilla/sessions"
	"github.com/jinzhu/gorm"
)

type Context struct {
	globalContext
	Session    *sessions.Session
	AdminLogin bool
	Captcha    *Deck
}

func NewContext(req *http.Request, gctx *globalContext) (*Context, error) {
	sess, err := gctx.Store.Get(req, "rtfblog")
	logger.LogIf(err)
	ctx := &Context{
		globalContext: *gctx,
		Session:       sess,
		AdminLogin:    sess.Values["adminlogin"] == "yes",
		Captcha:       deck,
	}
	return ctx, nil
}

func MkFlashes(ctx *Context) template.HTML {
	flashes := ctx.Session.Flashes()
	html := ""
	// TODO: extract that to separate flashes template
	format := `

%s

<svg onclick="removeElt('flash-%d');">
<circle cx="12" cy="12" r="11" stroke-width="0" fill="white" fill-opacity="0" />
<path stroke="black" stroke-width="4" fill="none" d="M6.25,6.25,17.75,17.75" />
<path stroke="black" stroke-width="4" fill="none" d="M6.25,17.75,17.75,6.25" />
</svg>

`
	for i, f := range flashes {
		html += fmt.Sprintf(format, i, f, i)
	}
	return template.HTML(`<div class="six columns">` + html + "
")
}

func MkBasicData(ctx *Context, pageNo, offset int) tmplMap {
	numTotalPosts, err := ctx.Db.numPosts(ctx.AdminLogin)
	logger.LogIf(err)
	titles, err := ctx.Db.titles(NumRecentPosts, ctx.AdminLogin)
	logger.LogIf(err)
	posts, err := ctx.Db.posts(PostsPerPage, offset, ctx.AdminLogin)
	logger.LogIf(err)
	return tmplMap{
		"PageTitle":       L10n("Welcome"),
		"BlogTitle":       conf.Interface.BlogTitle,
		"BlogSubtitle":    conf.Interface.BlogDescr,
		"NeedPagination":  numTotalPosts > PostsPerPage,
		"ListOfPages":     listOfPages(numTotalPosts, pageNo),
		"entries":         posts,
		"sidebar_entries": titles,
		"AdminLogin":      ctx.AdminLogin,
		"Version":         versionString(),
		"Flashes":         MkFlashes(ctx),
	}
}

func withTransaction(db Data, fn func(db Data) error) error {
	txErr := db.begin()
	if txErr != nil {
		return txErr
	}
	err := fn(db)
	if err != nil {
		db.rollback()
		return err
	}
	db.commit()
	return nil
}

func PublishCommentAndCommenter(db Data, postID int64, commenter *Commenter, rawBody string) (string, error) {
	var commentID int64
	err := withTransaction(db, func(db Data) error {
		commenterID, err := db.insertCommenter(commenter)
		if err != nil {
			return logger.LogIff(err, "db.insertCommenter() failed")
		}
		commentID, err = db.insertComment(commenterID, postID, rawBody)
		if err != nil {
			return logger.LogIff(err, "db.insertComment() failed")
		}
		return nil
	})
	return fmt.Sprintf("#comment-%d", commentID), err
}

func PublishComment(db Data, postID, commenterID int64, body string) (string, error) {
	var commentID int64
	err := withTransaction(db, func(db Data) error {
		var insErr error
		commentID, insErr = db.insertComment(commenterID, postID, body)
		return logger.LogIff(insErr, "db.insertComment() failed")
	})
	return fmt.Sprintf("#comment-%d", commentID), err
}

func InsertOrUpdatePost(db Data, post *EntryTable) (id int64, err error) {
	postID, idErr := db.postID(post.URL)
	if idErr != nil {
		if idErr == gorm.ErrRecordNotFound {
			author, err := db.author()
			if err != nil {
				return -1, err
			}
			post.AuthorID = author.ID
			newPostID, err := db.insertPost(post)
			if err != nil {
				return -1, err
			}
			postID = newPostID
		} else {
			return -1, logger.LogIff(idErr, "db.postID() failed")
		}
	} else {
		post.ID = postID
		updErr := db.updatePost(post)
		if updErr != nil {
			return -1, updErr
		}
	}
	return postID, nil
}

func InsertOrUpdateAuthor(db Data, newAuthor *Author) (id int64, err error) {
	author, err := db.author() // Pick default author
	id = author.ID
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			id, err = db.insertAuthor(newAuthor)
		}
	} else {
		newAuthor.ID = id
		err = db.updateAuthor(newAuthor)
	}
	return id, logger.LogIff(err, "Failed to insert author")
}
<commit_msg>Fix bug with editing posts<commit_after>package main

import (
	"fmt"
	"html/template"
	"net/http"

	"github.com/gorilla/sessions"
	"github.com/jinzhu/gorm"
)

type Context struct {
	globalContext
	Session    *sessions.Session
	AdminLogin bool
	Captcha    *Deck
}

func NewContext(req *http.Request, gctx *globalContext) (*Context, error) {
	sess, err := gctx.Store.Get(req, "rtfblog")
	logger.LogIf(err)
	ctx := &Context{
		globalContext: *gctx,
		Session:       sess,
		AdminLogin:    sess.Values["adminlogin"] == "yes",
		Captcha:       deck,
	}
	return ctx, nil
}

func MkFlashes(ctx *Context) template.HTML {
	flashes := ctx.Session.Flashes()
	html := ""
	// TODO: extract that to separate flashes template
	format := `

%s

<svg onclick="removeElt('flash-%d');">
<circle cx="12" cy="12" r="11" stroke-width="0" fill="white" fill-opacity="0" />
<path stroke="black" stroke-width="4" fill="none" d="M6.25,6.25,17.75,17.75" />
<path stroke="black" stroke-width="4" fill="none" d="M6.25,17.75,17.75,6.25" />
</svg>

`
	for i, f := range flashes {
		html += fmt.Sprintf(format, i, f, i)
	}
	return template.HTML(`<div class="six columns">` + html + "
")
}

func MkBasicData(ctx *Context, pageNo, offset int) tmplMap {
	numTotalPosts, err := ctx.Db.numPosts(ctx.AdminLogin)
	logger.LogIf(err)
	titles, err := ctx.Db.titles(NumRecentPosts, ctx.AdminLogin)
	logger.LogIf(err)
	posts, err := ctx.Db.posts(PostsPerPage, offset, ctx.AdminLogin)
	logger.LogIf(err)
	return tmplMap{
		"PageTitle":       L10n("Welcome"),
		"BlogTitle":       conf.Interface.BlogTitle,
		"BlogSubtitle":    conf.Interface.BlogDescr,
		"NeedPagination":  numTotalPosts > PostsPerPage,
		"ListOfPages":     listOfPages(numTotalPosts, pageNo),
		"entries":         posts,
		"sidebar_entries": titles,
		"AdminLogin":      ctx.AdminLogin,
		"Version":         versionString(),
		"Flashes":         MkFlashes(ctx),
	}
}

func withTransaction(db Data, fn func(db Data) error) error {
	txErr := db.begin()
	if txErr != nil {
		return txErr
	}
	err := fn(db)
	if err != nil {
		db.rollback()
		return err
	}
	db.commit()
	return nil
}

func PublishCommentAndCommenter(db Data, postID int64, commenter *Commenter, rawBody string) (string, error) {
	var commentID int64
	err := withTransaction(db, func(db Data) error {
		commenterID, err := db.insertCommenter(commenter)
		if err != nil {
			return logger.LogIff(err, "db.insertCommenter() failed")
		}
		commentID, err = db.insertComment(commenterID, postID, rawBody)
		if err != nil {
			return logger.LogIff(err, "db.insertComment() failed")
		}
		return nil
	})
	return fmt.Sprintf("#comment-%d", commentID), err
}

func PublishComment(db Data, postID, commenterID int64, body string) (string, error) {
	var commentID int64
	err := withTransaction(db, func(db Data) error {
		var insErr error
		commentID, insErr = db.insertComment(commenterID, postID, body)
		return logger.LogIff(insErr, "db.insertComment() failed")
	})
	return fmt.Sprintf("#comment-%d", commentID), err
}

func InsertOrUpdatePost(db Data, post *EntryTable) (id int64, err error) {
	author, err := db.author()
	if err != nil {
		return -1, err
	}
	postID, idErr := db.postID(post.URL)
	if idErr != nil {
		if idErr == gorm.ErrRecordNotFound {
			post.AuthorID = author.ID
			newPostID, err := db.insertPost(post)
			if err != nil {
				return -1, err
			}
			postID = newPostID
		} else {
			return -1, logger.LogIff(idErr, "db.postID() failed")
		}
	} else {
		post.ID = postID
		post.AuthorID = author.ID
		updErr := db.updatePost(post)
		if updErr != nil {
			return -1, updErr
		}
	}
	return postID, nil
}

func InsertOrUpdateAuthor(db Data, newAuthor *Author) (id int64, err error) {
	author, err := db.author() // Pick default author
	id = author.ID
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			id, err = db.insertAuthor(newAuthor)
		}
	} else {
		newAuthor.ID = id
		err = db.updateAuthor(newAuthor)
	}
	return id, logger.LogIff(err, "Failed to insert author")
}
<|endoftext|>


<commit_before>// Copyright 2016, RadiantBlue Technologies, 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 lib

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/venicegeo/pz-gocommon"
	"github.com/venicegeo/pz-gocommon/elasticsearch"
)

type LockedAdminStats struct {
	sync.Mutex
	LoggerAdminStats
}

var stats LockedAdminStats

type LogData struct {
	sync.Mutex
	esIndex elasticsearch.IIndex
	id      int
}

var logData LogData

var schema = "LogData"

func initServer(sys *piazza.SystemConfig, esIndex elasticsearch.IIndex) {
	var err error

	stats.StartTime = time.Now()

	/***
	err = esIndex.Delete()
	if err != nil {
		log.Fatal(err)
	}
	if esIndex.IndexExists() {
		log.Fatal("index still exists")
	}
	err = esIndex.Create()
	if err != nil {
		log.Fatal(err)
	}
	***/

	if !esIndex.IndexExists() {
		err = esIndex.Create()
		if err != nil {
			log.Fatal(err)
		}

		mapping :=
			`{
		    "LogData":{
			    "properties":{
				    "service":{
					    "type": "string",
                        "store": true
    			    },
				    "address":{
					    "type": "string",
                        "store": true
    			    },
				    "stamp":{
					    "type": "long",
                        "store": true
    			    },
				    "severity":{
					    "type": "string",
                        "store": true
    			    },
				    "message":{
					    "type": "string",
                        "store": true
    			    }
	    	    }
	        }
        }`

		err = esIndex.SetMapping(schema, piazza.JsonString(mapping))
		if err != nil {
			log.Fatal(err)
		}
	}

	logData.esIndex = esIndex
}

func handleGetRoot(c *gin.Context) {
	//log.Print("got health-check request")
	c.String(http.StatusOK, "Hi. I'm pz-logger.")
}

func handlePostMessages(c *gin.Context) {
	var mssg Message
	err := c.BindJSON(&mssg)
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	err = mssg.Validate()
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	log.Printf("PZLOG: %s\n", mssg.String())

	logData.Lock()
	idStr := strconv.Itoa(logData.id)
	logData.id++
	logData.Unlock()
	indexResult, err := logData.esIndex.PostData(schema, idStr, mssg)
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}
	if !indexResult.Created {
		c.String(http.StatusBadRequest, "POST of log data failed")
		return
	}

	err = logData.esIndex.Flush()
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	stats.LoggerAdminStats.NumMessages++

	c.JSON(http.StatusOK, nil)
}

func handleGetAdminStats(c *gin.Context) {
	logData.Lock()
	t := stats.LoggerAdminStats
	logData.Unlock()
	c.JSON(http.StatusOK, t)
}

// func handlePostAdminShutdown(c *gin.Context) {
// 	piazza.HandlePostAdminShutdown(c)
// }

func handleGetMessages(c *gin.Context) {
	var err error

	format := elasticsearch.GetFormatParams(c, 10, 0, "stamp", elasticsearch.SortDescending)

	//log.Printf("size %d, from %d, key %s, format %v",
	//	format.Size, format.From, format.Key, format.Order)

	searchResult, err := logData.esIndex.FilterByMatchAll(schema, format)
	if err != nil {
		c.String(http.StatusBadRequest, "query failed: %s", err)
		return
	}

	// TODO: unsafe truncation
	count := int(searchResult.TotalHits())
	lines := make([]Message, count)

	i := 0
	for _, hit := range *searchResult.GetHits() {
		if hit == nil {
			log.Printf("null source hit")
			continue
		}
		src := *hit.Source
		//log.Printf("source hit: %s", string(src))

		tmp := &Message{}
		err = json.Unmarshal(src, tmp)
		if err != nil {
			log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
			c.String(http.StatusBadRequest, "query unmarshal failed: %s", err)
			return
		}
		err = tmp.Validate()
		if err != nil {
			log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
			//c.String(http.StatusBadRequest, "query unmarshal failed to validate: %s", err)
			//return
			continue
		}
		lines[i] = *tmp
		i++
	}

	c.JSON(http.StatusOK, lines)
}

func CreateHandlers(sys *piazza.SystemConfig, esi elasticsearch.IIndex) http.Handler {
	initServer(sys, esi)

	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	//router.Use(gin.Logger())
	//router.Use(gin.Recovery())

	router.GET("/", func(c *gin.Context) { handleGetRoot(c) })

	router.POST("/v1/messages", func(c *gin.Context) { handlePostMessages(c) })
	router.GET("/v1/messages", func(c *gin.Context) { handleGetMessages(c) })

	router.GET("/v1/admin/stats", func(c *gin.Context) { handleGetAdminStats(c) })

	// router.POST("/v1/admin/shutdown", func(c *gin.Context) { handlePostAdminShutdown(c) })

	return router
}
<commit_msg>remove old /admin/shutdown code<commit_after>// Copyright 2016, RadiantBlue Technologies, 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 lib

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/venicegeo/pz-gocommon"
	"github.com/venicegeo/pz-gocommon/elasticsearch"
)

type LockedAdminStats struct {
	sync.Mutex
	LoggerAdminStats
}

var stats LockedAdminStats

type LogData struct {
	sync.Mutex
	esIndex elasticsearch.IIndex
	id      int
}

var logData LogData

var schema = "LogData"

func initServer(sys *piazza.SystemConfig, esIndex elasticsearch.IIndex) {
	var err error

	stats.StartTime = time.Now()

	/***
	err = esIndex.Delete()
	if err != nil {
		log.Fatal(err)
	}
	if esIndex.IndexExists() {
		log.Fatal("index still exists")
	}
	err = esIndex.Create()
	if err != nil {
		log.Fatal(err)
	}
	***/

	if !esIndex.IndexExists() {
		err = esIndex.Create()
		if err != nil {
			log.Fatal(err)
		}

		mapping :=
			`{
		    "LogData":{
			    "properties":{
				    "service":{
					    "type": "string",
                        "store": true
    			    },
				    "address":{
					    "type": "string",
                        "store": true
    			    },
				    "stamp":{
					    "type": "long",
                        "store": true
    			    },
				    "severity":{
					    "type": "string",
                        "store": true
    			    },
				    "message":{
					    "type": "string",
                        "store": true
    			    }
	    	    }
	        }
        }`

		err = esIndex.SetMapping(schema, piazza.JsonString(mapping))
		if err != nil {
			log.Fatal(err)
		}
	}

	logData.esIndex = esIndex
}

func handleGetRoot(c *gin.Context) {
	//log.Print("got health-check request")
	c.String(http.StatusOK, "Hi. I'm pz-logger.")
}

func handlePostMessages(c *gin.Context) {
	var mssg Message
	err := c.BindJSON(&mssg)
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	err = mssg.Validate()
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	log.Printf("PZLOG: %s\n", mssg.String())

	logData.Lock()
	idStr := strconv.Itoa(logData.id)
	logData.id++
	logData.Unlock()
	indexResult, err := logData.esIndex.PostData(schema, idStr, mssg)
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}
	if !indexResult.Created {
		c.String(http.StatusBadRequest, "POST of log data failed")
		return
	}

	err = logData.esIndex.Flush()
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	stats.LoggerAdminStats.NumMessages++

	c.JSON(http.StatusOK, nil)
}

func handleGetAdminStats(c *gin.Context) {
	logData.Lock()
	t := stats.LoggerAdminStats
	logData.Unlock()
	c.JSON(http.StatusOK, t)
}

func handleGetMessages(c *gin.Context) {
	var err error

	format := elasticsearch.GetFormatParams(c, 10, 0, "stamp", elasticsearch.SortDescending)

	//log.Printf("size %d, from %d, key %s, format %v",
	//	format.Size, format.From, format.Key, format.Order)

	searchResult, err := logData.esIndex.FilterByMatchAll(schema, format)
	if err != nil {
		c.String(http.StatusBadRequest, "query failed: %s", err)
		return
	}

	// TODO: unsafe truncation
	count := int(searchResult.TotalHits())
	lines := make([]Message, count)

	i := 0
	for _, hit := range *searchResult.GetHits() {
		if hit == nil {
			log.Printf("null source hit")
			continue
		}
		src := *hit.Source
		//log.Printf("source hit: %s", string(src))

		tmp := &Message{}
		err = json.Unmarshal(src, tmp)
		if err != nil {
			log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
			c.String(http.StatusBadRequest, "query unmarshal failed: %s", err)
			return
		}
		err = tmp.Validate()
		if err != nil {
			log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
			//c.String(http.StatusBadRequest, "query unmarshal failed to validate: %s", err)
			//return
			continue
		}
		lines[i] = *tmp
		i++
	}

	c.JSON(http.StatusOK, lines)
}

func CreateHandlers(sys *piazza.SystemConfig, esi elasticsearch.IIndex) http.Handler {
	initServer(sys, esi)

	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	//router.Use(gin.Logger())
	//router.Use(gin.Recovery())

	router.GET("/", func(c *gin.Context) { handleGetRoot(c) })

	router.POST("/v1/messages", func(c *gin.Context) { handlePostMessages(c) })
	router.GET("/v1/messages", func(c *gin.Context) { handleGetMessages(c) })

	router.GET("/v1/admin/stats", func(c *gin.Context) { handleGetAdminStats(c) })

	return router
}
<|endoftext|>


<commit_before>// +build !windows

package singleinstance

import (
	"io/ioutil"
	"os"
	"strconv"
	"syscall"
)

// CreateLockFile try to create a file with given name
// and acquire an exclusive lock on it
// if the file already exists AND is still locked, it will fail
func CreateLockFile(filename string) (*os.File, error) {
	var (
		file *os.File
		err  error
	)

	if _, err = os.Stat(filename); os.IsNotExist(err) {
		// file doesnt exist, create
		file, err = os.Create(filename)
	} else {
		// file does exist, open
		file, err = os.OpenFile(filename, os.O_WRONLY, 0666)
	}

	if err != nil {
		return nil, err
	}

	err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
	if err != nil {
		return nil, err
	}

	_, err = file.WriteString(strconv.Itoa(os.Getpid()))
	if err != nil {
		return nil, err
	}

	return file, nil
}

func GetLockFilePid(filename string) (pid int, err error) {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}

	pid, err = strconv.Atoi(string(contents))
	return
}
<commit_msg>Adds docs for GetLockFilePid()<commit_after>// +build !windows

package singleinstance

import (
	"io/ioutil"
	"os"
	"strconv"
	"syscall"
)

// CreateLockFile try to create a file with given name
// and acquire an exclusive lock on it
// if the file already exists AND is still locked, it will fail
func CreateLockFile(filename string) (*os.File, error) {
	var (
		file *os.File
		err  error
	)

	if _, err = os.Stat(filename); os.IsNotExist(err) {
		// file doesnt exist, create
		file, err = os.Create(filename)
	} else {
		// file does exist, open
		file, err = os.OpenFile(filename, os.O_WRONLY, 0666)
	}

	if err != nil {
		return nil, err
	}

	err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
	if err != nil {
		return nil, err
	}

	// Write PID to lock file
	_, err = file.WriteString(strconv.Itoa(os.Getpid()))
	if err != nil {
		return nil, err
	}

	return file, nil
}

// If filename is a lock file, returns the PID of the process locking it
func GetLockFilePid(filename string) (pid int, err error) {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}

	pid, err = strconv.Atoi(string(contents))
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"image/color"

	"engo.io/ecs"
	"engo.io/engo"
	"engo.io/engo/common"
	"github.com/kori-irrlicht/jump-game/ui"
)

type mainMenu struct{}

func (g *mainMenu) Type() string { return sceneMainMenu }
func (g *mainMenu) Preload() {
	err := engo.Files.Load("Roboto-Regular.ttf")
	fmt.Println(err)
}
func (g *mainMenu) Setup(world *ecs.World) {

	common.SetBackground(color.White)

	world.AddSystem(&common.RenderSystem{})
	world.AddSystem(&common.MouseSystem{})
	world.AddSystem(&ui.ActionSystem{})

	menu := buildMainMenu()

	for _, s := range world.Systems() {
		menu.AddTo(s)
	}

}

func buildMainMenu() *ui.Menu {
	buttons := []ui.Button{
		{
			Text: "Hallo",
			Action: func() {
				fmt.Println("Hallo")
			},
		},
		{
			Text: "Welt",
			Action: func() {
				fmt.Println("Welt")
			},
		},
	}
	m := &ui.Menu{}
	m.SpaceComponent = &common.SpaceComponent{
		Position: engo.Point{X: 0, Y: 0},
		Height:   100,
		Width:    200,
	}
	m.Center(engo.Point{
		X: 400,
		Y: 320,
	})

	m.BuildMenu(buttons)
	return m

}
<commit_msg>Change button labels<commit_after>package main

import (
	"fmt"
	"image/color"

	"engo.io/ecs"
	"engo.io/engo"
	"engo.io/engo/common"
	"github.com/kori-irrlicht/jump-game/ui"
)

type mainMenu struct{}

func (g *mainMenu) Type() string { return sceneMainMenu }
func (g *mainMenu) Preload() {
	err := engo.Files.Load("Roboto-Regular.ttf")
	fmt.Println(err)
}
func (g *mainMenu) Setup(world *ecs.World) {

	common.SetBackground(color.White)

	world.AddSystem(&common.RenderSystem{})
	world.AddSystem(&common.MouseSystem{})
	world.AddSystem(&ui.ActionSystem{})

	menu := buildMainMenu()

	for _, s := range world.Systems() {
		menu.AddTo(s)
	}

}

func buildMainMenu() *ui.Menu {
	buttons := []ui.Button{
		{
			Text: "Start",
			Action: func() {
				engo.SetSceneByName(sceneGame, true)
			},
		},
		{
			Text: "Quit",
			Action: func() {
				engo.Exit()
			},
		},
	}
	m := &ui.Menu{}
	m.SpaceComponent = &common.SpaceComponent{
		Position: engo.Point{X: 0, Y: 0},
		Height:   100,
		Width:    200,
	}
	m.Center(engo.Point{
		X: 400,
		Y: 320,
	})

	m.BuildMenu(buttons)
	return m

}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"errors"
	"testing"

	"github.com/codegangsta/cli"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

func TestCreateAndRunApp(t *testing.T) {
	mockCommander := new(mockCommander)
	torcher := &torcher{
		commander: mockCommander,
	}

	var validateContext = func(args mock.Arguments) {
		context := args.Get(0).(*cli.Context)
		assert.NotNil(t, context)
		assert.Equal(t, "go-torch", context.App.Name)
	}
	mockCommander.On("goTorchCommand", mock.AnythingOfType("*cli.Context")).Return().Run(validateContext).Once()

	torcher.createAndRunApp()
}

func TestCreateAndRunAppDefaultValues(t *testing.T) {
	mockCommander := new(mockCommander)
	torcher := &torcher{
		commander: mockCommander,
	}

	validateDefaults := func(args mock.Arguments) {
		context := args.Get(0).(*cli.Context)
		assert.Equal(t, 30, context.Int("time"))
		assert.Equal(t, "http://localhost:8080", context.String("url"))
		assert.Equal(t, "/debug/pprof/profile", context.String("suffix"))
		assert.Equal(t, "torch.svg", context.String("file"))
		assert.Equal(t, "", context.String("binaryinput"))
		assert.Equal(t, "", context.String("binaryname"))
		assert.Equal(t, false, context.Bool("print"))
		assert.Equal(t, false, context.Bool("raw"))
		assert.Equal(t, 10, len(context.App.Flags))
	}
	mockCommander.On("goTorchCommand", mock.AnythingOfType(
		"*cli.Context")).Return().Run(validateDefaults)

	torcher.createAndRunApp()
}

func TestGoTorchCommand(t *testing.T) {
	mockValidator := new(mockValidator)
	mockPprofer := new(mockPprofer)
	mockGrapher := new(mockGrapher)
	mockVisualizer := new(mockVisualizer)
	commander := &defaultCommander{
		validator:  mockValidator,
		pprofer:    mockPprofer,
		grapher:    mockGrapher,
		visualizer: mockVisualizer,
	}

	samplePprofOutput := []byte("out")

	mockValidator.On("validateArgument", "torch.svg", `\w+\.svg`,
		"Output file name must be .svg").Return(nil).Once()
	mockPprofer.On("runPprofCommand", []string{"-seconds", "30", "http://localhost/hi"}).Return(samplePprofOutput, nil).Once()
	mockGrapher.On("GraphAsText", samplePprofOutput).Return("1;2;3 3", nil).Once()
	mockVisualizer.On("GenerateFlameGraph", "1;2;3 3", "torch.svg", false).Return(nil).Once()

	createSampleContext(commander)

	mockValidator.AssertExpectations(t)
	mockPprofer.AssertExpectations(t)
	mockGrapher.AssertExpectations(t)
	mockVisualizer.AssertExpectations(t)
}

func TestGoTorchCommandRawOutput(t *testing.T) {
	mockValidator := new(mockValidator)
	mockPprofer := new(mockPprofer)
	mockGrapher := new(mockGrapher)
	mockVisualizer := new(mockVisualizer)
	commander := &defaultCommander{
		validator:  mockValidator,
		pprofer:    mockPprofer,
		grapher:    mockGrapher,
		visualizer: mockVisualizer,
	}

	samplePprofOutput := []byte("out")
	mockValidator.On("validateArgument", "torch.svg", `\w+\.svg`,
		"Output file name must be .svg").Return(nil).Once()
	mockPprofer.On("runPprofCommand", []string{"-seconds", "30", "http://localhost/hi"}).Return(samplePprofOutput, nil).Once()
	mockGrapher.On("GraphAsText", samplePprofOutput).Return("1;2;3 3", nil).Once()

	createSampleContextForRaw(commander)

	mockValidator.AssertExpectations(t)
	mockPprofer.AssertExpectations(t)
	mockGrapher.AssertExpectations(t)
	mockVisualizer.AssertExpectations(t) // ensure that mockVisualizer was never called
}

func TestGoTorchCommandBinaryInput(t *testing.T) {
	mockValidator := new(mockValidator)
	mockPprofer := new(mockPprofer)
	mockGrapher := new(mockGrapher)
	mockVisualizer := new(mockVisualizer)
	commander := &defaultCommander{
		validator:  mockValidator,
		pprofer:    mockPprofer,
		grapher:    mockGrapher,
		visualizer: mockVisualizer,
	}

	samplePprofOutput := []byte("out")
	mockValidator.On("validateArgument", "torch.svg", `\w+\.svg`,
		"Output file name must be .svg").Return(nil).Once()
	mockPprofer.On("runPprofCommand", []string{"/path/to/binary/file", "/path/to/binary/input"}).Return(samplePprofOutput, nil).Once()
	mockGrapher.On("GraphAsText", samplePprofOutput).Return("1;2;3 3", nil).Once()
	mockVisualizer.On("GenerateFlameGraph", "1;2;3 3", "torch.svg", false).Return(nil).Once()

	createSampleContextForBinaryInput(commander)

	mockValidator.AssertExpectations(t)
	mockPprofer.AssertExpectations(t)
	mockGrapher.AssertExpectations(t)
	mockVisualizer.AssertExpectations(t)
}

func TestValidateArgumentFail(t *testing.T) {
	validator := new(defaultValidator)
	assert.Error(t, validator.validateArgument("bad bad", `\w+\.svg`, "Message"))
}

func TestValidateArgumentPass(t *testing.T) {
	assert.NotPanics(t, func() {
		new(defaultValidator).validateArgument("good.svg", `\w+\.svg`, "Message")
	})
}

func TestRunPprofCommand(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	pprofer := defaultPprofer{
		osWrapper: mockOSWrapper,
	}

	mockOSWrapper.On("cmdOutput", mock.AnythingOfType("*exec.Cmd")).Return([]byte("output"), nil).Once()

	sampleArgs := []string{"-seconds", "15", "http://localhost:8080"}
	out, err := pprofer.runPprofCommand(sampleArgs...)

	assert.Equal(t, []byte("output"), out)
	assert.NoError(t, err)
	mockOSWrapper.AssertExpectations(t)
}

func TestRunPprofCommandUnderlyingError(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	pprofer := defaultPprofer{
		osWrapper: mockOSWrapper,
	}

	mockOSWrapper.On("cmdOutput", mock.AnythingOfType("*exec.Cmd")).Return(nil, errors.New("pprof underlying error")).Once()

	sampleArgs := []string{"-seconds", "15", "http://localhost:8080"}
	out, err := pprofer.runPprofCommand(sampleArgs...)

	assert.Equal(t, 0, len(out))
	assert.Error(t, err)
	mockOSWrapper.AssertExpectations(t)
}

// 'go tool pprof' doesn't exit on errors with nonzero status codes. This test
// ensures that go-torch will detect undrlying errors despite the pprof bug.
// See pprof issue here https://github.com/golang/go/issues/11510
func TestRunPprofCommandHandlePprofErrorBug(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	pprofer := defaultPprofer{
		osWrapper: mockOSWrapper,
	}

	mockOSWrapper.On("cmdOutput", mock.AnythingOfType("*exec.Cmd")).Return([]byte{}, nil).Once()

	sampleArgs := []string{"-seconds", "15", "http://localhost:8080"}
	out, err := pprofer.runPprofCommand(sampleArgs...)

	assert.Equal(t, 0, len(out))
	assert.Error(t, err)
	mockOSWrapper.AssertExpectations(t)
}

func TestNewTorcher(t *testing.T) {
	assert.NotNil(t, newTorcher())
}

func TestNewCommander(t *testing.T) {
	assert.NotNil(t, newCommander())
}

func createSampleContext(commander *defaultCommander) {
	app := cli.NewApp()
	app.Name = "go-torch"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "url, u",
			Value: "http://localhost",
		},
		cli.StringFlag{
			Name:  "suffix, s",
			Value: "/hi",
		},
		cli.IntFlag{
			Name:  "time, t",
			Value: 30,
		},
		cli.StringFlag{
			Name:  "file, f",
			Value: "torch.svg",
		},
	}
	app.Action = commander.goTorchCommand
	app.Run([]string{"go-torch"})
}

func createSampleContextForRaw(commander *defaultCommander) {
	app := cli.NewApp()
	app.Name = "go-torch"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "url, u",
			Value: "http://localhost",
		},
		cli.StringFlag{
			Name:  "suffix, s",
			Value: "/hi",
		},
		cli.IntFlag{
			Name:  "time, t",
			Value: 30,
		},
		cli.StringFlag{
			Name:  "file, f",
			Value: "torch.svg",
		},
		cli.BoolTFlag{
			Name: "raw, r",
		},
	}
	app.Action = commander.goTorchCommand
	app.Run([]string{"go-torch"})
}

func createSampleContextForBinaryInput(commander *defaultCommander) {
	app := cli.NewApp()
	app.Name = "go-torch"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "url, u",
			Value: "http://localhost",
		},
		cli.StringFlag{
			Name:  "suffix, s",
			Value: "/hi",
		},
		cli.StringFlag{
			Name:  "binaryinput, b",
			Value: "/path/to/binary/input",
		},
		cli.StringFlag{
			Name:  "binaryname",
			Value: "/path/to/binary/file",
		},
		cli.IntFlag{
			Name:  "time, t",
			Value: 30,
		},
		cli.StringFlag{
			Name:  "file, f",
			Value: "torch.svg",
		},
	}
	app.Action = commander.goTorchCommand
	app.Run([]string{"go-torch"})
}
<commit_msg>Add test for trailing slash in url<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"errors"
	"testing"

	"github.com/codegangsta/cli"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

func TestCreateAndRunApp(t *testing.T) {
	mockCommander := new(mockCommander)
	torcher := &torcher{
		commander: mockCommander,
	}

	var validateContext = func(args mock.Arguments) {
		context := args.Get(0).(*cli.Context)
		assert.NotNil(t, context)
		assert.Equal(t, "go-torch", context.App.Name)
	}
	mockCommander.On("goTorchCommand", mock.AnythingOfType("*cli.Context")).Return().Run(validateContext).Once()

	torcher.createAndRunApp()
}

func TestCreateAndRunAppDefaultValues(t *testing.T) {
	mockCommander := new(mockCommander)
	torcher := &torcher{
		commander: mockCommander,
	}

	validateDefaults := func(args mock.Arguments) {
		context := args.Get(0).(*cli.Context)
		assert.Equal(t, 30, context.Int("time"))
		assert.Equal(t, "http://localhost:8080", context.String("url"))
		assert.Equal(t, "/debug/pprof/profile", context.String("suffix"))
		assert.Equal(t, "torch.svg", context.String("file"))
		assert.Equal(t, "", context.String("binaryinput"))
		assert.Equal(t, "", context.String("binaryname"))
		assert.Equal(t, false, context.Bool("print"))
		assert.Equal(t, false, context.Bool("raw"))
		assert.Equal(t, 10, len(context.App.Flags))
	}
	mockCommander.On("goTorchCommand", mock.AnythingOfType(
		"*cli.Context")).Return().Run(validateDefaults)

	torcher.createAndRunApp()
}

func testGoTorchCommand(t *testing.T, url string) {
	mockValidator := new(mockValidator)
	mockPprofer := new(mockPprofer)
	mockGrapher := new(mockGrapher)
	mockVisualizer := new(mockVisualizer)
	commander := &defaultCommander{
		validator:  mockValidator,
		pprofer:    mockPprofer,
		grapher:    mockGrapher,
		visualizer: mockVisualizer,
	}

	samplePprofOutput := []byte("out")

	mockValidator.On("validateArgument", "torch.svg", `\w+\.svg`,
		"Output file name must be .svg").Return(nil).Once()
	mockPprofer.On("runPprofCommand", []string{"-seconds", "30", "http://localhost/hi"}).Return(samplePprofOutput, nil).Once()
	mockGrapher.On("GraphAsText", samplePprofOutput).Return("1;2;3 3", nil).Once()
	mockVisualizer.On("GenerateFlameGraph", "1;2;3 3", "torch.svg", false).Return(nil).Once()

	createSampleContext(commander, url)

	mockValidator.AssertExpectations(t)
	mockPprofer.AssertExpectations(t)
	mockGrapher.AssertExpectations(t)
	mockVisualizer.AssertExpectations(t)
}

func TestGoTorchCommand(t *testing.T) {
	testGoTorchCommand(t, "http://localhost")

	// Trailing slash in url should still work.
	testGoTorchCommand(t, "http://localhost/")
}

func TestGoTorchCommandRawOutput(t *testing.T) {
	mockValidator := new(mockValidator)
	mockPprofer := new(mockPprofer)
	mockGrapher := new(mockGrapher)
	mockVisualizer := new(mockVisualizer)
	commander := &defaultCommander{
		validator:  mockValidator,
		pprofer:    mockPprofer,
		grapher:    mockGrapher,
		visualizer: mockVisualizer,
	}

	samplePprofOutput := []byte("out")
	mockValidator.On("validateArgument", "torch.svg", `\w+\.svg`,
		"Output file name must be .svg").Return(nil).Once()
	mockPprofer.On("runPprofCommand", []string{"-seconds", "30", "http://localhost/hi"}).Return(samplePprofOutput, nil).Once()
	mockGrapher.On("GraphAsText", samplePprofOutput).Return("1;2;3 3", nil).Once()

	createSampleContextForRaw(commander)

	mockValidator.AssertExpectations(t)
	mockPprofer.AssertExpectations(t)
	mockGrapher.AssertExpectations(t)
	mockVisualizer.AssertExpectations(t) // ensure that mockVisualizer was never called
}

func TestGoTorchCommandBinaryInput(t *testing.T) {
	mockValidator := new(mockValidator)
	mockPprofer := new(mockPprofer)
	mockGrapher := new(mockGrapher)
	mockVisualizer := new(mockVisualizer)
	commander := &defaultCommander{
		validator:  mockValidator,
		pprofer:    mockPprofer,
		grapher:    mockGrapher,
		visualizer: mockVisualizer,
	}

	samplePprofOutput := []byte("out")
	mockValidator.On("validateArgument", "torch.svg", `\w+\.svg`,
		"Output file name must be .svg").Return(nil).Once()
	mockPprofer.On("runPprofCommand", []string{"/path/to/binary/file", "/path/to/binary/input"}).Return(samplePprofOutput, nil).Once()
	mockGrapher.On("GraphAsText", samplePprofOutput).Return("1;2;3 3", nil).Once()
	mockVisualizer.On("GenerateFlameGraph", "1;2;3 3", "torch.svg", false).Return(nil).Once()

	createSampleContextForBinaryInput(commander)

	mockValidator.AssertExpectations(t)
	mockPprofer.AssertExpectations(t)
	mockGrapher.AssertExpectations(t)
	mockVisualizer.AssertExpectations(t)
}

func TestValidateArgumentFail(t *testing.T) {
	validator := new(defaultValidator)
	assert.Error(t, validator.validateArgument("bad bad", `\w+\.svg`, "Message"))
}

func TestValidateArgumentPass(t *testing.T) {
	assert.NotPanics(t, func() {
		new(defaultValidator).validateArgument("good.svg", `\w+\.svg`, "Message")
	})
}

func TestRunPprofCommand(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	pprofer := defaultPprofer{
		osWrapper: mockOSWrapper,
	}

	mockOSWrapper.On("cmdOutput", mock.AnythingOfType("*exec.Cmd")).Return([]byte("output"), nil).Once()

	sampleArgs := []string{"-seconds", "15", "http://localhost:8080"}
	out, err := pprofer.runPprofCommand(sampleArgs...)

	assert.Equal(t, []byte("output"), out)
	assert.NoError(t, err)
	mockOSWrapper.AssertExpectations(t)
}

func TestRunPprofCommandUnderlyingError(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	pprofer := defaultPprofer{
		osWrapper: mockOSWrapper,
	}

	mockOSWrapper.On("cmdOutput", mock.AnythingOfType("*exec.Cmd")).Return(nil, errors.New("pprof underlying error")).Once()

	sampleArgs := []string{"-seconds", "15", "http://localhost:8080"}
	out, err := pprofer.runPprofCommand(sampleArgs...)

	assert.Equal(t, 0, len(out))
	assert.Error(t, err)
	mockOSWrapper.AssertExpectations(t)
}

// 'go tool pprof' doesn't exit on errors with nonzero status codes. This test
// ensures that go-torch will detect undrlying errors despite the pprof bug.
// See pprof issue here https://github.com/golang/go/issues/11510
func TestRunPprofCommandHandlePprofErrorBug(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	pprofer := defaultPprofer{
		osWrapper: mockOSWrapper,
	}

	mockOSWrapper.On("cmdOutput", mock.AnythingOfType("*exec.Cmd")).Return([]byte{}, nil).Once()

	sampleArgs := []string{"-seconds", "15", "http://localhost:8080"}
	out, err := pprofer.runPprofCommand(sampleArgs...)

	assert.Equal(t, 0, len(out))
	assert.Error(t, err)
	mockOSWrapper.AssertExpectations(t)
}

func TestNewTorcher(t *testing.T) {
	assert.NotNil(t, newTorcher())
}

func TestNewCommander(t *testing.T) {
	assert.NotNil(t, newCommander())
}

func createSampleContext(commander *defaultCommander, url string) {
	app := cli.NewApp()
	app.Name = "go-torch"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "url, u",
			Value: url,
		},
		cli.StringFlag{
			Name:  "suffix, s",
			Value: "/hi",
		},
		cli.IntFlag{
			Name:  "time, t",
			Value: 30,
		},
		cli.StringFlag{
			Name:  "file, f",
			Value: "torch.svg",
		},
	}
	app.Action = commander.goTorchCommand
	app.Run([]string{"go-torch"})
}

func createSampleContextForRaw(commander *defaultCommander) {
	app := cli.NewApp()
	app.Name = "go-torch"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "url, u",
			Value: "http://localhost",
		},
		cli.StringFlag{
			Name:  "suffix, s",
			Value: "/hi",
		},
		cli.IntFlag{
			Name:  "time, t",
			Value: 30,
		},
		cli.StringFlag{
			Name:  "file, f",
			Value: "torch.svg",
		},
		cli.BoolTFlag{
			Name: "raw, r",
		},
	}
	app.Action = commander.goTorchCommand
	app.Run([]string{"go-torch"})
}

func createSampleContextForBinaryInput(commander *defaultCommander) {
	app := cli.NewApp()
	app.Name = "go-torch"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "url, u",
			Value: "http://localhost",
		},
		cli.StringFlag{
			Name:  "suffix, s",
			Value: "/hi",
		},
		cli.StringFlag{
			Name:  "binaryinput, b",
			Value: "/path/to/binary/input",
		},
		cli.StringFlag{
			Name:  "binaryname",
			Value: "/path/to/binary/file",
		},
		cli.IntFlag{
			Name:  "time, t",
			Value: 30,
		},
		cli.StringFlag{
			Name:  "file, f",
			Value: "torch.svg",
		},
	}
	app.Action = commander.goTorchCommand
	app.Run([]string{"go-torch"})
}
<|endoftext|>


<commit_before>package main

import (
	"syscall"
	"testing"
	"time"
)

func TestInterruptThrough(t *testing.T) {
	in := make(ImageCh)
	out := in.interrupt()

	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	select {
	case in <- Image{Score: 1}:
	case <-timeout:
		t.Fatal("Can't image into channel")
	}

	select {
	case tval, ok := <-out:
		if !ok {
			t.Fatal("Out channel is closed prematurely")
		}
		if (tval != Image{Score: 1}) {
			t.Error("Pass through interrupter mangles image")
		}
	default:
		t.Fatal("Interrupter blocks")
	}
}

func TestInterruptSequence(t *testing.T) {
	in := make(ImageCh)
	out := in.interrupt()

	in <- Image{Score: 1}
	<-out

	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	select {
	case in <- Image{Faves: 1}:
	case <-timeout:
		t.Fatal("Can't push second image into channel")
	}

	select {
	case tval, ok := <-out:
		if !ok {
			t.Fatal("Out channel is closed prematurely")
		}
		if (tval != Image{Faves: 1}) {
			t.Error("Second pass through interrupter mangles image")
		}
	default:
		t.Fatal("Interrupter blocks on second image")
	}
}

func TestInterruptSignal(t *testing.T) {
	in := make(ImageCh)
	out := in.interrupt()

	err := syscall.Kill(syscall.Getpid(), syscall.SIGINT)

	if err != nil {
		t.Skip("Can't get pid, skipping")
	}

	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	select {
	case _, ok := <-out:
		if ok {
			t.Error("Channel open and passes data when it should be closed by interrupt")
		}
	case <-timeout:
		t.Skip("Race issue, timing out")
	}
}

func TestInterruptClose(t *testing.T) {
	in := make(ImageCh)
	out := in.interrupt()

	close(in)
	_, ok := <-out
	if ok {
		t.Error("Channel open and passes data when it should be closed by end of input")
	}
}
<commit_msg>Part of issue #28, TestInterruptClose irrepairably breaks program state<commit_after>package main

import (
	"syscall"
	"testing"
	"time"
)

func TestInterruptThrough(t *testing.T) {
	in := make(ImageCh)
	out := in.interrupt()

	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	select {
	case in <- Image{Score: 1}:
	case <-timeout:
		t.Fatal("Can't image into channel")
	}

	select {
	case tval, ok := <-out:
		if !ok {
			t.Fatal("Out channel is closed prematurely")
		}
		if (tval != Image{Score: 1}) {
			t.Error("Pass through interrupter mangles image")
		}
	default:
		t.Fatal("Interrupter blocks")
	}
}

func TestInterruptSequence(t *testing.T) {
	in := make(ImageCh)
	out := in.interrupt()

	in <- Image{Score: 1}
	<-out

	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	select {
	case in <- Image{Faves: 1}:
	case <-timeout:
		t.Fatal("Can't push second image into channel")
	}

	select {
	case tval, ok := <-out:
		if !ok {
			t.Fatal("Out channel is closed prematurely")
		}
		if (tval != Image{Faves: 1}) {
			t.Error("Second pass through interrupter mangles image")
		}
	default:
		t.Fatal("Interrupter blocks on second image")
	}
}

func TestInterruptClose(t *testing.T) {
	in := make(ImageCh)
	out := in.interrupt()

	close(in)
	_, ok := <-out
	if ok {
		t.Error("Channel open and passes data when it should be closed by end of input")
	}
}

func TestInterruptSignal(t *testing.T) {
	in := make(ImageCh)
	out := in.interrupt()

	err := syscall.Kill(syscall.Getpid(), syscall.SIGINT)

	if err != nil {
		t.Skip("Can't get pid, skipping")
	}

	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	select {
	case _, ok := <-out:
		if ok {
			t.Error("Channel open and passes data when it should be closed by interrupt")
		}
	case <-timeout:
		t.Skip("Race issue, timing out")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"testing"

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

const (
	unknownAsk = "unknown option asked for"
)

type MockClientContext struct{}

func (m MockClientContext) String(ask string) string {
	switch ask {
	case "exchange":
		return "delayd-test"
	case "key":
		return "delayd-key"
	case "file":
		return "tests/in.txt"
	case "out":
		return "tests/out.txt"
	case "config":
		return "delayd.toml"
	default:
		panic(unknownAsk)
	}
}

func (m MockClientContext) Bool(ask string) bool {
	switch ask {
	case "repl":
		return false
	default:
		panic(unknownAsk)
	}
}

func (m MockClientContext) Int(ask string) int {
	switch ask {
	case "delay":
		return 50
	default:
		panic(unknownAsk)
	}
}

func getFileAsString(path string) string {
	dat, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	return string(dat[:])
}

func cleanup(path string) {
	err := os.Remove(path)
	if err != nil {
		panic(err)
	}
}

func TestInAndOut(t *testing.T) {
	m := MockClientContext{}
	conf, err := loadConfig(m)

	// travis can't make a dir under /var/lib, but we can just put it
	// in its home dir
	if os.Getenv("TRAVIS") != "" {
		conf.DataDir = "delayd"
	}

	if err != nil {
		panic(err)
	}

	s := Server{}
	go s.Run(conf)

	c, err := NewClient(m)
	if err != nil {
		panic(err)
	}

	c.Run(conf)
	c.Stop()
	s.Stop()

	f1 := getFileAsString("tests/in.txt")
	f2 := getFileAsString("tests/out.txt")

	assert.Equal(t, f1, f2)

	cleanup("tests/out.txt")
}
<commit_msg>Add no-wait to mock config<commit_after>package main

import (
	"io/ioutil"
	"os"
	"testing"

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

const (
	unknownAsk = "unknown option asked for"
)

type MockClientContext struct{}

func (m MockClientContext) String(ask string) string {
	switch ask {
	case "exchange":
		return "delayd-test"
	case "key":
		return "delayd-key"
	case "file":
		return "tests/in.txt"
	case "out":
		return "tests/out.txt"
	case "config":
		return "delayd.toml"
	default:
		panic(unknownAsk)
	}
}

func (m MockClientContext) Bool(ask string) bool {
	switch ask {
	case "repl":
		return false
	case "no-wait":
		return false
	default:
		panic(unknownAsk)
	}
}

func (m MockClientContext) Int(ask string) int {
	switch ask {
	case "delay":
		return 50
	default:
		panic(unknownAsk)
	}
}

func getFileAsString(path string) string {
	dat, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	return string(dat[:])
}

func cleanup(path string) {
	err := os.Remove(path)
	if err != nil {
		panic(err)
	}
}

func TestInAndOut(t *testing.T) {
	m := MockClientContext{}
	conf, err := loadConfig(m)

	// travis can't make a dir under /var/lib, but we can just put it
	// in its home dir
	if os.Getenv("TRAVIS") != "" {
		conf.DataDir = "delayd"
	}

	if err != nil {
		panic(err)
	}

	s := Server{}
	go s.Run(conf)

	c, err := NewClient(m)
	if err != nil {
		panic(err)
	}

	c.Run(conf)
	c.Stop()
	s.Stop()

	f1 := getFileAsString("tests/in.txt")
	f2 := getFileAsString("tests/out.txt")

	assert.Equal(t, f1, f2)

	cleanup("tests/out.txt")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"testing"

	mylog "github.com/patrickalin/GoMyLog"
	"github.com/spf13/viper"
)

func TestSomething(t *testing.T) {
	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	if err := viper.ReadInConfig(); err != nil {
		fmt.Printf("%v", err)
	}
}
func TestMain(m *testing.M) {
	//i18n.MustLoadTranslationFile("lang/en-US.all.json")
	//i18n.MustLoadTranslationFile("lang/fr.all.json")
	mylog.Init(mylog.ERROR)

	os.Exit(m.Run())
}

func TestReadConfigFound(t *testing.T) {
	if err := readConfig("configForTest"); err != nil {
		fmt.Printf("%v", err)
	}
}

/*func TestReadConfigNotFound(t *testing.T) {
	if err := readConfig("configError"); err != nil {
		fmt.Printf("%v", err)
	}
}*/
<commit_msg>Error in test<commit_after>package main

import (
	"fmt"
	"os"
	"testing"

	"github.com/nicksnyder/go-i18n/i18n"
	mylog "github.com/patrickalin/GoMyLog"
	"github.com/spf13/viper"
)

func TestSomething(t *testing.T) {
	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	if err := viper.ReadInConfig(); err != nil {
		fmt.Printf("%v", err)
	}
}
func TestMain(m *testing.M) {
	i18n.MustLoadTranslationFile("lang/en-US.all.json")
	i18n.MustLoadTranslationFile("lang/fr.all.json")
	mylog.Init(mylog.ERROR)

	os.Exit(m.Run())
}

func TestReadConfigFound(t *testing.T) {
	if err := readConfig("configForTest"); err != nil {
		fmt.Printf("%v", err)
	}
}

/*func TestReadConfigNotFound(t *testing.T) {
	if err := readConfig("configError"); err != nil {
		fmt.Printf("%v", err)
	}
}*/
<|endoftext|>