<commit_before>// (c) Rick Arnold. Licensed under the BSD license (see LICENSE).

// Package ie provides holiday definitions for Brazil.
package br

import (
	"time"

	"github.com/rickar/cal/v2"
	"github.com/rickar/cal/v2/aa"
)

var (
	// AnoNovo represents New Year's Day on 1-Jan
	AnoNovo = aa.NewYear.Clone(&cal.Holiday{Name: "Ano Novo", Type: cal.ObservancePublic})

	// Tiradentes represents Tiradentes' Day on 21-Apr
	Tiradentes = &cal.Holiday{
		Name:  "Dia de Tiradentes",
		Month: time.April,
		Day:   21,
		Func:  cal.CalcDayOfMonth,
	}

	// Trabalhador represents Labor Day on 21-Apr
	Trabalhador = aa.WorkersDay.Clone(&cal.Holiday{Name: "Dia do Trabalhador", Type: cal.ObservancePublic})

	// Independencia represents Brazil Independence Day on 07-Sep
	Independencia = &cal.Holiday{
		Name:  "Dia da Independência",
		Month: time.September,
		Day:   7,
		Func:  cal.CalcDayOfMonth,
	}

	// NossaSenhoraAparecida represents Our Lady of Aparecida Day - Patroness of Brazil on 12-Oct
	NossaSenhoraAparecida = &cal.Holiday{
		Name:  "Dia de Nossa Senhora Aparecida",
		Month: time.October,
		Day:   12,
		Func:  cal.CalcDayOfMonth,
	}

	// Finados represents Day of the Dead on 02-Nov
	Finados = &cal.Holiday{
		Name:  "Dia de Finados",
		Month: time.November,
		Day:   2,
		Func:  cal.CalcDayOfMonth,
	}

	// Republica represents Proclamation of the Republic on 15-Nov
	Republica = &cal.Holiday{
		Name:  "Proclamação da República",
		Month: time.November,
		Day:   15,
		Func:  cal.CalcDayOfMonth,
	}

	// CorpusChristi represents Corpus Christi on the 60th day after Easter
	CorpusChristi = aa.CorpusChristi.Clone(&cal.Holiday{})

	// SextaFeiraSanta represents Good Friday - two days before Easter
	SextaFeiraSanta = aa.GoodFriday.Clone(&cal.Holiday{Name: "Sexta-feira Santa", Type: cal.ObservancePublic})

	// Carnaval represents Brazilian Carnival - 47 days before Easter
	Carnaval = &cal.Holiday{
		Name:   "Carnaval",
		Type:   cal.ObservancePublic,
		Offset: -47,
		Func:   cal.CalcEasterOffset,
	}

	// Natal represents Christmas Day on 25-Dec
	Natal = aa.ChristmasDay.Clone(&cal.Holiday{Name: "Natal", Type: cal.ObservancePublic})

	// Holidays provides a list of the standard national holidays
	Holidays = []*cal.Holiday{
		AnoNovo,
		Tiradentes,
		Trabalhador,
		Independencia,
		NossaSenhoraAparecida,
		Finados,
		Republica,
		CorpusChristi,
		SextaFeiraSanta,
		Carnaval,
		Natal,
	}
)
<commit_msg>fix: adding official holiday names in Brazil<commit_after>// (c) Rick Arnold. Licensed under the BSD license (see LICENSE).

// Package ie provides holiday definitions for Brazil.
package br

import (
	"time"

	"github.com/rickar/cal/v2"
	"github.com/rickar/cal/v2/aa"
)

var (
	// AnoNovo represents New Year's Day on 1-Jan
	AnoNovo = aa.NewYear.Clone(&cal.Holiday{Name: "Ano Novo", Type: cal.ObservancePublic})

	// Tiradentes represents Tiradentes' Day on 21-Apr
	Tiradentes = &cal.Holiday{
		Name:  "Tiradentes",
		Month: time.April,
		Day:   21,
		Func:  cal.CalcDayOfMonth,
	}

	// Trabalhador represents Labor Day on 21-Apr
	Trabalhador = aa.WorkersDay.Clone(&cal.Holiday{Name: "Dia do Trabalhador", Type: cal.ObservancePublic})

	// Independencia represents Brazil Independence Day on 07-Sep
	Independencia = &cal.Holiday{
		Name:  "Independência do Brasil",
		Month: time.September,
		Day:   7,
		Func:  cal.CalcDayOfMonth,
	}

	// NossaSenhoraAparecida represents Our Lady of Aparecida Day - Patroness of Brazil on 12-Oct
	NossaSenhoraAparecida = &cal.Holiday{
		Name:  "Nossa Senhora Aparecida",
		Month: time.October,
		Day:   12,
		Func:  cal.CalcDayOfMonth,
	}

	// Finados represents Day of the Dead on 02-Nov
	Finados = &cal.Holiday{
		Name:  "Finados",
		Month: time.November,
		Day:   2,
		Func:  cal.CalcDayOfMonth,
	}

	// Republica represents Proclamation of the Republic on 15-Nov
	Republica = &cal.Holiday{
		Name:  "Proclamação da República",
		Month: time.November,
		Day:   15,
		Func:  cal.CalcDayOfMonth,
	}

	// CorpusChristi represents Corpus Christi on the 60th day after Easter
	CorpusChristi = aa.CorpusChristi.Clone(&cal.Holiday{Name: "Corpus Christi", Type: cal.ObservancePublic})

	// SextaFeiraSanta represents Good Friday - two days before Easter
	SextaFeiraSanta = aa.GoodFriday.Clone(&cal.Holiday{Name: "Sexta-feira Santa", Type: cal.ObservancePublic})

	// Carnaval represents Brazilian Carnival - 47 days before Easter
	Carnaval = &cal.Holiday{
		Name:   "Carnaval",
		Type:   cal.ObservancePublic,
		Offset: -47,
		Func:   cal.CalcEasterOffset,
	}

	// Natal represents Christmas Day on 25-Dec
	Natal = aa.ChristmasDay.Clone(&cal.Holiday{Name: "Natal", Type: cal.ObservancePublic})

	// Holidays provides a list of the standard national holidays
	Holidays = []*cal.Holiday{
		AnoNovo,
		Tiradentes,
		Trabalhador,
		Independencia,
		NossaSenhoraAparecida,
		Finados,
		Republica,
		CorpusChristi,
		SextaFeiraSanta,
		Carnaval,
		Natal,
	}
)
<|endoftext|>


<commit_before>package i18n

import (
	"fmt"
	"text/template"

	"github.com/nicksnyder/go-i18n/v2/internal/plural"
	"golang.org/x/text/language"
)

// Localizer provides Localize and MustLocalize methods that return localized messages.
type Localizer struct {
	// bundle contains the messages that can be returned by the Localizer.
	bundle *Bundle

	// tags is the list of language tags that the Localizer checks
	// in order when localizing a message.
	tags []language.Tag
}

// NewLocalizer returns a new Localizer that looks up messages
// in the bundle according to the language preferences in langs.
// It can parse Accept-Language headers as defined in http://www.ietf.org/rfc/rfc2616.txt.
func NewLocalizer(bundle *Bundle, langs ...string) *Localizer {
	return &Localizer{
		bundle: bundle,
		tags:   parseTags(langs),
	}
}

func parseTags(langs []string) []language.Tag {
	tags := []language.Tag{}
	for _, lang := range langs {
		t, _, err := language.ParseAcceptLanguage(lang)
		if err != nil {
			continue
		}
		tags = append(tags, t...)
	}
	return tags
}

// LocalizeConfig configures a call to the Localize method on Localizer.
type LocalizeConfig struct {
	// MessageID is the id of the message to lookup.
	// This field is ignored if DefaultMessage is set.
	MessageID string

	// TemplateData is the data passed when executing the message's template.
	// If TemplateData is nil and PluralCount is not nil, then the message template
	// will be executed with data that contains the plural count.
	TemplateData interface{}

	// PluralCount determines which plural form of the message is used.
	PluralCount interface{}

	// DefaultMessage is used if the message is not found in any message files.
	DefaultMessage *Message

	// Funcs is used to extend the Go template engine's built in functions
	Funcs template.FuncMap
}

type invalidPluralCountErr struct {
	messageID   string
	pluralCount interface{}
	err         error
}

func (e *invalidPluralCountErr) Error() string {
	return fmt.Sprintf("invalid plural count %#v for message id %q: %s", e.pluralCount, e.messageID, e.err)
}

// MessageNotFoundErr is returned from Localize when a message could not be found.
type MessageNotFoundErr struct {
	tag       language.Tag
	messageID string
}

func (e *MessageNotFoundErr) Error() string {
	return fmt.Sprintf("message %q not found in language %q", e.messageID, e.tag)
}

type pluralizeErr struct {
	messageID string
	tag       language.Tag
}

func (e *pluralizeErr) Error() string {
	return fmt.Sprintf("unable to pluralize %q because there no plural rule for %q", e.messageID, e.tag)
}

type messageIDMismatchErr struct {
	messageID        string
	defaultMessageID string
}

func (e *messageIDMismatchErr) Error() string {
	return fmt.Sprintf("message id %q does not match default message id %q", e.messageID, e.defaultMessageID)
}

// Localize returns a localized message.
func (l *Localizer) Localize(lc *LocalizeConfig) (string, error) {
	msg, _, err := l.LocalizeWithTag(lc)
	return msg, err
}

// Localize returns a localized message.
func (l *Localizer) LocalizeMessage(msg *Message) (string, error) {
	return l.Localize(&LocalizeConfig{
		DefaultMessage: msg,
	})
}

// TODO: uncomment this (and the test) when extract has been updated to extract these call sites too.
// Localize returns a localized message.
// func (l *Localizer) LocalizeMessageID(messageID string) (string, error) {
// 	return l.Localize(&LocalizeConfig{
// 		MessageID: messageID,
// 	})
// }

// LocalizeWithTag returns a localized message and the language tag.
// It may return a best effort localized message even if an error happens.
func (l *Localizer) LocalizeWithTag(lc *LocalizeConfig) (string, language.Tag, error) {
	messageID := lc.MessageID
	if lc.DefaultMessage != nil {
		if messageID != "" && messageID != lc.DefaultMessage.ID {
			return "", language.Und, &messageIDMismatchErr{messageID: messageID, defaultMessageID: lc.DefaultMessage.ID}
		}
		messageID = lc.DefaultMessage.ID
	}

	var operands *plural.Operands
	templateData := lc.TemplateData
	if lc.PluralCount != nil {
		var err error
		operands, err = plural.NewOperands(lc.PluralCount)
		if err != nil {
			return "", language.Und, &invalidPluralCountErr{messageID: messageID, pluralCount: lc.PluralCount, err: err}
		}
		if templateData == nil {
			templateData = map[string]interface{}{
				"PluralCount": lc.PluralCount,
			}
		}
	}

	tag, template, err := l.getMessageTemplate(messageID, lc.DefaultMessage)
	if template == nil {
		return "", language.Und, err
	}

	pluralForm := l.pluralForm(tag, operands)
	msg, err2 := template.Execute(pluralForm, templateData, lc.Funcs)
	if err2 != nil {
		if err == nil {
			err = err2
		}

		// Attempt to fallback to "Other" pluralization in case translations are incomplete.
		if pluralForm != plural.Other {
			msg2, err3 := template.Execute(plural.Other, templateData, lc.Funcs)
			if err3 == nil {
				msg = msg2
			}
		}
	}
	return msg, tag, err
}

func (l *Localizer) getMessageTemplate(id string, defaultMessage *Message) (language.Tag, *MessageTemplate, error) {
	_, i, _ := l.bundle.matcher.Match(l.tags...)
	tag := l.bundle.tags[i]
	mt := l.bundle.getMessageTemplate(tag, id)
	if mt != nil {
		return tag, mt, nil
	}

	if tag == l.bundle.defaultLanguage {
		if defaultMessage == nil {
			return language.Und, nil, &MessageNotFoundErr{tag: tag, messageID: id}
		}
		return tag, NewMessageTemplate(defaultMessage), nil
	}

	// Fallback to default language in bundle.
	mt = l.bundle.getMessageTemplate(l.bundle.defaultLanguage, id)
	if mt != nil {
		return l.bundle.defaultLanguage, mt, &MessageNotFoundErr{tag: tag, messageID: id}
	}

	// Fallback to default message.
	if defaultMessage == nil {
		return language.Und, nil, &MessageNotFoundErr{tag: tag, messageID: id}
	}
	return l.bundle.defaultLanguage, NewMessageTemplate(defaultMessage), &MessageNotFoundErr{tag: tag, messageID: id}
}

func (l *Localizer) pluralForm(tag language.Tag, operands *plural.Operands) plural.Form {
	if operands == nil {
		return plural.Other
	}
	return l.bundle.pluralRules.Rule(tag).PluralFormFunc(operands)
}

// MustLocalize is similar to Localize, except it panics if an error happens.
func (l *Localizer) MustLocalize(lc *LocalizeConfig) string {
	localized, err := l.Localize(lc)
	if err != nil {
		panic(err)
	}
	return localized
}
<commit_msg>doc(localizer): add specification about language tag detection (#270)<commit_after>package i18n

import (
	"fmt"
	"text/template"

	"github.com/nicksnyder/go-i18n/v2/internal/plural"
	"golang.org/x/text/language"
)

// Localizer provides Localize and MustLocalize methods that return localized messages.
// Localize and MustLocalize methods use a language.Tag matching algorithm based
// on the best possible value. This algorithm may cause an unexpected language.Tag returned
// value depending on the order of the tags stored in memory. For example, if the bundle
// used to create a Localizer instance ingested locales following this order
// ["en-US", "en-GB", "en-IE", "en"] and the locale "en" is asked, the underlying matching
// algorithm will return "en-US" thinking it is the best match possible. More information
// about the algorithm in this Github issue: https://github.com/golang/go/issues/49176.
// There is additionnal informations inside the Go code base:
// https://github.com/golang/text/blob/master/language/match.go#L142
type Localizer struct {
	// bundle contains the messages that can be returned by the Localizer.
	bundle *Bundle

	// tags is the list of language tags that the Localizer checks
	// in order when localizing a message.
	tags []language.Tag
}

// NewLocalizer returns a new Localizer that looks up messages
// in the bundle according to the language preferences in langs.
// It can parse Accept-Language headers as defined in http://www.ietf.org/rfc/rfc2616.txt.
func NewLocalizer(bundle *Bundle, langs ...string) *Localizer {
	return &Localizer{
		bundle: bundle,
		tags:   parseTags(langs),
	}
}

func parseTags(langs []string) []language.Tag {
	tags := []language.Tag{}
	for _, lang := range langs {
		t, _, err := language.ParseAcceptLanguage(lang)
		if err != nil {
			continue
		}
		tags = append(tags, t...)
	}
	return tags
}

// LocalizeConfig configures a call to the Localize method on Localizer.
type LocalizeConfig struct {
	// MessageID is the id of the message to lookup.
	// This field is ignored if DefaultMessage is set.
	MessageID string

	// TemplateData is the data passed when executing the message's template.
	// If TemplateData is nil and PluralCount is not nil, then the message template
	// will be executed with data that contains the plural count.
	TemplateData interface{}

	// PluralCount determines which plural form of the message is used.
	PluralCount interface{}

	// DefaultMessage is used if the message is not found in any message files.
	DefaultMessage *Message

	// Funcs is used to extend the Go template engine's built in functions
	Funcs template.FuncMap
}

type invalidPluralCountErr struct {
	messageID   string
	pluralCount interface{}
	err         error
}

func (e *invalidPluralCountErr) Error() string {
	return fmt.Sprintf("invalid plural count %#v for message id %q: %s", e.pluralCount, e.messageID, e.err)
}

// MessageNotFoundErr is returned from Localize when a message could not be found.
type MessageNotFoundErr struct {
	tag       language.Tag
	messageID string
}

func (e *MessageNotFoundErr) Error() string {
	return fmt.Sprintf("message %q not found in language %q", e.messageID, e.tag)
}

type pluralizeErr struct {
	messageID string
	tag       language.Tag
}

func (e *pluralizeErr) Error() string {
	return fmt.Sprintf("unable to pluralize %q because there no plural rule for %q", e.messageID, e.tag)
}

type messageIDMismatchErr struct {
	messageID        string
	defaultMessageID string
}

func (e *messageIDMismatchErr) Error() string {
	return fmt.Sprintf("message id %q does not match default message id %q", e.messageID, e.defaultMessageID)
}

// Localize returns a localized message.
func (l *Localizer) Localize(lc *LocalizeConfig) (string, error) {
	msg, _, err := l.LocalizeWithTag(lc)
	return msg, err
}

// Localize returns a localized message.
func (l *Localizer) LocalizeMessage(msg *Message) (string, error) {
	return l.Localize(&LocalizeConfig{
		DefaultMessage: msg,
	})
}

// TODO: uncomment this (and the test) when extract has been updated to extract these call sites too.
// Localize returns a localized message.
// func (l *Localizer) LocalizeMessageID(messageID string) (string, error) {
// 	return l.Localize(&LocalizeConfig{
// 		MessageID: messageID,
// 	})
// }

// LocalizeWithTag returns a localized message and the language tag.
// It may return a best effort localized message even if an error happens.
func (l *Localizer) LocalizeWithTag(lc *LocalizeConfig) (string, language.Tag, error) {
	messageID := lc.MessageID
	if lc.DefaultMessage != nil {
		if messageID != "" && messageID != lc.DefaultMessage.ID {
			return "", language.Und, &messageIDMismatchErr{messageID: messageID, defaultMessageID: lc.DefaultMessage.ID}
		}
		messageID = lc.DefaultMessage.ID
	}

	var operands *plural.Operands
	templateData := lc.TemplateData
	if lc.PluralCount != nil {
		var err error
		operands, err = plural.NewOperands(lc.PluralCount)
		if err != nil {
			return "", language.Und, &invalidPluralCountErr{messageID: messageID, pluralCount: lc.PluralCount, err: err}
		}
		if templateData == nil {
			templateData = map[string]interface{}{
				"PluralCount": lc.PluralCount,
			}
		}
	}

	tag, template, err := l.getMessageTemplate(messageID, lc.DefaultMessage)
	if template == nil {
		return "", language.Und, err
	}

	pluralForm := l.pluralForm(tag, operands)
	msg, err2 := template.Execute(pluralForm, templateData, lc.Funcs)
	if err2 != nil {
		if err == nil {
			err = err2
		}

		// Attempt to fallback to "Other" pluralization in case translations are incomplete.
		if pluralForm != plural.Other {
			msg2, err3 := template.Execute(plural.Other, templateData, lc.Funcs)
			if err3 == nil {
				msg = msg2
			}
		}
	}
	return msg, tag, err
}

func (l *Localizer) getMessageTemplate(id string, defaultMessage *Message) (language.Tag, *MessageTemplate, error) {
	_, i, _ := l.bundle.matcher.Match(l.tags...)
	tag := l.bundle.tags[i]
	mt := l.bundle.getMessageTemplate(tag, id)
	if mt != nil {
		return tag, mt, nil
	}

	if tag == l.bundle.defaultLanguage {
		if defaultMessage == nil {
			return language.Und, nil, &MessageNotFoundErr{tag: tag, messageID: id}
		}
		return tag, NewMessageTemplate(defaultMessage), nil
	}

	// Fallback to default language in bundle.
	mt = l.bundle.getMessageTemplate(l.bundle.defaultLanguage, id)
	if mt != nil {
		return l.bundle.defaultLanguage, mt, &MessageNotFoundErr{tag: tag, messageID: id}
	}

	// Fallback to default message.
	if defaultMessage == nil {
		return language.Und, nil, &MessageNotFoundErr{tag: tag, messageID: id}
	}
	return l.bundle.defaultLanguage, NewMessageTemplate(defaultMessage), &MessageNotFoundErr{tag: tag, messageID: id}
}

func (l *Localizer) pluralForm(tag language.Tag, operands *plural.Operands) plural.Form {
	if operands == nil {
		return plural.Other
	}
	return l.bundle.pluralRules.Rule(tag).PluralFormFunc(operands)
}

// MustLocalize is similar to Localize, except it panics if an error happens.
func (l *Localizer) MustLocalize(lc *LocalizeConfig) string {
	localized, err := l.Localize(lc)
	if err != nil {
		panic(err)
	}
	return localized
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/codebuild"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsCodeBuildWebhook() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCodeBuildWebhookCreate,
		Read:   resourceAwsCodeBuildWebhookRead,
		Delete: resourceAwsCodeBuildWebhookDelete,
		Update: resourceAwsCodeBuildWebhookUpdate,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"project_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"branch_filter": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"filter_group": {
				Type:     schema.TypeSet,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"type": {
							Type:     schema.TypeString,
							Required: true,
							ValidateFunc: validation.StringInSlice([]string{
								codebuild.WebhookFilterTypeEvent,
								codebuild.WebhookFilterTypeActorAccountId,
								codebuild.WebhookFilterTypeBaseRef,
								codebuild.WebhookFilterTypeFilePath,
								codebuild.WebhookFilterTypeHeadRef,
							}, false),
						},
						"exclude_matched_pattern": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  false,
						},
						"pattern": {
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
			"payload_url": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"secret": {
				Type:      schema.TypeString,
				Computed:  true,
				Sensitive: true,
			},
			"url": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsCodeBuildWebhookCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codebuildconn

	webhookFilterGroups := expandWebhookFilterGroup(d)

	input := &codebuild.CreateWebhookInput{
		ProjectName:  aws.String(d.Get("project_name").(string)),
		FilterGroups: webhookFilterGroups,
	}

	// The CodeBuild API requires this to be non-empty if defined
	if v, ok := d.GetOk("branch_filter"); ok {
		input.BranchFilter = aws.String(v.(string))
	}

	log.Printf("[DEBUG] Creating CodeBuild Webhook: %s", input)
	resp, err := conn.CreateWebhook(input)

	if err != nil {
		return fmt.Errorf("error creating CodeBuild Webhook: %s", err)
	}

	// Secret is only returned on create, so capture it at the start
	d.Set("secret", resp.Webhook.Secret)
	d.SetId(d.Get("project_name").(string))

	return resourceAwsCodeBuildWebhookRead(d, meta)
}

func expandWebhookFilterGroup(d *schema.ResourceData) [][]*codebuild.WebhookFilter {
	webhookFilters := make([]*codebuild.WebhookFilter, 0)

	configsList := d.Get("filter_group").(*schema.Set).List()

	if len(configsList) == 0 {
		return nil
	}

	for _, config := range configsList {
		filter := expandWebhookFilterData(config.(map[string]interface{}))
		webhookFilters = append(webhookFilters, &filter)
	}

	return [][]*codebuild.WebhookFilter{webhookFilters}
}

func expandWebhookFilterData(data map[string]interface{}) codebuild.WebhookFilter {
	filter := codebuild.WebhookFilter{
		Type:                  aws.String(data["type"].(string)),
		ExcludeMatchedPattern: aws.Bool(data["exclude_matched_pattern"].(bool)),
	}

	if v := data["pattern"]; v != nil {
		filter.Pattern = aws.String(v.(string))
	}

	return filter
}

func resourceAwsCodeBuildWebhookRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codebuildconn

	resp, err := conn.BatchGetProjects(&codebuild.BatchGetProjectsInput{
		Names: []*string{
			aws.String(d.Id()),
		},
	})

	if err != nil {
		return err
	}

	if len(resp.Projects) == 0 {
		log.Printf("[WARN] CodeBuild Project %q not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	project := resp.Projects[0]

	if project.Webhook == nil {
		log.Printf("[WARN] CodeBuild Project %q webhook not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	d.Set("branch_filter", project.Webhook.BranchFilter)
	d.Set("filter_group", project.Webhook.FilterGroups)
	d.Set("payload_url", project.Webhook.PayloadUrl)
	d.Set("project_name", project.Name)
	d.Set("url", project.Webhook.Url)
	// The secret is never returned after creation, so don't set it here

	return nil
}

func resourceAwsCodeBuildWebhookUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codebuildconn

	_, err := conn.UpdateWebhook(&codebuild.UpdateWebhookInput{
		ProjectName:  aws.String(d.Id()),
		BranchFilter: aws.String(d.Get("branch_filter").(string)),
		FilterGroups: expandWebhookFilterGroup(d),
		RotateSecret: aws.Bool(false),
	})

	if err != nil {
		return err
	}

	return resourceAwsCodeBuildWebhookRead(d, meta)
}

func resourceAwsCodeBuildWebhookDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codebuildconn

	_, err := conn.DeleteWebhook(&codebuild.DeleteWebhookInput{
		ProjectName: aws.String(d.Id()),
	})

	if err != nil {
		if isAWSErr(err, codebuild.ErrCodeResourceNotFoundException, "") {
			return nil
		}
		return err
	}

	return nil
}
<commit_msg>Fix webhook update<commit_after>package aws

import (
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/codebuild"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsCodeBuildWebhook() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCodeBuildWebhookCreate,
		Read:   resourceAwsCodeBuildWebhookRead,
		Delete: resourceAwsCodeBuildWebhookDelete,
		Update: resourceAwsCodeBuildWebhookUpdate,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"project_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"branch_filter": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"filter_group": {
				Type:     schema.TypeSet,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"type": {
							Type:     schema.TypeString,
							Required: true,
							ValidateFunc: validation.StringInSlice([]string{
								codebuild.WebhookFilterTypeEvent,
								codebuild.WebhookFilterTypeActorAccountId,
								codebuild.WebhookFilterTypeBaseRef,
								codebuild.WebhookFilterTypeFilePath,
								codebuild.WebhookFilterTypeHeadRef,
							}, false),
						},
						"exclude_matched_pattern": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  false,
						},
						"pattern": {
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
			"payload_url": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"secret": {
				Type:      schema.TypeString,
				Computed:  true,
				Sensitive: true,
			},
			"url": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsCodeBuildWebhookCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codebuildconn

	webhookFilterGroups := expandWebhookFilterGroup(d)

	input := &codebuild.CreateWebhookInput{
		ProjectName:  aws.String(d.Get("project_name").(string)),
		FilterGroups: webhookFilterGroups,
	}

	// The CodeBuild API requires this to be non-empty if defined
	if v, ok := d.GetOk("branch_filter"); ok {
		input.BranchFilter = aws.String(v.(string))
	}

	log.Printf("[DEBUG] Creating CodeBuild Webhook: %s", input)
	resp, err := conn.CreateWebhook(input)

	if err != nil {
		return fmt.Errorf("error creating CodeBuild Webhook: %s", err)
	}

	// Secret is only returned on create, so capture it at the start
	d.Set("secret", resp.Webhook.Secret)
	d.SetId(d.Get("project_name").(string))

	return resourceAwsCodeBuildWebhookRead(d, meta)
}

func expandWebhookFilterGroup(d *schema.ResourceData) [][]*codebuild.WebhookFilter {
	webhookFilters := make([]*codebuild.WebhookFilter, 0)

	configsList := d.Get("filter_group").(*schema.Set).List()

	if len(configsList) == 0 {
		return nil
	}

	for _, config := range configsList {
		filter := expandWebhookFilterData(config.(map[string]interface{}))
		webhookFilters = append(webhookFilters, &filter)
	}

	return [][]*codebuild.WebhookFilter{webhookFilters}
}

func expandWebhookFilterData(data map[string]interface{}) codebuild.WebhookFilter {
	filter := codebuild.WebhookFilter{
		Type:                  aws.String(data["type"].(string)),
		ExcludeMatchedPattern: aws.Bool(data["exclude_matched_pattern"].(bool)),
	}

	if v := data["pattern"]; v != nil {
		filter.Pattern = aws.String(v.(string))
	}

	return filter
}

func resourceAwsCodeBuildWebhookRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codebuildconn

	resp, err := conn.BatchGetProjects(&codebuild.BatchGetProjectsInput{
		Names: []*string{
			aws.String(d.Id()),
		},
	})

	if err != nil {
		return err
	}

	if len(resp.Projects) == 0 {
		log.Printf("[WARN] CodeBuild Project %q not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	project := resp.Projects[0]

	if project.Webhook == nil {
		log.Printf("[WARN] CodeBuild Project %q webhook not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	d.Set("branch_filter", project.Webhook.BranchFilter)
	d.Set("filter_group", project.Webhook.FilterGroups)
	d.Set("payload_url", project.Webhook.PayloadUrl)
	d.Set("project_name", project.Name)
	d.Set("url", project.Webhook.Url)
	// The secret is never returned after creation, so don't set it here

	return nil
}

func resourceAwsCodeBuildWebhookUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codebuildconn

	var err error
	filterGroups := expandWebhookFilterGroup(d)

	if len(filterGroups) >= 1 {
		_, err = conn.UpdateWebhook(&codebuild.UpdateWebhookInput{
			ProjectName:  aws.String(d.Id()),
			FilterGroups: filterGroups,
			RotateSecret: aws.Bool(false),
		})
	} else {
		_, err = conn.UpdateWebhook(&codebuild.UpdateWebhookInput{
			ProjectName:  aws.String(d.Id()),
			BranchFilter: aws.String(d.Get("branch_filter").(string)),
			RotateSecret: aws.Bool(false),
		})
	}

	if err != nil {
		return err
	}

	return resourceAwsCodeBuildWebhookRead(d, meta)
}

func resourceAwsCodeBuildWebhookDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codebuildconn

	_, err := conn.DeleteWebhook(&codebuild.DeleteWebhookInput{
		ProjectName: aws.String(d.Id()),
	})

	if err != nil {
		if isAWSErr(err, codebuild.ErrCodeResourceNotFoundException, "") {
			return nil
		}
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lease

import (
	"fmt"
	"sync"
	"testing"
	"time"

	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils/set"
	gc "gopkg.in/check.v1"

	coretesting "github.com/juju/juju/testing"
)

func Test(t *testing.T) { gc.TestingT(t) }

const (
	testNamespace = "leadership-stub-service"
	testId        = "stub-unit/0"
	testDuration  = 30 * time.Hour
)

var (
	_ = gc.Suite(&leaseSuite{})
)

type stubLeasePersistor struct {
	WriteTokenFn      func(string, Token) error
	RemoveTokenFn     func(string) error
	PersistedTokensFn func() ([]Token, error)
}

func (p *stubLeasePersistor) WriteToken(id string, tok Token) error {
	if p.WriteTokenFn != nil {
		return p.WriteTokenFn(id, tok)
	}
	return nil
}

func (p *stubLeasePersistor) RemoveToken(id string) error {
	if p.RemoveTokenFn != nil {
		return p.RemoveTokenFn(id)
	}
	return nil
}

func (p *stubLeasePersistor) PersistedTokens() ([]Token, error) {
	if p.PersistedTokensFn != nil {
		return p.PersistedTokensFn()
	}
	return nil, nil
}

type leaseSuite struct{}

func (s *leaseSuite) TestSingleton(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()

	copyA := Manager()
	copyB := Manager()

	c.Assert(copyA, gc.NotNil)
	c.Assert(copyA, gc.Equals, copyB)
}

// TestTokenListIsolation ensures that the copy of the lease tokens we
// get is truly a copy and thus isolated from all other code.
func (s *leaseSuite) TestCopyOfLeaseTokensIsolated(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	toksA := mgr.CopyOfLeaseTokens()
	toksB := mgr.CopyOfLeaseTokens()

	// The tokens are equivalent...
	c.Assert(toksA, gc.HasLen, 1)
	c.Check(toksA, gc.DeepEquals, toksB)

	//...but isolated.
	toksA[0].Id = "I'm a bad, bad programmer. Why would I do this?"
	c.Check(toksA[0], gc.Not(gc.Equals), toksB[0])

	//...and the cache remains intact.
	err = mgr.ReleaseLease(testNamespace, testId)
	c.Check(err, jc.ErrorIsNil)
}

func (s *leaseSuite) TestCopyOfLeaseTokensRaces(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	// Fill a channel with several concurrently-acquired copies...
	var wg sync.WaitGroup
	const count = 10
	results := make(chan []Token, count)
	for i := 0; i < count; i++ {
		wg.Add(1)
		go func() {
			results <- mgr.CopyOfLeaseTokens()
			wg.Done()
		}()
	}
	wg.Wait()

	// ...then extract all those copies for checking below...
	var allResults [][]Token
	for i := 0; i < count; i++ {
		select {
		case result := <-results:
			allResults = append(allResults, result)
		default:
			c.Fatalf("not enough results received")
		}
	}

	// ...and verify that they're all the same.
	for i := 1; i < count; i++ {
		c.Check(allResults[0], jc.DeepEquals, allResults[i])
	}
}

func (s *leaseSuite) TestClaimLeaseSuccess(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()

	ownerId, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(ownerId, gc.Equals, testId)

	toks := mgr.CopyOfLeaseTokens()
	c.Assert(toks, gc.HasLen, 1)
	c.Assert(toks[0].Namespace, gc.Equals, testNamespace)
	c.Assert(toks[0].Id, gc.Equals, testId)
}

func (s *leaseSuite) TestClaimLeaseRaces(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()

	// Run several concurrent requests for different ids in the same namespace.
	var wg sync.WaitGroup
	const count = 10
	owners := make(chan string, count)
	for i := 0; i < count; i++ {
		wg.Add(1)
		go func(i int) {
			id := fmt.Sprintf("unit/%d", i)
			ownerId, err := mgr.ClaimLease(testNamespace, id, testDuration)
			c.Logf(ownerId)
			if err != nil {
				c.Check(err, gc.Equals, LeaseClaimDeniedErr)
			}
			owners <- ownerId
			wg.Done()
		}(i)
	}
	wg.Wait()

	// Consolidate all the results, and check they agree.
	allOwners := set.NewStrings()
	for i := 0; i < count; i++ {
		select {
		case ownerId := <-owners:
			allOwners.Add(ownerId)
		default:
			c.Fatalf("not enough ownerIds received")
		}
	}
	c.Check(allOwners.Size(), gc.Equals, 1)
	c.Check(allOwners.Contains(""), jc.IsFalse)
}

func (s *leaseSuite) TestReleaseLease(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	err = mgr.ReleaseLease(testNamespace, testId)
	c.Assert(err, jc.ErrorIsNil)

	toks := mgr.CopyOfLeaseTokens()
	c.Assert(toks, gc.HasLen, 0)
}

func (s *leaseSuite) TestReleaseLeaseRaces(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()

	// Add several leases in different namespaces.
	const count = 10
	var namespaces []string
	for i := 0; i < count; i++ {
		namespace := fmt.Sprintf("namespace-%d", i)
		namespaces = append(namespaces, namespace)
		_, err := mgr.ClaimLease(namespace, testId, testDuration)
		c.Assert(err, jc.ErrorIsNil)
	}

	// Release them all.
	var wg sync.WaitGroup
	for _, namespace := range namespaces {
		wg.Add(1)
		go func(namespace string) {
			err := mgr.ReleaseLease(namespace, testId)
			c.Check(err, jc.ErrorIsNil)
			wg.Done()
		}(namespace)
	}
	wg.Wait()

	// Check the cache agrees they're all released.
	toks := mgr.CopyOfLeaseTokens()
	c.Assert(toks, gc.HasLen, 0)
}

func (s *leaseSuite) TestRetrieveLease(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	tok := mgr.RetrieveLease(testNamespace)
	c.Check(tok.Id, gc.Equals, testId)
	c.Check(tok.Namespace, gc.Equals, testNamespace)
}

func (s *leaseSuite) TestRetrieveLeaseWithBadNamespaceFails(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()

	mgr := Manager()

	tok := mgr.RetrieveLease(testNamespace)
	c.Assert(tok, gc.DeepEquals, Token{})
}

func (s *leaseSuite) TestReleaseLeaseNotification(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	// Listen for the lease to be released.
	subscription := mgr.LeaseReleasedNotifier(testNamespace)
	receivedSignal := make(chan struct{})
	go func() {
		<-subscription
		receivedSignal <- struct{}{}
	}()

	// Release it
	err = mgr.ReleaseLease(testNamespace, testId)
	c.Assert(err, jc.ErrorIsNil)

	select {
	case <-receivedSignal:
	case <-time.After(coretesting.LongWait):
		c.Errorf("Failed to unblock after release. Waited for %s", coretesting.LongWait)
	}
}

func (s *leaseSuite) TestLeaseExpiration(c *gc.C) {

	// WARNING: This code may be load-sensitive. Unfortunately it must
	// deal with ellapsed time since this is the nature of the code
	// it is testing. For that reason, we try a few times to see if we
	// can get a successful run.

	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()

	const (
		leaseDuration      = 500 * time.Millisecond
		acceptableOverhead = 50 * time.Millisecond
	)

	if leaseDuration+acceptableOverhead > coretesting.LongWait {
		panic("This test will always fail.")
	}

	// Listen for releases before sending the claim to avoid the
	// overhead which may affect our timing measurements.
	mgr := Manager()
	subscription := mgr.LeaseReleasedNotifier(testNamespace)
	receivedSignal := make(chan struct{})

	var leaseClaimedTime time.Time
	go func() {

		<-subscription
		leaseReleasedTime := time.Now()

		// Ensure we didn't release too early or too late.
		switch elapsed := leaseReleasedTime.Sub(leaseClaimedTime); {
		default:
			receivedSignal <- struct{}{}
		case elapsed > leaseDuration+acceptableOverhead:
			fallthrough
		case elapsed < leaseDuration-acceptableOverhead:
			c.Errorf(
				"Expected the lease to be released in %s, but it was released in %s",
				leaseDuration,
				elapsed,
			)
		}
	}()

	// Grab a lease.
	_, err := mgr.ClaimLease(testNamespace, testId, leaseDuration)
	leaseClaimedTime = time.Now()
	c.Assert(err, jc.ErrorIsNil)

	// Wait for the all-clear, or a time-out.
	select {
	case <-receivedSignal:
	case <-time.After(coretesting.LongWait):
		c.Errorf("Failed to unblock after release. Waited for %s", coretesting.LongWait)
	}
}

func (s *leaseSuite) TestManagerPeresistsOnClaims(c *gc.C) {

	persistor := &stubLeasePersistor{}

	stop := make(chan struct{})
	go WorkerLoop(persistor)(stop)
	defer func() { stop <- struct{}{} }()

	mgr := Manager()

	numWriteCalls := 0
	persistor.WriteTokenFn = func(id string, tok Token) error {
		numWriteCalls++

		c.Assert(tok, gc.NotNil)
		c.Check(tok.Namespace, gc.Equals, testNamespace)
		c.Check(tok.Id, gc.Equals, testId)
		c.Check(id, gc.Equals, testNamespace)

		return nil
	}

	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Check(err, jc.ErrorIsNil)
	c.Check(numWriteCalls, gc.Equals, 1)
}

func (s *leaseSuite) TestManagerRemovesOnRelease(c *gc.C) {

	persistor := &stubLeasePersistor{}

	stop := make(chan struct{})
	go WorkerLoop(persistor)(stop)
	defer func() { stop <- struct{}{} }()

	mgr := Manager()

	// Grab a lease.
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	numRemoveCalls := 0
	persistor.RemoveTokenFn = func(id string) error {
		numRemoveCalls++
		c.Check(id, gc.Equals, testNamespace)
		return nil
	}

	// Release the lease, and the persistor should be called.
	mgr.ReleaseLease(testNamespace, testId)

	c.Check(numRemoveCalls, gc.Equals, 1)
}

func (s *leaseSuite) TestManagerDepersistsAllTokensOnStart(c *gc.C) {

	persistor := &stubLeasePersistor{}

	numCalls := 0
	testToks := []Token{
		{testNamespace, testId, time.Now().Add(testDuration)},
		{testNamespace + "2", "a" + testId, time.Now().Add(testDuration)},
	}
	persistor.PersistedTokensFn = func() ([]Token, error) {

		numCalls++
		return testToks, nil
	}

	stop := make(chan struct{})
	go WorkerLoop(persistor)(stop)
	defer func() { stop <- struct{}{} }()

	mgr := Manager()

	// NOTE: This call will naturally block until the worker loop is
	// sucessfully pumping. Place all checks below here.
	heldToks := mgr.CopyOfLeaseTokens()

	c.Assert(numCalls, gc.Equals, 1)

	for _, heldTok := range heldToks {
		found := false
		for _, testTok := range testToks {
			found, _ = gc.DeepEquals.Check([]interface{}{testTok, heldTok}, []string{})
			if found {
				break
			}
		}
		if !found {
			c.Log("The manager is not managing the expected token list.\nNOTE: Test is coded so that order does not matter.")
			c.Assert(heldToks, gc.DeepEquals, testToks)
		}
	}
}
<commit_msg>lease: fix data race in tests<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lease

import (
	"fmt"
	"sync"
	"testing"
	"time"

	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils/set"
	gc "gopkg.in/check.v1"

	coretesting "github.com/juju/juju/testing"
)

func Test(t *testing.T) { gc.TestingT(t) }

const (
	testNamespace = "leadership-stub-service"
	testId        = "stub-unit/0"
	testDuration  = 30 * time.Hour
)

var (
	_ = gc.Suite(&leaseSuite{})
)

type stubLeasePersistor struct {
	WriteTokenFn      func(string, Token) error
	RemoveTokenFn     func(string) error
	PersistedTokensFn func() ([]Token, error)
}

func (p *stubLeasePersistor) WriteToken(id string, tok Token) error {
	if p.WriteTokenFn != nil {
		return p.WriteTokenFn(id, tok)
	}
	return nil
}

func (p *stubLeasePersistor) RemoveToken(id string) error {
	if p.RemoveTokenFn != nil {
		return p.RemoveTokenFn(id)
	}
	return nil
}

func (p *stubLeasePersistor) PersistedTokens() ([]Token, error) {
	if p.PersistedTokensFn != nil {
		return p.PersistedTokensFn()
	}
	return nil, nil
}

type leaseSuite struct{}

func (s *leaseSuite) TestSingleton(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()

	copyA := Manager()
	copyB := Manager()

	c.Assert(copyA, gc.NotNil)
	c.Assert(copyA, gc.Equals, copyB)
}

// TestTokenListIsolation ensures that the copy of the lease tokens we
// get is truly a copy and thus isolated from all other code.
func (s *leaseSuite) TestCopyOfLeaseTokensIsolated(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	toksA := mgr.CopyOfLeaseTokens()
	toksB := mgr.CopyOfLeaseTokens()

	// The tokens are equivalent...
	c.Assert(toksA, gc.HasLen, 1)
	c.Check(toksA, gc.DeepEquals, toksB)

	//...but isolated.
	toksA[0].Id = "I'm a bad, bad programmer. Why would I do this?"
	c.Check(toksA[0], gc.Not(gc.Equals), toksB[0])

	//...and the cache remains intact.
	err = mgr.ReleaseLease(testNamespace, testId)
	c.Check(err, jc.ErrorIsNil)
}

func (s *leaseSuite) TestCopyOfLeaseTokensRaces(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	// Fill a channel with several concurrently-acquired copies...
	var wg sync.WaitGroup
	const count = 10
	results := make(chan []Token, count)
	for i := 0; i < count; i++ {
		wg.Add(1)
		go func() {
			results <- mgr.CopyOfLeaseTokens()
			wg.Done()
		}()
	}
	wg.Wait()

	// ...then extract all those copies for checking below...
	var allResults [][]Token
	for i := 0; i < count; i++ {
		select {
		case result := <-results:
			allResults = append(allResults, result)
		default:
			c.Fatalf("not enough results received")
		}
	}

	// ...and verify that they're all the same.
	for i := 1; i < count; i++ {
		c.Check(allResults[0], jc.DeepEquals, allResults[i])
	}
}

func (s *leaseSuite) TestClaimLeaseSuccess(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()

	ownerId, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(ownerId, gc.Equals, testId)

	toks := mgr.CopyOfLeaseTokens()
	c.Assert(toks, gc.HasLen, 1)
	c.Assert(toks[0].Namespace, gc.Equals, testNamespace)
	c.Assert(toks[0].Id, gc.Equals, testId)
}

func (s *leaseSuite) TestClaimLeaseRaces(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()

	// Run several concurrent requests for different ids in the same namespace.
	var wg sync.WaitGroup
	const count = 10
	owners := make(chan string, count)
	for i := 0; i < count; i++ {
		wg.Add(1)
		go func(i int) {
			id := fmt.Sprintf("unit/%d", i)
			ownerId, err := mgr.ClaimLease(testNamespace, id, testDuration)
			c.Logf(ownerId)
			if err != nil {
				c.Check(err, gc.Equals, LeaseClaimDeniedErr)
			}
			owners <- ownerId
			wg.Done()
		}(i)
	}
	wg.Wait()

	// Consolidate all the results, and check they agree.
	allOwners := set.NewStrings()
	for i := 0; i < count; i++ {
		select {
		case ownerId := <-owners:
			allOwners.Add(ownerId)
		default:
			c.Fatalf("not enough ownerIds received")
		}
	}
	c.Check(allOwners.Size(), gc.Equals, 1)
	c.Check(allOwners.Contains(""), jc.IsFalse)
}

func (s *leaseSuite) TestReleaseLease(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	err = mgr.ReleaseLease(testNamespace, testId)
	c.Assert(err, jc.ErrorIsNil)

	toks := mgr.CopyOfLeaseTokens()
	c.Assert(toks, gc.HasLen, 0)
}

func (s *leaseSuite) TestReleaseLeaseRaces(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()

	// Add several leases in different namespaces.
	const count = 10
	var namespaces []string
	for i := 0; i < count; i++ {
		namespace := fmt.Sprintf("namespace-%d", i)
		namespaces = append(namespaces, namespace)
		_, err := mgr.ClaimLease(namespace, testId, testDuration)
		c.Assert(err, jc.ErrorIsNil)
	}

	// Release them all.
	var wg sync.WaitGroup
	for _, namespace := range namespaces {
		wg.Add(1)
		go func(namespace string) {
			err := mgr.ReleaseLease(namespace, testId)
			c.Check(err, jc.ErrorIsNil)
			wg.Done()
		}(namespace)
	}
	wg.Wait()

	// Check the cache agrees they're all released.
	toks := mgr.CopyOfLeaseTokens()
	c.Assert(toks, gc.HasLen, 0)
}

func (s *leaseSuite) TestRetrieveLease(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	tok := mgr.RetrieveLease(testNamespace)
	c.Check(tok.Id, gc.Equals, testId)
	c.Check(tok.Namespace, gc.Equals, testNamespace)
}

func (s *leaseSuite) TestRetrieveLeaseWithBadNamespaceFails(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()

	mgr := Manager()

	tok := mgr.RetrieveLease(testNamespace)
	c.Assert(tok, gc.DeepEquals, Token{})
}

func (s *leaseSuite) TestReleaseLeaseNotification(c *gc.C) {
	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()
	mgr := Manager()
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	// Listen for the lease to be released.
	subscription := mgr.LeaseReleasedNotifier(testNamespace)
	receivedSignal := make(chan struct{})
	go func() {
		<-subscription
		receivedSignal <- struct{}{}
	}()

	// Release it
	err = mgr.ReleaseLease(testNamespace, testId)
	c.Assert(err, jc.ErrorIsNil)

	select {
	case <-receivedSignal:
	case <-time.After(coretesting.LongWait):
		c.Errorf("Failed to unblock after release. Waited for %s", coretesting.LongWait)
	}
}

func (s *leaseSuite) TestLeaseExpiration(c *gc.C) {

	// WARNING: This code may be load-sensitive. Unfortunately it must
	// deal with ellapsed time since this is the nature of the code
	// it is testing. For that reason, we try a few times to see if we
	// can get a successful run.

	stop := make(chan struct{})
	go WorkerLoop(&stubLeasePersistor{})(stop)
	defer func() { stop <- struct{}{} }()

	const (
		leaseDuration      = 500 * time.Millisecond
		acceptableOverhead = 50 * time.Millisecond
	)

	if leaseDuration+acceptableOverhead > coretesting.LongWait {
		panic("This test will always fail.")
	}

	// Listen for releases before sending the claim to avoid the
	// overhead which may affect our timing measurements.
	mgr := Manager()
	subscription := mgr.LeaseReleasedNotifier(testNamespace)
	receivedSignal := make(chan struct{})

	leaseClaimedTime := time.Now()
	go func() {

		<-subscription
		leaseReleasedTime := time.Now()

		// Ensure we didn't release too early or too late.
		switch elapsed := leaseReleasedTime.Sub(leaseClaimedTime); {
		default:
			receivedSignal <- struct{}{}
		case elapsed > leaseDuration+acceptableOverhead:
			fallthrough
		case elapsed < leaseDuration-acceptableOverhead:
			c.Errorf(
				"Expected the lease to be released in %s, but it was released in %s",
				leaseDuration,
				elapsed,
			)
		}
	}()

	// Grab a lease.
	_, err := mgr.ClaimLease(testNamespace, testId, leaseDuration)
	c.Assert(err, jc.ErrorIsNil)

	// Wait for the all-clear, or a time-out.
	select {
	case <-receivedSignal:
	case <-time.After(coretesting.LongWait):
		c.Errorf("Failed to unblock after release. Waited for %s", coretesting.LongWait)
	}
}

func (s *leaseSuite) TestManagerPeresistsOnClaims(c *gc.C) {

	persistor := &stubLeasePersistor{}

	stop := make(chan struct{})
	go WorkerLoop(persistor)(stop)
	defer func() { stop <- struct{}{} }()

	mgr := Manager()

	numWriteCalls := 0
	persistor.WriteTokenFn = func(id string, tok Token) error {
		numWriteCalls++

		c.Assert(tok, gc.NotNil)
		c.Check(tok.Namespace, gc.Equals, testNamespace)
		c.Check(tok.Id, gc.Equals, testId)
		c.Check(id, gc.Equals, testNamespace)

		return nil
	}

	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Check(err, jc.ErrorIsNil)
	c.Check(numWriteCalls, gc.Equals, 1)
}

func (s *leaseSuite) TestManagerRemovesOnRelease(c *gc.C) {

	persistor := &stubLeasePersistor{}

	stop := make(chan struct{})
	go WorkerLoop(persistor)(stop)
	defer func() { stop <- struct{}{} }()

	mgr := Manager()

	// Grab a lease.
	_, err := mgr.ClaimLease(testNamespace, testId, testDuration)
	c.Assert(err, jc.ErrorIsNil)

	numRemoveCalls := 0
	persistor.RemoveTokenFn = func(id string) error {
		numRemoveCalls++
		c.Check(id, gc.Equals, testNamespace)
		return nil
	}

	// Release the lease, and the persistor should be called.
	mgr.ReleaseLease(testNamespace, testId)

	c.Check(numRemoveCalls, gc.Equals, 1)
}

func (s *leaseSuite) TestManagerDepersistsAllTokensOnStart(c *gc.C) {

	persistor := &stubLeasePersistor{}

	numCalls := 0
	testToks := []Token{
		{testNamespace, testId, time.Now().Add(testDuration)},
		{testNamespace + "2", "a" + testId, time.Now().Add(testDuration)},
	}
	persistor.PersistedTokensFn = func() ([]Token, error) {

		numCalls++
		return testToks, nil
	}

	stop := make(chan struct{})
	go WorkerLoop(persistor)(stop)
	defer func() { stop <- struct{}{} }()

	mgr := Manager()

	// NOTE: This call will naturally block until the worker loop is
	// sucessfully pumping. Place all checks below here.
	heldToks := mgr.CopyOfLeaseTokens()

	c.Assert(numCalls, gc.Equals, 1)

	for _, heldTok := range heldToks {
		found := false
		for _, testTok := range testToks {
			found, _ = gc.DeepEquals.Check([]interface{}{testTok, heldTok}, []string{})
			if found {
				break
			}
		}
		if !found {
			c.Log("The manager is not managing the expected token list.\nNOTE: Test is coded so that order does not matter.")
			c.Assert(heldToks, gc.DeepEquals, testToks)
		}
	}
}
<|endoftext|>


<commit_before>package widgets

import (
	"fmt"
	"github.com/heysquirrel/tribe/apis"
	"github.com/heysquirrel/tribe/blame/model"
	"github.com/jroimartin/gocui"
)

func NewFileWorkItemsView(g *gocui.Gui, works <-chan *model.AssociatedWork) (<-chan apis.WorkItem, gocui.ManagerFunc) {
	name := "fileworkitems"
	selectedWorkItem := make(chan apis.WorkItem)

	// Handle Updates
	go func(name string) {
		for associatedWork := range works {
			g.Update(func(g *gocui.Gui) error {
				v, _ := g.View(name)
				v.Title = fmt.Sprintf(" Associated Work: %s ", associatedWork.Context.GetTitle())

				for _, item := range associatedWork.WorkItems {
					fmt.Fprintf(v, "%10s - %s\n",
						item.GetId(),
						item.GetName(),
					)
				}

				return nil
			})
		}
	}(name)

	// Initial Layout
	layout := func(g *gocui.Gui) error {
		maxX, maxY := g.Size()

		x1 := int(0.0 * float64(maxX))
		y1 := int(0.5 * float64(maxY))
		x2 := int(0.5*float64(maxX)) - 1
		y2 := int(0.75*float64(maxY)) - 1

		v, err := g.SetView(name, x1, y1, x2, y2)
		if err != gocui.ErrUnknownView {
			return err
		}

		v.Title = "Associated Work"

		return nil
	}

	return selectedWorkItem, layout
}
<commit_msg>Extract common UI things to a common UI class<commit_after>package widgets

import (
	"fmt"
	"github.com/heysquirrel/tribe/apis"
	"github.com/heysquirrel/tribe/blame/model"
	"github.com/jroimartin/gocui"
)

func ToBinding(f func()) func(g *gocui.Gui, v *gocui.View) error {
	return func(g *gocui.Gui, v *gocui.View) error { f(); return nil }
}

type KeyBinding struct {
	view    string
	key     interface{}
	handler func()
}

type UI struct {
	name   string
	startx float64
	starty float64
	endx   float64
	endy   float64
	gui    *gocui.Gui
	keys   []KeyBinding
}

func (u *UI) Update(f func(v *gocui.View)) {
	u.gui.Update(func(g *gocui.Gui) error {
		v, err := g.View(u.name)
		if err != nil {
			return err
		}

		f(v)
		return nil
	})
}

func (u *UI) Title(title string) {
	u.Update(func(v *gocui.View) {
		v.Title = title
	})
}

func (u *UI) Focus() {
	u.Update(func(v *gocui.View) {
		u.gui.CurrentView().Highlight = false
		v.Highlight = true
		u.gui.SetCurrentView(u.name)
	})
}

func (u *UI) AddLocalKey(key interface{}, handler func()) {
	u.keys = append(u.keys, KeyBinding{u.name, key, handler})
}

func (u *UI) AddGlobalKey(key interface{}, handler func()) {
	u.keys = append(u.keys, KeyBinding{"", key, handler})
}

func (u *UI) Layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()

	x1 := int(u.startx * float64(maxX))
	y1 := int(u.starty * float64(maxY))
	x2 := int(u.endx*float64(maxX)) - 1
	y2 := int(u.endy*float64(maxY)) - 1

	_, err := g.SetView(u.name, x1, y1, x2, y2)
	if err != gocui.ErrUnknownView {
		return err
	}

	return u.registerKeyBindings(g)
}

func (u *UI) registerKeyBindings(g *gocui.Gui) error {
	for _, binding := range u.keys {
		err := g.SetKeybinding(binding.view, binding.key, gocui.ModNone, ToBinding(binding.handler))
		if err != nil {
			return err
		}
	}
	return nil
}

type list struct {
	*UI
	items    apis.WorkItems
	current  int
	selected chan apis.WorkItem
}

func (l *list) setSelection(index int) {
	if len(l.items) == 0 {
		return
	}

	if index < 0 || index >= len(l.items) {
		fmt.Print("\a")
		return
	}

	l.Update(func(v *gocui.View) {
		if l.current == -1 {
			l.current = 0
			v.SetOrigin(0, 0)
		} else {
			moveDistance := index - l.current
			l.current = index
			v.MoveCursor(0, moveDistance, false)
		}
	})
}

func (l *list) setItems(items apis.WorkItems) {
	l.Update(func(v *gocui.View) {
		v.Clear()

		for _, item := range items {
			fmt.Fprintf(v, "%10s - %s\n",
				item.GetId(),
				item.GetName(),
			)
		}

		l.items = items
		l.setSelection(0)
	})
}

func (l *list) next()     { l.setSelection(l.current + 1) }
func (l *list) previous() { l.setSelection(l.current - 1) }

func NewFileWorkItemsView(g *gocui.Gui, works <-chan *model.AssociatedWork) (<-chan apis.WorkItem, gocui.Manager) {
	selected := make(chan apis.WorkItem)
	ui := &UI{
		name:   "fileworkitems",
		startx: 0.0,
		starty: 0.5,
		endx:   0.5,
		endy:   0.75,
		gui:    g,
		keys:   make([]KeyBinding, 0),
	}
	l := &list{ui, []apis.WorkItem{}, -1, selected}
	l.AddLocalKey(gocui.KeyArrowUp, l.previous)
	l.AddLocalKey(gocui.KeyArrowDown, l.next)
	l.AddGlobalKey(gocui.KeyF2, l.Focus)

	go func(l *list) {
		for work := range works {
			l.Title(fmt.Sprintf(" Associated Work: %s ", work.Context.GetTitle()))
			l.setItems(work.WorkItems)
		}
	}(l)

	return selected, l
}
<|endoftext|>


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

package main

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"errors"
	"flag"
	"log"
	"math/big"
	"net"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/jlmucb/cloudproxy/go/support_libraries/domain_policy"
	"github.com/jlmucb/cloudproxy/go/tao"
	"github.com/jlmucb/cloudproxy/go/tao/auth"
	"github.com/jlmucb/cloudproxy/go/util"
)

var network = flag.String("network", "tcp", "The network to use for connections")
var addr = flag.String("addr", "localhost:8124", "The address to listen on")
var domainPass = flag.String("password", "xxx", "The domain password")
var configPath = flag.String("config",
	"/Domains/domain.simpleexample/tao.config", "The Tao domain config")
var servicePath = flag.String("service_path",
	"/Domains/domain.simpleexample/SimpleDomainService", "The Tao domain config")

var SerialNumber int64

func IsAuthenticationValid(name *string) bool {
	log.Printf("simpledomainservice, IsAuthenticationValid name is %s\n", *name)
	if name == nil {
		return false
	}
	log.Printf("simpledomainservice, IsAuthenticationValid returning true\n")
	return true
}

// First return is terminate flag.
func DomainRequest(conn net.Conn, policyKey *tao.Keys, guard tao.Guard) (bool, error) {
	log.Printf("DomainRequest\n")

	// Expect a request with attestation from client.
	ms := util.NewMessageStream(conn)
	var request domain_policy.DomainCertRequest
	err := ms.ReadMessage(&request)
	if err != nil {
		log.Printf("DomainRequest: Couldn't read attestation from channel. Error : %v", err)
		log.Printf("\n")
		return false, err
	}

	var a tao.Attestation
	err = proto.Unmarshal(request.Attestation, &a)
	if request.KeyType == nil {
		log.Printf("Domain: Empty key type")
		return false, errors.New("Empty key type")
	}

log.Printf("SimpleDomainService: got attestation and request ")
	switch *request.KeyType {
	case "ecdsap256-public", "ecdsap384-public", "ecdsap521-public",
		"ecdsap256", "ecdsap384", "ecdsap521":
		break
	default:
		log.Printf("Domain: bad key type")
		return false, errors.New("Domain: bad key type")
	}

	subjectVerifier, err := tao.VerifierKeyFromCanonicalKeyBytes(request.SubjectPublicKey)
	if err != nil {
		log.Printf("DomainRequest: can't get key from der")
		return false, errors.New("DomainRequest: can't get key from der")
	}
	subjectKeyHash, err := subjectVerifier.UniversalKeyNameFromVerifier()
	if err != nil {
		log.Printf("SimpleDomain DomainRequest: calculate universal name")
		return false, errors.New("SimpleDomain DomainRequest: can't get key from der")
	}
	peerCert := conn.(*tls.Conn).ConnectionState().PeerCertificates[0]
	log.Printf("\n")
	log.Printf("\nNumber of peer certs: %d\n", len(conn.(*tls.Conn).ConnectionState().PeerCertificates))
	for i := 0; i < len(conn.(*tls.Conn).ConnectionState().PeerCertificates); i++ {
		tao.PrintPKIXName("Issuer", &conn.(*tls.Conn).ConnectionState().PeerCertificates[i].Issuer)
		tao.PrintPKIXName("Subject", &conn.(*tls.Conn).ConnectionState().PeerCertificates[i].Subject)
		log.Printf("\n")
	}
	// TODO(jlm): Change this.
	err = tao.ValidatePeerAttestation(&a, peerCert, guard)
	/*
	   if err != nil {
	       log.Printf("Domain: RequestCouldn't validate peer attestation:", err)
	   		 return false, err
	   }
	   fmt.Printf("DomainRequest, peerCert: %x\n", peerCert)
	*/

	// Sign cert
log.Printf("SimpleDomainService: signing cert")

	// Get Program name and key info from delegation.
	f, err := auth.UnmarshalForm(a.SerializedStatement)
	if err != nil {
		log.Printf("DomainRequest: Can't unmarshal a.SerializedStatement\n")
		return false, err
	}

	var saysStatement *auth.Says
	if ptr, ok := f.(*auth.Says); ok {
		saysStatement = ptr
	} else if val, ok := f.(auth.Says); ok {
		saysStatement = &val
	}
	sf, ok := saysStatement.Message.(auth.Speaksfor)
	if ok != true {
		log.Printf("DomainRequest: says doesnt have speaksfor message\n")
		return false, err
	}
	// this in the new key principal
	clientKeyPrincipal, ok := sf.Delegate.(auth.Prin)
	if ok != true {
		log.Printf("DomainRequest: speaksfor Delegate is not auth.Prin\n")
		return false, err
	}

	programPrincipal, ok := sf.Delegator.(auth.Prin)
	if ok != true {
		log.Printf("DomainRequest: Can't get subject principal\n")
		return false, errors.New("Can't get principal name from verifier")
	}
	programPrincipalName := programPrincipal.String()
	verified := IsAuthenticationValid(&programPrincipalName)
	if !verified {
		log.Printf("DomainRequest: name verification failed\n")
		return false, err
	}
	log.Printf("SimpleDomainService: key principal: %s, program principal: %s\n", clientKeyPrincipal, programPrincipalName)

	// Is the delegate the same key as was presented in the name in the request?
	namedHash := clientKeyPrincipal.KeyHash.(auth.Bytes)
	log.Printf("keyhash: %x\n", namedHash)
	if bytes.Compare(subjectKeyHash[:], namedHash) != 0 {
		log.Printf("DomainRequest: named hash is wrong, named: %x, computed: %x\n",
			namedHash, subjectKeyHash)
		return false, errors.New("DomainRequest: named hash is wrong")
	}

	// Sign program certificate.

	notBefore := time.Now()
	validFor := 365 * 24 * time.Hour
	notAfter := notBefore.Add(validFor)

	us := "US"
	localhost := "localhost"
	x509SubjectName := &pkix.Name{
		Organization:       []string{programPrincipalName},
		OrganizationalUnit: []string{programPrincipalName},
		CommonName:         localhost,
		Country:            []string{us},
	}

/*
	FIX
	issuerName := "Google"
	x509IssuerName := &pkix.Name{
		Organization:       []string{issuerName},
		OrganizationalUnit: []string{issuerName},
		CommonName:         localhost,
		Country:            []string{us},
	}
 */

	log.Printf("Signing cert for ")
	tao.PrintPKIXName("Subject", x509SubjectName)
	log.Printf(" with \n")
	tao.PrintPKIXName("Issuer", &policyKey.Cert.Issuer)
	log.Printf("\n")

	SerialNumber = SerialNumber + 1
	var sn big.Int
	certificateTemplate := &x509.Certificate{
		SerialNumber: &sn,

		// Issuer:    *x509IssuerName,
		Issuer:    policyKey.Cert.Issuer,
		Subject:   *x509SubjectName,
		NotBefore: notBefore,
		NotAfter:  notAfter,
		KeyUsage:  x509.KeyUsageCertSign | x509.KeyUsageKeyAgreement | x509.KeyUsageDigitalSignature,
	}

	// FIX: pass certificate template
	signerAlg := tao.SignerTypeFromSuiteName(tao.TaoCryptoSuite)
	if signerAlg == nil {
		return false, errors.New("Bad suite")
	}
	pkAlg := tao.PublicKeyAlgFromSignerAlg(*signerAlg)
	sigAlg := tao.SignatureAlgFromSignerAlg(*signerAlg)
	if pkAlg < 0 || sigAlg < 0 {
		return false, errors.New("Bad signing algs")
	}
	clientCert, err := policyKey.SigningKey.CreateSignedX509FromTemplate(policyKey.Cert, certificateTemplate,
		subjectVerifier, pkAlg, sigAlg)

	zero := int32(0)
	var ra domain_policy.DomainCertResponse
	ra.Error = &zero
	ra.SignedCert = clientCert.Raw

	// Add cert chain (just policy cert for now).
	ra.CertChain = append(ra.CertChain, policyKey.Cert.Raw)

	_, err = ms.WriteMessage(&ra)
	if err != nil {
		log.Printf("DomainRequest: Couldn't return the attestation on the channel. Error: %v", err)
		log.Printf("\n")
		return false, err
	}
	return false, nil
}

func main() {
	flag.Parse()
	domain, err := tao.LoadDomain(*configPath, []byte(*domainPass))
	if domain == nil {
		log.Printf("simpledomainservice: no domain path - %s, pass - %s, err - %s\n",
			*configPath, *domainPass, err)
		return
	} else if err != nil {
		log.Printf("simpledomainservice: Couldn't load the config path %s: %s\n",
			*configPath, err)
		return
	}
	log.Printf("simpledomainservice: Loaded domain\n")
	if domain.Keys.Cert == nil {
		log.Printf("\nPolicy key Cert is nil\n")
	} else {
		log.Printf("\nPolicy Cert Issuer: \n")
		tao.PrintPKIXName("Issuer", &domain.Keys.Cert.Issuer)
		log.Printf("\nPolicy Cert Subject: \n")
		tao.PrintPKIXName("Subject", &domain.Keys.Cert.Subject)
		log.Printf("\n\n")
	}
	log.Printf("\n")

	// Set up temporary keys for the connection, since the only thing that
	// matters to the remote client is that they receive a correctly-signed new
	// attestation from the policy key.
	// JLM:  I left this in place but I'm not sure what a TLS connection with a
	//   self signed Cert buys in terms of security.
	//   The security of this protocol should not depend on the
	//   confidentiality or intergity of the channel.  All that said, if we
	//   do ever distribute a signed simpledomainservice cert
	// for this TLS channel, it would be good.
	keys, err := tao.NewTemporaryKeys(tao.Signing)
	if keys == nil || err != nil {
		log.Fatalln("simpledomainservice: Couldn't set up temporary keys for connection:", err)
		return
	}
	pkAlg := tao.PublicKeyAlgFromSignerAlg(*keys.SigningKey.Header.KeyType)
	sigAlg := tao.SignatureAlgFromSignerAlg(*keys.SigningKey.Header.KeyType)
	keys.Cert, err = keys.SigningKey.CreateSelfSignedX509(pkAlg, sigAlg, int64(1),
		&pkix.Name{
			Organization: []string{"Google Tao Demo"}})
	if err != nil {
		log.Fatalln("simpledomainservice: Couldn't set up a self-signed cert:", err)
		return
	}
	SerialNumber = int64(time.Now().UnixNano()) / (1000000)
	policyKey := domain.Keys
	log.Printf("SimpleDomainService: policyKey: %v\n", policyKey)
	log.Printf("SimpleDomainService: policyKey Subject: ")
	tao.PrintPKIXName("Subject", &policyKey.Cert.Subject)
	log.Printf("\n")

	tlsc, err := tao.EncodeTLSCert(keys)
	if err != nil {
		log.Fatalln("simpledomainservice: Couldn't encode a TLS cert:", err)
	}
	conf := &tls.Config{
		RootCAs:            x509.NewCertPool(),
		Certificates:       []tls.Certificate{*tlsc},
		InsecureSkipVerify: true,
		ClientAuth:         tls.RequireAnyClientCert,
	}
	sock, err := tls.Listen(*network, *addr, conf)
	if err != nil {
		log.Printf("simpledomainservice: error: %s\n", err)
	}
	if sock == nil {
		log.Printf("simpledomainservice: Empty socket, terminating\n")
		return
	}
	defer sock.Close()

	log.Printf("simpledomainservice: accepting connections\n")
	for {
		conn, err := sock.Accept()
		if conn == nil {
			log.Printf("simpledomainservice: Empty connection\n")
			return
		} else if err != nil {
			log.Printf("simpledomainservice: Couldn't accept a connection on %s: %s\n", *addr, err)
			return
		}
		go DomainRequest(conn, policyKey, domain.Guard)
	}
	log.Println("simpledomainservice: finishing")
}
<commit_msg>removed FIX comments<commit_after>// Copyright (c) 2014, Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"errors"
	"flag"
	"log"
	"math/big"
	"net"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/jlmucb/cloudproxy/go/support_libraries/domain_policy"
	"github.com/jlmucb/cloudproxy/go/tao"
	"github.com/jlmucb/cloudproxy/go/tao/auth"
	"github.com/jlmucb/cloudproxy/go/util"
)

var network = flag.String("network", "tcp", "The network to use for connections")
var addr = flag.String("addr", "localhost:8124", "The address to listen on")
var domainPass = flag.String("password", "xxx", "The domain password")
var configPath = flag.String("config",
	"/Domains/domain.simpleexample/tao.config", "The Tao domain config")
var servicePath = flag.String("service_path",
	"/Domains/domain.simpleexample/SimpleDomainService", "The Tao domain config")

var SerialNumber int64

func IsAuthenticationValid(name *string) bool {
	log.Printf("simpledomainservice, IsAuthenticationValid name is %s\n", *name)
	if name == nil {
		return false
	}
	log.Printf("simpledomainservice, IsAuthenticationValid returning true\n")
	return true
}

// First return is terminate flag.
func DomainRequest(conn net.Conn, policyKey *tao.Keys, guard tao.Guard) (bool, error) {
	log.Printf("DomainRequest\n")

	// Expect a request with attestation from client.
	ms := util.NewMessageStream(conn)
	var request domain_policy.DomainCertRequest
	err := ms.ReadMessage(&request)
	if err != nil {
		log.Printf("DomainRequest: Couldn't read attestation from channel. Error : %v", err)
		log.Printf("\n")
		return false, err
	}

	var a tao.Attestation
	err = proto.Unmarshal(request.Attestation, &a)
	if request.KeyType == nil {
		log.Printf("Domain: Empty key type")
		return false, errors.New("Empty key type")
	}

log.Printf("SimpleDomainService: got attestation and request ")
	switch *request.KeyType {
	case "ecdsap256-public", "ecdsap384-public", "ecdsap521-public",
		"ecdsap256", "ecdsap384", "ecdsap521":
		break
	default:
		log.Printf("Domain: bad key type")
		return false, errors.New("Domain: bad key type")
	}

	subjectVerifier, err := tao.VerifierKeyFromCanonicalKeyBytes(request.SubjectPublicKey)
	if err != nil {
		log.Printf("DomainRequest: can't get key from der")
		return false, errors.New("DomainRequest: can't get key from der")
	}
	subjectKeyHash, err := subjectVerifier.UniversalKeyNameFromVerifier()
	if err != nil {
		log.Printf("SimpleDomain DomainRequest: calculate universal name")
		return false, errors.New("SimpleDomain DomainRequest: can't get key from der")
	}
	peerCert := conn.(*tls.Conn).ConnectionState().PeerCertificates[0]
	log.Printf("\n")
	log.Printf("\nNumber of peer certs: %d\n", len(conn.(*tls.Conn).ConnectionState().PeerCertificates))
	for i := 0; i < len(conn.(*tls.Conn).ConnectionState().PeerCertificates); i++ {
		tao.PrintPKIXName("Issuer", &conn.(*tls.Conn).ConnectionState().PeerCertificates[i].Issuer)
		tao.PrintPKIXName("Subject", &conn.(*tls.Conn).ConnectionState().PeerCertificates[i].Subject)
		log.Printf("\n")
	}
	// TODO(jlm): Change this.
	err = tao.ValidatePeerAttestation(&a, peerCert, guard)
	/*
	   if err != nil {
	       log.Printf("Domain: RequestCouldn't validate peer attestation:", err)
	   		 return false, err
	   }
	   fmt.Printf("DomainRequest, peerCert: %x\n", peerCert)
	*/

	// Sign cert
log.Printf("SimpleDomainService: signing cert")

	// Get Program name and key info from delegation.
	f, err := auth.UnmarshalForm(a.SerializedStatement)
	if err != nil {
		log.Printf("DomainRequest: Can't unmarshal a.SerializedStatement\n")
		return false, err
	}

	var saysStatement *auth.Says
	if ptr, ok := f.(*auth.Says); ok {
		saysStatement = ptr
	} else if val, ok := f.(auth.Says); ok {
		saysStatement = &val
	}
	sf, ok := saysStatement.Message.(auth.Speaksfor)
	if ok != true {
		log.Printf("DomainRequest: says doesnt have speaksfor message\n")
		return false, err
	}
	// this in the new key principal
	clientKeyPrincipal, ok := sf.Delegate.(auth.Prin)
	if ok != true {
		log.Printf("DomainRequest: speaksfor Delegate is not auth.Prin\n")
		return false, err
	}

	programPrincipal, ok := sf.Delegator.(auth.Prin)
	if ok != true {
		log.Printf("DomainRequest: Can't get subject principal\n")
		return false, errors.New("Can't get principal name from verifier")
	}
	programPrincipalName := programPrincipal.String()
	verified := IsAuthenticationValid(&programPrincipalName)
	if !verified {
		log.Printf("DomainRequest: name verification failed\n")
		return false, err
	}
	log.Printf("SimpleDomainService: key principal: %s, program principal: %s\n", clientKeyPrincipal, programPrincipalName)

	// Is the delegate the same key as was presented in the name in the request?
	namedHash := clientKeyPrincipal.KeyHash.(auth.Bytes)
	log.Printf("keyhash: %x\n", namedHash)
	if bytes.Compare(subjectKeyHash[:], namedHash) != 0 {
		log.Printf("DomainRequest: named hash is wrong, named: %x, computed: %x\n",
			namedHash, subjectKeyHash)
		return false, errors.New("DomainRequest: named hash is wrong")
	}

	// Sign program certificate.

	notBefore := time.Now()
	validFor := 365 * 24 * time.Hour
	notAfter := notBefore.Add(validFor)

	us := "US"
	localhost := "localhost"
	x509SubjectName := &pkix.Name{
		Organization:       []string{programPrincipalName},
		OrganizationalUnit: []string{programPrincipalName},
		CommonName:         localhost,
		Country:            []string{us},
	}

	log.Printf("Signing cert for ")
	tao.PrintPKIXName("Subject", x509SubjectName)
	log.Printf(" with \n")
	tao.PrintPKIXName("Issuer", &policyKey.Cert.Issuer)
	log.Printf("\n")

	SerialNumber = SerialNumber + 1
	var sn big.Int
	certificateTemplate := &x509.Certificate{
		SerialNumber: &sn,
		Issuer:    policyKey.Cert.Issuer,
		Subject:   *x509SubjectName,
		NotBefore: notBefore,
		NotAfter:  notAfter,
		KeyUsage:  x509.KeyUsageCertSign | x509.KeyUsageKeyAgreement | x509.KeyUsageDigitalSignature,
	}

	signerAlg := tao.SignerTypeFromSuiteName(tao.TaoCryptoSuite)
	if signerAlg == nil {
		return false, errors.New("Bad suite")
	}
	pkAlg := tao.PublicKeyAlgFromSignerAlg(*signerAlg)
	sigAlg := tao.SignatureAlgFromSignerAlg(*signerAlg)
	if pkAlg < 0 || sigAlg < 0 {
		return false, errors.New("Bad signing algs")
	}
	clientCert, err := policyKey.SigningKey.CreateSignedX509FromTemplate(policyKey.Cert, certificateTemplate,
		subjectVerifier, pkAlg, sigAlg)

	zero := int32(0)
	var ra domain_policy.DomainCertResponse
	ra.Error = &zero
	ra.SignedCert = clientCert.Raw

	// Add cert chain (just policy cert for now).
	ra.CertChain = append(ra.CertChain, policyKey.Cert.Raw)

	_, err = ms.WriteMessage(&ra)
	if err != nil {
		log.Printf("DomainRequest: Couldn't return the attestation on the channel. Error: %v", err)
		log.Printf("\n")
		return false, err
	}
	return false, nil
}

func main() {
	flag.Parse()
	domain, err := tao.LoadDomain(*configPath, []byte(*domainPass))
	if domain == nil {
		log.Printf("simpledomainservice: no domain path - %s, pass - %s, err - %s\n",
			*configPath, *domainPass, err)
		return
	} else if err != nil {
		log.Printf("simpledomainservice: Couldn't load the config path %s: %s\n",
			*configPath, err)
		return
	}
	log.Printf("simpledomainservice: Loaded domain\n")
	if domain.Keys.Cert == nil {
		log.Printf("\nPolicy key Cert is nil\n")
	} else {
		log.Printf("\nPolicy Cert Issuer: \n")
		tao.PrintPKIXName("Issuer", &domain.Keys.Cert.Issuer)
		log.Printf("\nPolicy Cert Subject: \n")
		tao.PrintPKIXName("Subject", &domain.Keys.Cert.Subject)
		log.Printf("\n\n")
	}
	log.Printf("\n")

	// Set up temporary keys for the connection, since the only thing that
	// matters to the remote client is that they receive a correctly-signed new
	// attestation from the policy key.
	// JLM:  I left this in place but I'm not sure what a TLS connection with a
	//   self signed Cert buys in terms of security.
	//   The security of this protocol should not depend on the
	//   confidentiality or intergity of the channel.  All that said, if we
	//   do ever distribute a signed simpledomainservice cert
	// for this TLS channel, it would be good.
	keys, err := tao.NewTemporaryKeys(tao.Signing)
	if keys == nil || err != nil {
		log.Fatalln("simpledomainservice: Couldn't set up temporary keys for connection:", err)
		return
	}
	pkAlg := tao.PublicKeyAlgFromSignerAlg(*keys.SigningKey.Header.KeyType)
	sigAlg := tao.SignatureAlgFromSignerAlg(*keys.SigningKey.Header.KeyType)
	keys.Cert, err = keys.SigningKey.CreateSelfSignedX509(pkAlg, sigAlg, int64(1),
		&pkix.Name{
			Organization: []string{"Google Tao Demo"}})
	if err != nil {
		log.Fatalln("simpledomainservice: Couldn't set up a self-signed cert:", err)
		return
	}
	SerialNumber = int64(time.Now().UnixNano()) / (1000000)
	policyKey := domain.Keys
	log.Printf("SimpleDomainService: policyKey: %v\n", policyKey)
	log.Printf("SimpleDomainService: policyKey Subject: ")
	tao.PrintPKIXName("Subject", &policyKey.Cert.Subject)
	log.Printf("\n")

	tlsc, err := tao.EncodeTLSCert(keys)
	if err != nil {
		log.Fatalln("simpledomainservice: Couldn't encode a TLS cert:", err)
	}
	conf := &tls.Config{
		RootCAs:            x509.NewCertPool(),
		Certificates:       []tls.Certificate{*tlsc},
		InsecureSkipVerify: true,
		ClientAuth:         tls.RequireAnyClientCert,
	}
	sock, err := tls.Listen(*network, *addr, conf)
	if err != nil {
		log.Printf("simpledomainservice: error: %s\n", err)
	}
	if sock == nil {
		log.Printf("simpledomainservice: Empty socket, terminating\n")
		return
	}
	defer sock.Close()

	log.Printf("simpledomainservice: accepting connections\n")
	for {
		conn, err := sock.Accept()
		if conn == nil {
			log.Printf("simpledomainservice: Empty connection\n")
			return
		} else if err != nil {
			log.Printf("simpledomainservice: Couldn't accept a connection on %s: %s\n", *addr, err)
			return
		}
		go DomainRequest(conn, policyKey, domain.Guard)
	}
	log.Println("simpledomainservice: finishing")
}
<|endoftext|>


<commit_before>package images

import (
	"Fantasia/system"
	"image"
	"image/gif"
	"image/png"
	"io"
	"log"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	"github.com/bwmarrin/discordgo"
)

// util.go : provides various utility functions
var urlRegex = regexp.MustCompile(`(http|ftp|https):\/\/([\w\-_]+(?:(?:\.[\w\-_]+)+))([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?`)

// ImageSuffixes is a list of image suffixes
var ImageSuffixes = []string{
	"png",
	"jpeg",
	"jpg",
	"gif",
}

// ReplyImage replies to the sender with the given image
func ReplyImage(ctx *system.Context, img image.Image) {
	rd, wr := io.Pipe()
	go func() {
		png.Encode(wr, img)
		wr.Close()
	}()
	ctx.Ses.DG.ChannelFileSend(ctx.Msg.ChannelID, "image.png", rd)
}

// ReplyGif replies to the sender with the given gif
func ReplyGif(ctx *system.Context, g *gif.GIF) {
	rd, wr := io.Pipe()
	go func() {
		err := gif.EncodeAll(wr, g)
		if err != nil {
			ctx.ReplyError("error encoding gif: ", err)
		}
		wr.Close()
	}()
	_, err := ctx.Ses.DG.ChannelFileSend(ctx.Msg.ChannelID, "image.gif", rd)
	if err != nil {
		ctx.ReplyError("Error uploading gif: ", err)
	}
}

// CompressGif attempts to compress a Gif's images
func CompressGif(src *gif.GIF) *gif.GIF {
	dst := &gif.GIF{
		Image:    make([]*image.Paletted, len(src.Image)),
		Disposal: make([]byte, len(src.Disposal)),
	}
	// Set disposal to none.
	for i := 0; i < len(dst.Disposal); i++ {
		dst.Disposal[i] = gif.DisposalNone
	}

	return dst
}

// PullImages requests images from the user, or retrieves them from the cache.
//    amount    : amount of messages to retrieve
//    channelID : channelID to pull images from
//    message   : message user supplied. If images are present, pull them from here first.
//                otherwise fall back to the image cache.
func (m *Module) PullImages(limit int, channelID string, message *discordgo.Message) ([]image.Image, error) {
	images := make([]image.Image, 0, limit)

	// Pull images from message issuing command.
	tmp, err := PullImagesFromMessage(limit, message)
	if err != nil {
		return images, err
	}
	images = append(images, tmp...)

	// If we have satisfied the message limit, return
	if len(images) >= limit {
		return images, nil
	}

	// Else continue searching the cache for images
	tmp, err = PullImagesFromCache(m.ImgCache, limit-len(images), channelID)
	if err != nil {
		return images, err
	}
	images = append(images, tmp...)

	return images, nil
}

// PullImagesFromMessage retrieves images from a message
func PullImagesFromMessage(limit int, msg *discordgo.Message) ([]image.Image, error) {
	URLs := ImageURLsInMessage(msg)
	images := []image.Image{}

	for _, v := range URLs {
		img, err := ImageFromURL(v)
		if err != nil {
			return images, err
		}
		images = append(images, img)

		limit--
		if limit == 0 {
			break
		}
	}

	return images, nil
}

// ImageFromURL gets an image from a URL
//    URL : URL to perform an HTTP get reqeust to
func ImageFromURL(URL string) (image.Image, error) {
	resp, err := http.Get(URL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	img, _, err := image.Decode(resp.Body)
	return img, err
}

// ImageURLsInMessage returns a list of image URLs in a message
// Images are obtained from embed images, and thumbnails, and attachments.
//    msg : message to obtain the URLs from
func ImageURLsInMessage(msg *discordgo.Message) []string {
	URLs := []string{}

	for _, a := range msg.Attachments {
		URLs = append(URLs, a.URL)
	}

	for _, embed := range msg.Embeds {
		if embed.Image != nil && embed.Image.ProxyURL != "" {
			URLs = append(URLs, embed.Image.ProxyURL)
		}
		if embed.Thumbnail != nil && embed.Thumbnail.ProxyURL != "" {
			URLs = append(URLs, embed.Thumbnail.ProxyURL)
		}
	}

	if len(msg.Embeds) == 0 {
		for _, u := range urlRegex.FindAllString(msg.Content, -1) {
			if IsImageURL(u) {
				URLs = append(URLs, u)
			}
		}
	}

	return URLs
}

// IsImageURL guesses if a URL is an image
func IsImageURL(path string) bool {
	t, err := url.Parse(path)
	if err != nil {
		log.Println("error parsing URL")
	} else {
		if HasImageSuffix(strings.ToLower(t.Path)) {
			return true
		}
	}
	return false
}

// PullImagesFromCache ...
func PullImagesFromCache(cache *MessageCache, limit int, channelID string) ([]image.Image, error) {
	images := make([]image.Image, 0, limit)

	messages, err := cache.Messages(channelID)
	if err != nil {
		return nil, err
	}

	for i := len(messages) - 1; i >= 0; i-- {
		v := messages[i]
		tmp, err := PullImagesFromMessage(limit, v)
		if err != nil {
			return nil, err
		}
		images = append(images, tmp...)

		// Decrement the image limit
		limit -= len(images)
		if limit <= 0 {
			break
		}
	}

	return images, nil
}

// HasImage returns if a message has an image
func HasImage(msg *discordgo.Message) bool {

	for _, embed := range msg.Embeds {
		if embed.Image != nil && embed.Image.URL != "" {
			return true
		}
		if embed.Thumbnail != nil && embed.Thumbnail.URL != "" {
			return true
		}
	}

	for _, v := range msg.Attachments {
		if HasImageSuffix(v.Filename) {
			return true
		}
	}

	for _, u := range urlRegex.FindAllString(msg.Content, -1) {
		if IsImageURL(u) {
			return true
		}
	}

	return false
}

// HasImageSuffix returns true if an image suffix is present
func HasImageSuffix(filename string) bool {
	for _, v := range ImageSuffixes {
		if strings.HasSuffix(filename, v) {
			return true
		}
	}
	return false
}
<commit_msg>CompressGif now works<commit_after>package images

import (
	"Fantasia/system"
	"image"
	"image/color"
	"image/gif"
	"image/png"
	"io"
	"log"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	"github.com/bwmarrin/discordgo"
)

// util.go : provides various utility functions
var urlRegex = regexp.MustCompile(`(http|ftp|https):\/\/([\w\-_]+(?:(?:\.[\w\-_]+)+))([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?`)

// ImageSuffixes is a list of image suffixes
var ImageSuffixes = []string{
	"png",
	"jpeg",
	"jpg",
	"gif",
}

// ReplyImage replies to the sender with the given image
func ReplyImage(ctx *system.Context, img image.Image) {
	rd, wr := io.Pipe()
	go func() {
		png.Encode(wr, img)
		wr.Close()
	}()
	ctx.Ses.DG.ChannelFileSend(ctx.Msg.ChannelID, "image.png", rd)
}

// ReplyGif replies to the sender with the given gif
func ReplyGif(ctx *system.Context, g *gif.GIF) {
	rd, wr := io.Pipe()
	go func() {
		err := gif.EncodeAll(wr, g)
		if err != nil {
			ctx.ReplyError("error encoding gif: ", err)
		}
		wr.Close()
	}()
	_, err := ctx.Ses.DG.ChannelFileSend(ctx.Msg.ChannelID, "image.gif", rd)
	if err != nil {
		ctx.ReplyError("Error uploading gif: ", err)
	}
}

// CompressGif attempts to compress a Gif's images
func CompressGif(src *gif.GIF) *gif.GIF {
	dst := &gif.GIF{
		Image:    make([]*image.Paletted, len(src.Image)),
		Disposal: make([]byte, len(src.Disposal)),
		Delay:    src.Delay,
	}
	// Set disposal to none.
	for i := 0; i < len(dst.Disposal); i++ {
		dst.Disposal[i] = 1
	}

	diff := func(a, b uint32) bool {
		if a >= b-500 && a <= b+500 {
			return false
		}
		return true
	}

	var frame = src.Image[0]
	dst.Image[0] = frame
	for i := 1; i < len(src.Image); i++ {
		cp := src.Image[i]
		np := image.NewPaletted(src.Image[i].Bounds(), cp.Palette)
		np.Palette[0] = color.RGBA{0, 0, 0, 0} // Insert an alpha pixel into the palette

		w, h := cp.Bounds().Dx(), cp.Bounds().Dy()
		for y := 0; y < h; y++ {
			for x := 0; x < w; x++ {
				pidx := y*cp.Stride + x*1
				// Compare the colours of frame(last image) and cp(current paletted),
				// if they are different, add the pixel to new paletted (np)
				r, g, b, a := cp.Palette[cp.Pix[pidx]].RGBA()
				r1, g1, b1, a1 := frame.Palette[frame.Pix[pidx]].RGBA()

				if diff(r, r1) || diff(g, g1) || diff(b, b1) || diff(a, a1) {
					np.Pix[pidx] = cp.Pix[pidx]
				} else {
					np.Pix[pidx] = uint8(np.Palette.Index(color.RGBA{0, 0, 0, 0}))
				}
			}
		}

		dst.Image[i] = np
		frame = cp // Update last frame
	}

	return dst
}

// PullImages requests images from the user, or retrieves them from the cache.
//    amount    : amount of messages to retrieve
//    channelID : channelID to pull images from
//    message   : message user supplied. If images are present, pull them from here first.
//                otherwise fall back to the image cache.
func (m *Module) PullImages(limit int, channelID string, message *discordgo.Message) ([]image.Image, error) {
	images := make([]image.Image, 0, limit)

	// Pull images from message issuing command.
	tmp, err := PullImagesFromMessage(limit, message)
	if err != nil {
		return images, err
	}
	images = append(images, tmp...)

	// If we have satisfied the message limit, return
	if len(images) >= limit {
		return images, nil
	}

	// Else continue searching the cache for images
	tmp, err = PullImagesFromCache(m.ImgCache, limit-len(images), channelID)
	if err != nil {
		return images, err
	}
	images = append(images, tmp...)

	return images, nil
}

// PullImagesFromMessage retrieves images from a message
func PullImagesFromMessage(limit int, msg *discordgo.Message) ([]image.Image, error) {
	URLs := ImageURLsInMessage(msg)
	images := []image.Image{}

	for _, v := range URLs {
		img, err := ImageFromURL(v)
		if err != nil {
			return images, err
		}
		images = append(images, img)

		limit--
		if limit == 0 {
			break
		}
	}

	return images, nil
}

// ImageFromURL gets an image from a URL
//    URL : URL to perform an HTTP get reqeust to
func ImageFromURL(URL string) (image.Image, error) {
	resp, err := http.Get(URL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	img, _, err := image.Decode(resp.Body)
	return img, err
}

// ImageURLsInMessage returns a list of image URLs in a message
// Images are obtained from embed images, and thumbnails, and attachments.
//    msg : message to obtain the URLs from
func ImageURLsInMessage(msg *discordgo.Message) []string {
	URLs := []string{}

	for _, a := range msg.Attachments {
		URLs = append(URLs, a.URL)
	}

	for _, embed := range msg.Embeds {
		if embed.Image != nil && embed.Image.ProxyURL != "" {
			URLs = append(URLs, embed.Image.ProxyURL)
		}
		if embed.Thumbnail != nil && embed.Thumbnail.ProxyURL != "" {
			URLs = append(URLs, embed.Thumbnail.ProxyURL)
		}
	}

	if len(msg.Embeds) == 0 {
		for _, u := range urlRegex.FindAllString(msg.Content, -1) {
			if IsImageURL(u) {
				URLs = append(URLs, u)
			}
		}
	}

	return URLs
}

// IsImageURL guesses if a URL is an image
func IsImageURL(path string) bool {
	t, err := url.Parse(path)
	if err != nil {
		log.Println("error parsing URL")
	} else {
		if HasImageSuffix(strings.ToLower(t.Path)) {
			return true
		}
	}
	return false
}

// PullImagesFromCache ...
func PullImagesFromCache(cache *MessageCache, limit int, channelID string) ([]image.Image, error) {
	images := make([]image.Image, 0, limit)

	messages, err := cache.Messages(channelID)
	if err != nil {
		return nil, err
	}

	for i := len(messages) - 1; i >= 0; i-- {
		v := messages[i]
		tmp, err := PullImagesFromMessage(limit, v)
		if err != nil {
			return nil, err
		}
		images = append(images, tmp...)

		// Decrement the image limit
		limit -= len(images)
		if limit <= 0 {
			break
		}
	}

	return images, nil
}

// HasImage returns if a message has an image
func HasImage(msg *discordgo.Message) bool {

	for _, embed := range msg.Embeds {
		if embed.Image != nil && embed.Image.URL != "" {
			return true
		}
		if embed.Thumbnail != nil && embed.Thumbnail.URL != "" {
			return true
		}
	}

	for _, v := range msg.Attachments {
		if HasImageSuffix(v.Filename) {
			return true
		}
	}

	for _, u := range urlRegex.FindAllString(msg.Content, -1) {
		if IsImageURL(u) {
			return true
		}
	}

	return false
}

// HasImageSuffix returns true if an image suffix is present
func HasImageSuffix(filename string) bool {
	for _, v := range ImageSuffixes {
		if strings.HasSuffix(filename, v) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package vmware

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"strings"
)

// Workstation9Driver is a driver that can run VMware Workstation 9
// on non-Windows platforms.
type Workstation9Driver struct {
	AppPath          string
	VdiskManagerPath string
	VmrunPath        string
}

func (d *Workstation9Driver) CompactDisk(diskPath string) error {
	defragCmd := exec.Command(d.VdiskManagerPath, "-d", diskPath)
	if _, _, err := d.runAndLog(defragCmd); err != nil {
		return err
	}

	shrinkCmd := exec.Command(d.VdiskManagerPath, "-k", diskPath)
	if _, _, err := d.runAndLog(shrinkCmd); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) CreateDisk(output string, size string) error {
	cmd := exec.Command(d.VdiskManagerPath, "-c", "-s", size, "-a", "lsilogic", "-t", "1", output)
	if _, _, err := d.runAndLog(cmd); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) IsRunning(vmxPath string) (bool, error) {
	vmxPath, err := filepath.Abs(vmxPath)
	if err != nil {
		return false, err
	}

	cmd := exec.Command(d.VmrunPath, "-T", "ws", "list")
	stdout, _, err := d.runAndLog(cmd)
	if err != nil {
		return false, err
	}

	for _, line := range strings.Split(stdout, "\n") {
		if line == vmxPath {
			return true, nil
		}
	}

	return false, nil
}

func (d *Workstation9Driver) Start(vmxPath string, headless bool) error {
	guiArgument := "gui"
	if headless {
		guiArgument = "nogui"
	}

	cmd := exec.Command(d.VmrunPath, "-T", "ws", "start", vmxPath, guiArgument)
	if _, _, err := d.runAndLog(cmd); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) Stop(vmxPath string) error {
	cmd := exec.Command(d.VmrunPath, "-T", "ws", "stop", vmxPath, "hard")
	if _, _, err := d.runAndLog(cmd); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) Verify() error {
	var err error
	if d.AppPath == "" {
		if d.AppPath, err = workstationFindVMware(); err != nil {
			return err
		}
	}

	if d.VmrunPath == "" {
		if d.VmrunPath, err = workstationFindVmrun(); err != nil {
			return err
		}
	}

	if d.VdiskManagerPath == "" {
		if d.VdiskManagerPath, err = workstationFindVdiskManager(); err != nil {
			return err
		}
	}

	// Check to see if it APPEARS to be licensed.
	if err := workstationCheckLicense(); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) ToolsIsoPath(flavor string) string {
	return workstationToolsIsoPath(flavor)
}

func (d *Workstation9Driver) DhcpLeasesPath(device string) string {
	return workstationDhcpLeasesPath(device)
}

func (d *Workstation9Driver) runAndLog(cmd *exec.Cmd) (string, string, error) {
	var stdout, stderr bytes.Buffer

	log.Printf("Executing: %s %v", cmd.Path, cmd.Args[1:])
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()

	stdoutString := strings.TrimSpace(stdout.String())
	stderrString := strings.TrimSpace(stderr.String())

	if _, ok := err.(*exec.ExitError); ok {
		err = fmt.Errorf("VMware error: %s", stderrString)
	}

	log.Printf("stdout: %s", stdoutString)
	log.Printf("stderr: %s", stderrString)

	return stdout.String(), stderr.String(), err
}
<commit_msg>builder/vmware: verify various paths exist for Workstation<commit_after>package vmware

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

// Workstation9Driver is a driver that can run VMware Workstation 9
// on non-Windows platforms.
type Workstation9Driver struct {
	AppPath          string
	VdiskManagerPath string
	VmrunPath        string
}

func (d *Workstation9Driver) CompactDisk(diskPath string) error {
	defragCmd := exec.Command(d.VdiskManagerPath, "-d", diskPath)
	if _, _, err := d.runAndLog(defragCmd); err != nil {
		return err
	}

	shrinkCmd := exec.Command(d.VdiskManagerPath, "-k", diskPath)
	if _, _, err := d.runAndLog(shrinkCmd); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) CreateDisk(output string, size string) error {
	cmd := exec.Command(d.VdiskManagerPath, "-c", "-s", size, "-a", "lsilogic", "-t", "1", output)
	if _, _, err := d.runAndLog(cmd); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) IsRunning(vmxPath string) (bool, error) {
	vmxPath, err := filepath.Abs(vmxPath)
	if err != nil {
		return false, err
	}

	cmd := exec.Command(d.VmrunPath, "-T", "ws", "list")
	stdout, _, err := d.runAndLog(cmd)
	if err != nil {
		return false, err
	}

	for _, line := range strings.Split(stdout, "\n") {
		if line == vmxPath {
			return true, nil
		}
	}

	return false, nil
}

func (d *Workstation9Driver) Start(vmxPath string, headless bool) error {
	guiArgument := "gui"
	if headless {
		guiArgument = "nogui"
	}

	cmd := exec.Command(d.VmrunPath, "-T", "ws", "start", vmxPath, guiArgument)
	if _, _, err := d.runAndLog(cmd); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) Stop(vmxPath string) error {
	cmd := exec.Command(d.VmrunPath, "-T", "ws", "stop", vmxPath, "hard")
	if _, _, err := d.runAndLog(cmd); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) Verify() error {
	var err error
	if d.AppPath == "" {
		if d.AppPath, err = workstationFindVMware(); err != nil {
			return err
		}
	}

	if d.VmrunPath == "" {
		if d.VmrunPath, err = workstationFindVmrun(); err != nil {
			return err
		}
	}

	if d.VdiskManagerPath == "" {
		if d.VdiskManagerPath, err = workstationFindVdiskManager(); err != nil {
			return err
		}
	}

	if _, err := os.Stat(d.AppPath); err != nil {
		return fmt.Errorf("VMware application not found: %s", d.AppPath)
	}

	if _, err := os.Stat(d.VmrunPath); err != nil {
		return fmt.Errorf("'vmrun' application not found: %s", d.VmrunPath)
	}

	if _, err := os.Stat(d.VdiskManagerPath); err != nil {
		return fmt.Errorf("'vmrun' application not found: %s", d.VdiskManagerPath)
	}

	// Check to see if it APPEARS to be licensed.
	if err := workstationCheckLicense(); err != nil {
		return err
	}

	return nil
}

func (d *Workstation9Driver) ToolsIsoPath(flavor string) string {
	return workstationToolsIsoPath(flavor)
}

func (d *Workstation9Driver) DhcpLeasesPath(device string) string {
	return workstationDhcpLeasesPath(device)
}

func (d *Workstation9Driver) runAndLog(cmd *exec.Cmd) (string, string, error) {
	var stdout, stderr bytes.Buffer

	log.Printf("Executing: %s %v", cmd.Path, cmd.Args[1:])
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()

	stdoutString := strings.TrimSpace(stdout.String())
	stderrString := strings.TrimSpace(stderr.String())

	if _, ok := err.(*exec.ExitError); ok {
		err = fmt.Errorf("VMware error: %s", stderrString)
	}

	log.Printf("stdout: %s", stdoutString)
	log.Printf("stderr: %s", stderrString)

	return stdout.String(), stderr.String(), err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
)

func largestRectangleArea(heights []int) int {
	n := len(heights)
	// minHeight[i][j] means the minimum height between [i, j)
	// so area[i][j] = (j-i)*minHeight[i][j]
	var maxArea int
	for i := 0; i < n; i++ {
		min := heights[i]
		for j := i + 1; j <= n; j++ {
			min = int(math.Min(float64(min), float64(heights[j-1])))
			if (j-i)*min > maxArea {
				maxArea = (j - i) * min
			}
		}
	}
	return maxArea
}

func main() {
	var h []int
	var expected int
	h, expected = []int{2, 1, 5, 6, 2, 3}, 10
	fmt.Printf("h: %v, expected: %d, actual: %d\n", h, expected, largestRectangleArea(h))
}
<commit_msg>solution: largest-rectangle-in-histogram<commit_after>package main

import (
	"fmt"
)

func largestRectangleArea(heights []int) int {
	n := len(heights)
	if n == 0 {
		return 0
	}
	var maxArea int
	var left, right int
	left = -1
	for right = 1; right < n && heights[right] >= heights[0]; right++ {
	}
	maxArea = (right - left - 1) * heights[0]
	for i := 1; i < n; i++ {
		if heights[i] > heights[i-1] {
			left = i - 1
			for right = i + 1; right < n && heights[right] >= heights[i]; right++ {
			}
		} else if heights[i] < heights[i-1] {
			for ; left >= 0 && heights[left] >= heights[i]; left-- {
			}
			for ; right < n && heights[right] >= heights[i]; right++ {
			}
		} else {
			// do nothing
		}
		if (right-left-1)*heights[i] > maxArea {
			maxArea = (right - left - 1) * heights[i]
		}
	}
	return maxArea
}

func main() {
	var h []int
	var expected int
	h, expected = []int{2, 1, 5, 6, 2, 3}, 10
	fmt.Printf("h: %v, expected: %d, actual: %d\n", h, expected, largestRectangleArea(h))
	h, expected = []int{}, 0
	fmt.Printf("h: %v, expected: %d, actual: %d\n", h, expected, largestRectangleArea(h))
}
<|endoftext|>