<commit_before>package dockerutils

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/fsouza/go-dockerclient"
)

type DockerEnvironment struct {
	DockerHost      string
	DockerTlsVerify string
	DockerCertPath  string
}

func (this *DockerEnvironment) IsDockerTls() bool {
	return IsDockerTls(this.DockerTlsVerify)
}

func (this *DockerEnvironment) EnvStrings() []string {
	envStrings := []string{
		fmt.Sprintf("DOCKER_HOST=%s", this.DockerHost),
	}
	if this.IsDockerTls() {
		envStrings = append(
			envStrings,
			fmt.Sprintf("DOCKER_TLS_VERIFY=%s", this.DockerTlsVerify),
			fmt.Sprintf("DOCKER_CERT_PATH=%s", this.DockerCertPath),
		)
	}
	return envStrings
}

func (this *DockerEnvironment) HostVolumeToVolume() map[string]string {
	if !this.IsDockerTls() || this.DockerCertPath == "" {
		return nil
	}
	return map[string]string{
		this.DockerCertPath: this.DockerCertPath,
	}
}

// TODO(pedge): we are assuming the DOCKER_CERT_PATH is a directory within the host
// regardless of if we are running in a docker container or not, this should actually
// still work but this is not great
func GetDockerEnvironment() (*DockerEnvironment, error) {
	dockerHost := os.Getenv("DOCKER_HOST")
	if dockerHost == "" {
		dockerHost = "unix:///var/run/docker.sock"
	}
	dockerTlsVerify := os.Getenv("DOCKER_TLS_VERIFY")
	var dockerCertPath string
	var err error
	if IsDockerTls(dockerTlsVerify) {
		dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
		if dockerCertPath == "" {
			home := os.Getenv("HOME")
			if home == "" {
				return nil, errors.New("dockerutils: environment variable HOME must be set if DOCKER_CERT_PATH is not set")
			}
			dockerCertPath = filepath.Join(home, ".docker")
			dockerCertPath, err = filepath.Abs(dockerCertPath)
			if err != nil {
				return nil, err
			}
		}
	}
	return &DockerEnvironment{
		DockerHost:      dockerHost,
		DockerTlsVerify: dockerTlsVerify,
		DockerCertPath:  dockerCertPath,
	}, nil
}

func NewDockerClientFromEnv(apiVersion string) (*docker.Client, error) {
	dockerEnvironment, err := GetDockerEnvironment()
	if err != nil {
		return nil, err
	}
	return NewDockerClient(dockerEnvironment, apiVersion)
}

func NewDockerClient(dockerEnvironment *DockerEnvironment, apiVersion string) (*docker.Client, error) {
	dockerHost := dockerEnvironment.DockerHost
	if dockerEnvironment.IsDockerTls() {
		parts := strings.SplitN(dockerHost, "://", 2)
		if len(parts) != 2 {
			return nil, fmt.Errorf("dockerutils: could not split %s into two parts by ://", dockerHost)
		}
		dockerHost = fmt.Sprintf("https://%s", parts[1])
		dockerCertPath := dockerEnvironment.DockerCertPath
		cert := filepath.Join(dockerCertPath, "cert.pem")
		key := filepath.Join(dockerCertPath, "key.pem")
		ca := filepath.Join(dockerCertPath, "ca.pem")
		if err := checkFileExists(dockerCertPath); err != nil {
			return nil, err
		}
		if err := checkFileExists(cert); err != nil {
			return nil, err
		}
		if err := checkFileExists(key); err != nil {
			return nil, err
		}
		if err := checkFileExists(ca); err != nil {
			return nil, err
		}
		return docker.NewVersionedTLSClient(dockerHost, cert, key, ca, apiVersion)
	}
	return docker.NewVersionedClient(dockerHost, apiVersion)
}

func IsDockerTls(dockerTlsVerify string) bool {
	// TODO(pedge): is any non-empty value legal? any non-zero value?
	return dockerTlsVerify == "1"
}

func DockerExposedPorts(expose []uint16) map[docker.Port]struct{} {
	if expose == nil || len(expose) == 0 {
		return nil
	}
	m := make(map[docker.Port]struct{})
	for _, port := range expose {
		m[docker.Port(fmt.Sprintf("%v/tcp", port))] = emptyStruct()
	}
	return m
}

func DockerVolumes(volumes []string) map[string]struct{} {
	if volumes == nil || len(volumes) == 0 {
		return nil
	}
	m := make(map[string]struct{})
	for _, volume := range volumes {
		m[volume] = emptyStruct()
	}
	return m
}

func DockerVolumesFrom(volumesFrom []string) string {
	return strings.Join(volumesFrom, ",")
}

func DockerBinds(hostVolumeToVolume map[string]string) []string {
	if hostVolumeToVolume == nil || len(hostVolumeToVolume) == 0 {
		return nil
	}
	binds := make([]string, len(hostVolumeToVolume))
	i := 0
	for hostVolume, volume := range hostVolumeToVolume {
		binds[i] = fmt.Sprintf("%s:%s:rw", hostVolume, volume)
		i++
	}
	return binds
}

// ***** PRIVATE *****

func checkFileExists(path string) error {
	exists, err := isFileExists(path)
	if err != nil {
		return err
	}
	if !exists {
		return fmt.Errorf("docker: file %s does not exist", path)
	}
	return nil
}

func isFileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// TODO(pedge): what?
func emptyStruct() struct{} {
	var str struct{}
	return str
}
<commit_msg>ports<commit_after>package dockerutils

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/fsouza/go-dockerclient"
)

type DockerEnvironment struct {
	DockerHost      string
	DockerTlsVerify string
	DockerCertPath  string
}

func (this *DockerEnvironment) IsDockerTls() bool {
	return IsDockerTls(this.DockerTlsVerify)
}

func (this *DockerEnvironment) EnvStrings() []string {
	envStrings := []string{
		fmt.Sprintf("DOCKER_HOST=%s", this.DockerHost),
	}
	if this.IsDockerTls() {
		envStrings = append(
			envStrings,
			fmt.Sprintf("DOCKER_TLS_VERIFY=%s", this.DockerTlsVerify),
			fmt.Sprintf("DOCKER_CERT_PATH=%s", this.DockerCertPath),
		)
	}
	return envStrings
}

func (this *DockerEnvironment) HostVolumeToVolume() map[string]string {
	if !this.IsDockerTls() || this.DockerCertPath == "" {
		return nil
	}
	return map[string]string{
		this.DockerCertPath: this.DockerCertPath,
	}
}

// TODO(pedge): we are assuming the DOCKER_CERT_PATH is a directory within the host
// regardless of if we are running in a docker container or not, this should actually
// still work but this is not great
func GetDockerEnvironment() (*DockerEnvironment, error) {
	dockerHost := os.Getenv("DOCKER_HOST")
	if dockerHost == "" {
		dockerHost = "unix:///var/run/docker.sock"
	}
	dockerTlsVerify := os.Getenv("DOCKER_TLS_VERIFY")
	var dockerCertPath string
	var err error
	if IsDockerTls(dockerTlsVerify) {
		dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
		if dockerCertPath == "" {
			home := os.Getenv("HOME")
			if home == "" {
				return nil, errors.New("dockerutils: environment variable HOME must be set if DOCKER_CERT_PATH is not set")
			}
			dockerCertPath = filepath.Join(home, ".docker")
			dockerCertPath, err = filepath.Abs(dockerCertPath)
			if err != nil {
				return nil, err
			}
		}
	}
	return &DockerEnvironment{
		DockerHost:      dockerHost,
		DockerTlsVerify: dockerTlsVerify,
		DockerCertPath:  dockerCertPath,
	}, nil
}

func NewDockerClientFromEnv(apiVersion string) (*docker.Client, error) {
	dockerEnvironment, err := GetDockerEnvironment()
	if err != nil {
		return nil, err
	}
	return NewDockerClient(dockerEnvironment, apiVersion)
}

func NewDockerClient(dockerEnvironment *DockerEnvironment, apiVersion string) (*docker.Client, error) {
	dockerHost := dockerEnvironment.DockerHost
	if dockerEnvironment.IsDockerTls() {
		parts := strings.SplitN(dockerHost, "://", 2)
		if len(parts) != 2 {
			return nil, fmt.Errorf("dockerutils: could not split %s into two parts by ://", dockerHost)
		}
		dockerHost = fmt.Sprintf("https://%s", parts[1])
		dockerCertPath := dockerEnvironment.DockerCertPath
		cert := filepath.Join(dockerCertPath, "cert.pem")
		key := filepath.Join(dockerCertPath, "key.pem")
		ca := filepath.Join(dockerCertPath, "ca.pem")
		if err := checkFileExists(dockerCertPath); err != nil {
			return nil, err
		}
		if err := checkFileExists(cert); err != nil {
			return nil, err
		}
		if err := checkFileExists(key); err != nil {
			return nil, err
		}
		if err := checkFileExists(ca); err != nil {
			return nil, err
		}
		return docker.NewVersionedTLSClient(dockerHost, cert, key, ca, apiVersion)
	}
	return docker.NewVersionedClient(dockerHost, apiVersion)
}

func IsDockerTls(dockerTlsVerify string) bool {
	return dockerTlsVerify != ""
}

func DockerPorts(expose []uint16, ports []string) (map[docker.Port]struct{}, map[docker.Port][]docker.PortBinding, error) {
	if (expose == nil || len(expose) == 0) && (ports == nil || len(ports) == 0) {
		return nil, nil, nil
	}
	m := make(map[docker.Port]struct{})
	n := make(map[docker.Port][]docker.PortBinding)
	for _, port := range expose {
		m[docker.Port(fmt.Sprintf("%v/tcp", port))] = emptyStruct()
	}
	for _, port := range ports {
		split := strings.Split(port, ":")
		if len(split) != 2 {
			return nil, nil, fmt.Errorf("invalid port: %s", port)
		}
		hostPort, err := strconv.ParseInt(split[0], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		containerPort, err := strconv.ParseInt(split[1], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		dockerPort := docker.Port(fmt.Sprintf("%v/tcp", containerPort))
		m[dockerPort] = emptyStruct()
		n[dockerPort] = []docker.PortBinding{
			docker.PortBinding{
				HostPort: fmt.Sprintf("%d", hostPort),
			},
		}
	}
	return m, n, nil
}

func DockerVolumes(volumes []string) map[string]struct{} {
	if volumes == nil || len(volumes) == 0 {
		return nil
	}
	m := make(map[string]struct{})
	for _, volume := range volumes {
		m[volume] = emptyStruct()
	}
	return m
}

func DockerVolumesFrom(volumesFrom []string) string {
	return strings.Join(volumesFrom, ",")
}

func DockerBinds(hostVolumeToVolume map[string]string) []string {
	if hostVolumeToVolume == nil || len(hostVolumeToVolume) == 0 {
		return nil
	}
	binds := make([]string, len(hostVolumeToVolume))
	i := 0
	for hostVolume, volume := range hostVolumeToVolume {
		binds[i] = fmt.Sprintf("%s:%s:rw", hostVolume, volume)
		i++
	}
	return binds
}

// ***** PRIVATE *****

func checkFileExists(path string) error {
	exists, err := isFileExists(path)
	if err != nil {
		return err
	}
	if !exists {
		return fmt.Errorf("docker: file %s does not exist", path)
	}
	return nil
}

func isFileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// TODO(pedge): what?
func emptyStruct() struct{} {
	var str struct{}
	return str
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

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

func resourceAwsGuardDutyFilter() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsGuardDutyFilterCreate,
		Read:   resourceAwsGuardDutyFilterRead,
		// Update: resourceAwsGuardDutyFilterUpdate,
		Delete: resourceAwsGuardDutyFilterDelete,

		// Importer: &schema.ResourceImporter{
		// 	State: schema.ImportStatePassthrough,
		// },
		Schema: map[string]*schema.Schema{ // TODO: add validations
			// "account_id": { // idk, do we need it
			// 	Type:         schema.TypeString,
			// 	Required:     true,
			// 	ForceNew:     true,
			// 	ValidateFunc: validateAwsAccountId,
			// },
			"detector_id": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
			},
			"description": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
			},
			"tags": tagsSchemaForceNew(),
			"finding_criteria": {
				Type:     schema.TypeList,
				MaxItems: 1,
				Required: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"criterion": &schema.Schema{
							Type:     schema.TypeSet,
							Optional: true,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"condition": &schema.Schema{
										Type:     schema.TypeSet,
										Optional: true,
										Elem: &schema.Resource{
											Schema: map[string]*schema.Schema{
												"equals": {
													Type:     schema.TypeList,
													Optional: true,
													Elem:     &schema.Schema{Type: schema.TypeString},
												},
												"greater_than": {
													Type:     schema.TypeInt,
													Optional: true,
												},
												"greater_than_or_equal": {
													Type:     schema.TypeInt,
													Optional: true,
												},
												"less_than": {
													Type:     schema.TypeInt,
													Optional: true,
												},
												"less_than_or_equal": {
													Type:     schema.TypeInt,
													Optional: true,
												},
												"not_equals": {
													Type:     schema.TypeList,
													Optional: true,
													Elem:     &schema.Schema{Type: schema.TypeString},
												},
											},
										},
									},
								},
							},
						},
					},
				},
			},
			"action": {
				Type:     schema.TypeString, // should have a new type or a validation for NOOP/ARCHIVE
				Optional: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
			},
			"rank": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
			},
		},
		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(60 * time.Second),
			Update: schema.DefaultTimeout(60 * time.Second),
		},
	}
}

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

	input := guardduty.CreateFilterInput{
		DetectorId:  aws.String(d.Get("detector_id").(string)),
		Name:        aws.String(d.Get("name").(string)),
		Description: aws.String(d.Get("description").(string)),
		Rank:        aws.Int64(int64(d.Get("rank").(int))),
	}

	// building `FindingCriteria`
	findingCriteria := d.Get("finding_criteria").([]interface{})[0].(map[string]interface{})
	criterion := findingCriteria["criterion"].(*schema.Set).List()[0].(map[string]interface{})
	condition := criterion["condition"].(*schema.Set).List()[0].(map[string]interface{})

	interfaceForEquals := condition["equals"].([]interface{})

	equals := make([]string, len(interfaceForEquals))
	for i, v := range interfaceForEquals {
		equals[i] = string(v.(string)) // Maybe aws.string?
	}

	interfaceForNotEquals := condition["equals"].([]interface{})

	notEquals := make([]string, len(interfaceForNotEquals))
	for i, v := range interfaceForNotEquals {
		notEquals[i] = string(v.(string))
	}

	if len(d.Get("tags")) > 0 {
		tagsInterface := d.Get("tags").(map[string]interface{})

		tags := make(map[string]*string, len(tagsInterface))
		for i, v := range tagsInterface {
			tags[i] = aws.String(v.(string))
		}

		input.Tags = tags
	}

	input.FindingCriteria = &guardduty.FindingCriteria{
		Criterion: map[string]*guardduty.Condition{
			"condition": &guardduty.Condition{
				Equals:             aws.StringSlice(equals),
				GreaterThan:        aws.Int64(int64(condition["greater_than"].(int))),
				GreaterThanOrEqual: aws.Int64(int64(condition["greater_than_or_equal"].(int))),
				LessThan:           aws.Int64(int64(condition["less_than"].(int))),
				LessThanOrEqual:    aws.Int64(int64(condition["less_than_or_equal"].(int))),
				NotEquals:          aws.StringSlice(notEquals),
			},
		},
	}
	log.Printf("[DEBUG] Creating FindingCriteria map: %#v", findingCriteria)

	// Setting the default value for `action`
	action := "NOOP"

	if len(d.Get("action").(string)) > 0 {
		action = d.Get("action").(string)
	}

	input.Action = aws.String(action)

	log.Printf("[DEBUG] Creating GuardDuty Filter: %s", input)
	output, err := conn.CreateFilter(&input)
	if err != nil {
		return fmt.Errorf("Creating GuardDuty Filter failed: %s", err.Error())
	}
	d.SetId(*output.Name)

	return resourceAwsGuardDutyFilterRead(d, meta)
}

func resourceAwsGuardDutyFilterRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).guarddutyconn
	detectorId := d.Get("detectorId").(string)
	filterName := d.Get("filterName").(string)

	input := guardduty.GetFilterInput{
		DetectorId: aws.String(detectorId),
		FilterName: aws.String(filterName),
	}

	log.Printf("[DEBUG] Reading GuardDuty Filter: %s", input)
	filter, err := conn.GetFilter(&input)

	if err != nil {
		if isAWSErr(err, guardduty.ErrCodeBadRequestException, "The request is rejected because the input detectorId is not owned by the current account.") {
			log.Printf("[WARN] GuardDuty detector %q not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Reading GuardDuty Filter '%s' failed: %s", filterName, err.Error())
	}

	d.Set("action", filter.Action)
	d.Set("description", filter.Description)
	d.Set("rank", filter.Rank)
	d.Set("name", d.Id())

	// need to find a way how to fill it interface{}
	// d.Set("account_id", filter.FindingCriteria)

	// FindingCriteria.Criterion
	// Eq
	// Gt
	// Gte
	// Lt
	// Lte
	// Neq

	return nil
}

// func resourceAwsGuardDutyFilterUpdate(d *schema.ResourceData, meta interface{}) error {
// 	conn := meta.(*AWSClient).guarddutyconn
//
// 	accountID, detectorID, err := decodeGuardDutyMemberID(d.Id())
// 	if err != nil {
// 		return err
// 	}
//
// 	if d.HasChange("invite") {
// 		if d.Get("invite").(bool) {
// 			input := &guardduty.InviteMembersInput{
// 				DetectorId:               aws.String(detectorID),
// 				AccountIds:               []*string{aws.String(accountID)},
// 				DisableEmailNotification: aws.Bool(d.Get("disable_email_notification").(bool)),
// 				Message:                  aws.String(d.Get("invitation_message").(string)),
// 			}
//
// 			log.Printf("[INFO] Inviting GuardDuty Member: %s", input)
// 			output, err := conn.InviteMembers(input)
// 			if err != nil {
// 				return fmt.Errorf("error inviting GuardDuty Member %q: %s", d.Id(), err)
// 			}
//
// 			// {"unprocessedAccounts":[{"result":"The request is rejected because the current account has already invited or is already the GuardDuty master of the given member account ID.","accountId":"067819342479"}]}
// 			if len(output.UnprocessedAccounts) > 0 {
// 				return fmt.Errorf("error inviting GuardDuty Member %q: %s", d.Id(), aws.StringValue(output.UnprocessedAccounts[0].Result))
// 			}
// 		} else {
// 			input := &guardduty.DisassociateMembersInput{
// 				AccountIds: []*string{aws.String(accountID)},
// 				DetectorId: aws.String(detectorID),
// 			}
// 			log.Printf("[INFO] Disassociating GuardDuty Member: %s", input)
// 			_, err := conn.DisassociateMembers(input)
// 			if err != nil {
// 				return fmt.Errorf("error disassociating GuardDuty Member %q: %s", d.Id(), err)
// 			}
// 		}
// 	}
//
// 	return resourceAwsGuardDutyFilterRead(d, meta)
// }

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

	accountID, detectorID, err := decodeGuardDutyMemberID(d.Id())
	if err != nil {
		return err
	}

	input := guardduty.DeleteMembersInput{
		AccountIds: []*string{aws.String(accountID)},
		DetectorId: aws.String(detectorID),
	}

	log.Printf("[DEBUG] Delete GuardDuty Member: %s", input)
	_, err = conn.DeleteMembers(&input)
	if err != nil {
		return fmt.Errorf("Deleting GuardDuty Member '%s' failed: %s", d.Id(), err.Error())
	}
	return nil
}
<commit_msg>Fixed tags assignment<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

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

func resourceAwsGuardDutyFilter() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsGuardDutyFilterCreate,
		Read:   resourceAwsGuardDutyFilterRead,
		// Update: resourceAwsGuardDutyFilterUpdate,
		Delete: resourceAwsGuardDutyFilterDelete,

		// Importer: &schema.ResourceImporter{
		// 	State: schema.ImportStatePassthrough,
		// },
		Schema: map[string]*schema.Schema{ // TODO: add validations
			// "account_id": { // idk, do we need it
			// 	Type:         schema.TypeString,
			// 	Required:     true,
			// 	ForceNew:     true,
			// 	ValidateFunc: validateAwsAccountId,
			// },
			"detector_id": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
			},
			"description": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
			},
			"tags": tagsSchemaForceNew(),
			"finding_criteria": {
				Type:     schema.TypeList,
				MaxItems: 1,
				Required: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"criterion": &schema.Schema{
							Type:     schema.TypeSet,
							Optional: true,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"condition": &schema.Schema{
										Type:     schema.TypeSet,
										Optional: true,
										Elem: &schema.Resource{
											Schema: map[string]*schema.Schema{
												"equals": {
													Type:     schema.TypeList,
													Optional: true,
													Elem:     &schema.Schema{Type: schema.TypeString},
												},
												"greater_than": {
													Type:     schema.TypeInt,
													Optional: true,
												},
												"greater_than_or_equal": {
													Type:     schema.TypeInt,
													Optional: true,
												},
												"less_than": {
													Type:     schema.TypeInt,
													Optional: true,
												},
												"less_than_or_equal": {
													Type:     schema.TypeInt,
													Optional: true,
												},
												"not_equals": {
													Type:     schema.TypeList,
													Optional: true,
													Elem:     &schema.Schema{Type: schema.TypeString},
												},
											},
										},
									},
								},
							},
						},
					},
				},
			},
			"action": {
				Type:     schema.TypeString, // should have a new type or a validation for NOOP/ARCHIVE
				Optional: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
			},
			"rank": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true, // perhaps remove here and below, when Update is back
			},
		},
		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(60 * time.Second),
			Update: schema.DefaultTimeout(60 * time.Second),
		},
	}
}

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

	input := guardduty.CreateFilterInput{
		DetectorId:  aws.String(d.Get("detector_id").(string)),
		Name:        aws.String(d.Get("name").(string)),
		Description: aws.String(d.Get("description").(string)),
		Rank:        aws.Int64(int64(d.Get("rank").(int))),
	}

	// building `FindingCriteria`
	findingCriteria := d.Get("finding_criteria").([]interface{})[0].(map[string]interface{})
	criterion := findingCriteria["criterion"].(*schema.Set).List()[0].(map[string]interface{})
	condition := criterion["condition"].(*schema.Set).List()[0].(map[string]interface{})

	interfaceForEquals := condition["equals"].([]interface{})

	equals := make([]string, len(interfaceForEquals))
	for i, v := range interfaceForEquals {
		equals[i] = string(v.(string)) // Maybe aws.string?
	}

	interfaceForNotEquals := condition["equals"].([]interface{})

	notEquals := make([]string, len(interfaceForNotEquals))
	for i, v := range interfaceForNotEquals {
		notEquals[i] = string(v.(string))
	}

	tagsInterface := d.Get("tags").(map[string]interface{})
	if len(tagsInterface) > 0 {
		tags := make(map[string]*string, len(tagsInterface))
		for i, v := range tagsInterface {
			tags[i] = aws.String(v.(string))
		}

		input.Tags = tags
	}

	input.FindingCriteria = &guardduty.FindingCriteria{
		Criterion: map[string]*guardduty.Condition{
			"condition": &guardduty.Condition{
				Equals:             aws.StringSlice(equals),
				GreaterThan:        aws.Int64(int64(condition["greater_than"].(int))),
				GreaterThanOrEqual: aws.Int64(int64(condition["greater_than_or_equal"].(int))),
				LessThan:           aws.Int64(int64(condition["less_than"].(int))),
				LessThanOrEqual:    aws.Int64(int64(condition["less_than_or_equal"].(int))),
				NotEquals:          aws.StringSlice(notEquals),
			},
		},
	}
	log.Printf("[DEBUG] Creating FindingCriteria map: %#v", findingCriteria)

	// Setting the default value for `action`
	action := "NOOP"

	if len(d.Get("action").(string)) > 0 {
		action = d.Get("action").(string)
	}

	input.Action = aws.String(action)

	log.Printf("[DEBUG] Creating GuardDuty Filter: %s", input)
	output, err := conn.CreateFilter(&input)
	if err != nil {
		return fmt.Errorf("Creating GuardDuty Filter failed: %s", err.Error())
	}
	d.SetId(*output.Name)

	return resourceAwsGuardDutyFilterRead(d, meta)
}

func resourceAwsGuardDutyFilterRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).guarddutyconn
	detectorId := d.Get("detectorId").(string)
	filterName := d.Get("filterName").(string)

	input := guardduty.GetFilterInput{
		DetectorId: aws.String(detectorId),
		FilterName: aws.String(filterName),
	}

	log.Printf("[DEBUG] Reading GuardDuty Filter: %s", input)
	filter, err := conn.GetFilter(&input)

	if err != nil {
		if isAWSErr(err, guardduty.ErrCodeBadRequestException, "The request is rejected because the input detectorId is not owned by the current account.") {
			log.Printf("[WARN] GuardDuty detector %q not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Reading GuardDuty Filter '%s' failed: %s", filterName, err.Error())
	}

	d.Set("action", filter.Action)
	d.Set("description", filter.Description)
	d.Set("rank", filter.Rank)
	d.Set("name", d.Id())

	// need to find a way how to fill it interface{}
	// d.Set("account_id", filter.FindingCriteria)

	// FindingCriteria.Criterion
	// Eq
	// Gt
	// Gte
	// Lt
	// Lte
	// Neq

	return nil
}

// func resourceAwsGuardDutyFilterUpdate(d *schema.ResourceData, meta interface{}) error {
// 	conn := meta.(*AWSClient).guarddutyconn
//
// 	accountID, detectorID, err := decodeGuardDutyMemberID(d.Id())
// 	if err != nil {
// 		return err
// 	}
//
// 	if d.HasChange("invite") {
// 		if d.Get("invite").(bool) {
// 			input := &guardduty.InviteMembersInput{
// 				DetectorId:               aws.String(detectorID),
// 				AccountIds:               []*string{aws.String(accountID)},
// 				DisableEmailNotification: aws.Bool(d.Get("disable_email_notification").(bool)),
// 				Message:                  aws.String(d.Get("invitation_message").(string)),
// 			}
//
// 			log.Printf("[INFO] Inviting GuardDuty Member: %s", input)
// 			output, err := conn.InviteMembers(input)
// 			if err != nil {
// 				return fmt.Errorf("error inviting GuardDuty Member %q: %s", d.Id(), err)
// 			}
//
// 			// {"unprocessedAccounts":[{"result":"The request is rejected because the current account has already invited or is already the GuardDuty master of the given member account ID.","accountId":"067819342479"}]}
// 			if len(output.UnprocessedAccounts) > 0 {
// 				return fmt.Errorf("error inviting GuardDuty Member %q: %s", d.Id(), aws.StringValue(output.UnprocessedAccounts[0].Result))
// 			}
// 		} else {
// 			input := &guardduty.DisassociateMembersInput{
// 				AccountIds: []*string{aws.String(accountID)},
// 				DetectorId: aws.String(detectorID),
// 			}
// 			log.Printf("[INFO] Disassociating GuardDuty Member: %s", input)
// 			_, err := conn.DisassociateMembers(input)
// 			if err != nil {
// 				return fmt.Errorf("error disassociating GuardDuty Member %q: %s", d.Id(), err)
// 			}
// 		}
// 	}
//
// 	return resourceAwsGuardDutyFilterRead(d, meta)
// }

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

	accountID, detectorID, err := decodeGuardDutyMemberID(d.Id())
	if err != nil {
		return err
	}

	input := guardduty.DeleteMembersInput{
		AccountIds: []*string{aws.String(accountID)},
		DetectorId: aws.String(detectorID),
	}

	log.Printf("[DEBUG] Delete GuardDuty Member: %s", input)
	_, err = conn.DeleteMembers(&input)
	if err != nil {
		return fmt.Errorf("Deleting GuardDuty Member '%s' failed: %s", d.Id(), err.Error())
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/fabiofalci/sconsify/sconsify"
	"github.com/fabiofalci/sconsify/infrastructure"
	"github.com/fabiofalci/sconsify/ui"
	"github.com/fabiofalci/sconsify/spotify/mock"
	"os/exec"
	"bytes"
)

func main() {
	infrastructure.ProcessSconsifyrc()

	fmt.Println("Sconsify - your awesome Spotify music service in a text-mode interface.")
	events := sconsify.InitialiseEvents()

	go mock.Initialise(events)

	var output bytes.Buffer
	go generateKeys(&output)
	ui := ui.InitialiseConsoleUserInterface(events)
	sconsify.StartMainLoop(events, ui, false)
	println(output.String())
}

func generateKeys(output *bytes.Buffer) {
	time.Sleep(2 * time.Second)

	cmd("h")
	cmd("h")
	cmd("g")
	cmd("g")
	if !ui.CuiAssertSelectedPlaylist("Bob Marley") {
		output.WriteString("Playlist Bob Marley not found on position 1")
		cmd("q")
	}
	time.Sleep(2 * time.Second)

	cmd("j")
	if !ui.CuiAssertSelectedPlaylist("My folder") {
		output.WriteString("Playlist My folder not found on position 2")
		cmd("q")
	}
	time.Sleep(2 * time.Second)

	cmd("space")
	if !ui.CuiAssertSelectedPlaylist("[My folder]") {
		output.WriteString("Playlist [My folder] not found on position 2")
		cmd("q")
	}
	time.Sleep(2 * time.Second)

	cmd("space")
	if !ui.CuiAssertSelectedPlaylist("My folder") {
		output.WriteString("Playlist My folder not found on position 2")
		cmd("q")
	}
	time.Sleep(2 * time.Second)

	cmd("q")
}

func cmd(key string) {
	exec.Command("xdotool", "key", key).Run()
}
<commit_msg>Make test sleep a function<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/fabiofalci/sconsify/sconsify"
	"github.com/fabiofalci/sconsify/infrastructure"
	"github.com/fabiofalci/sconsify/ui"
	"github.com/fabiofalci/sconsify/spotify/mock"
	"os/exec"
	"bytes"
)

func main() {
	infrastructure.ProcessSconsifyrc()

	fmt.Println("Sconsify - your awesome Spotify music service in a text-mode interface.")
	events := sconsify.InitialiseEvents()

	go mock.Initialise(events)

	var output bytes.Buffer
	go generateKeys(&output)
	ui := ui.InitialiseConsoleUserInterface(events)
	sconsify.StartMainLoop(events, ui, false)
	println(output.String())
}

func generateKeys(output *bytes.Buffer) {
	sleep()

	cmd("h")
	cmd("h")
	cmd("g")
	cmd("g")
	if !ui.CuiAssertSelectedPlaylist("Bob Marley") {
		output.WriteString("Playlist Bob Marley not found on position 1")
		cmd("q")
	}
	sleep()

	cmd("j")
	if !ui.CuiAssertSelectedPlaylist("My folder") {
		output.WriteString("Playlist My folder not found on position 2")
		cmd("q")
	}
	sleep()

	cmd("space")
	if !ui.CuiAssertSelectedPlaylist("[My folder]") {
		output.WriteString("Playlist [My folder] not found on position 2")
		cmd("q")
	}
	sleep()

	cmd("space")
	if !ui.CuiAssertSelectedPlaylist("My folder") {
		output.WriteString("Playlist My folder not found on position 2")
		cmd("q")
	}
	sleep()

	cmd("q")
}

func sleep() {
	time.Sleep(1 * time.Second)
}

func cmd(key string) {
	exec.Command("xdotool", "key", key).Run()
}
<|endoftext|>


<commit_before>package commands

import (
	"flag"
	"fmt"
	"net/rpc"
	"os"
	"path/filepath"
	"time"

	"github.com/hamo/capsule/instance"
)

var (
	GlobalCapsuledDir  = filepath.Join("usr", "lib", "capsule", "libexec")
	GlobalCapsuledPath = filepath.Join(GlobalCapsuledDir, "capsuled")
)

var createCommand CapsuleCommand = CapsuleCommand{
	Handler:     cmdCreate,
	Description: "Create a new capsule",
}

func init() {
	RegisterCommand("create", &createCommand)
}

func cmdCreate(args []string, cmdEnv *CommandEnv) error {
	logger := cmdEnv.Logger

	createFlag := flag.NewFlagSet("create command", flag.ExitOnError)

	var (
		flInstanceName string
		flKernelName   string

		flMemorySize int

		flCmdline string
	)

	createFlag.StringVar(&flInstanceName, "name", "", "instance name")
	createFlag.StringVar(&flKernelName, "kernel", "", "kernel name")

	createFlag.IntVar(&flMemorySize, "m", 512, "memory size")

	createFlag.StringVar(&flCmdline, "cmdline", "", "cmdline")

	createFlag.Parse(args)

	if flInstanceName == "" {
		fmt.Fprintf(os.Stderr, "Please provide new instance name.\n\n")
		createFlag.PrintDefaults()
		os.Exit(1)
	}

	if flKernelName == "" {
		fmt.Fprintf(os.Stderr, "Please provide kernel name used by new instance.\n\n")
		createFlag.PrintDefaults()
		os.Exit(1)
	}

	instancesCatalog, err := cmdEnv.BaseCatalog.Dir("instances")
	if err != nil {
		logger.Fatalf("create instances catalog failed: %s\n", err)
	}

	if _, err := instancesCatalog.TryDir(flInstanceName); err == nil {
		logger.Fatalf("target instance name %s exists.\n", flInstanceName)
	}

	myInstanceCatalog, err := instancesCatalog.Dir(flInstanceName)
	if err != nil {
		logger.Fatalf("create target instance catalog failed: %s\n", err)
	}

	kernelsCatalog, err := cmdEnv.BaseCatalog.Dir("kernels")
	if err != nil {
		myInstanceCatalog.Cleanup(true)
		logger.Fatalf("read kernels catalog failed: %s\n", err)
	}

	myKernelCatalog, err := kernelsCatalog.TryDir(flKernelName)
	if err != nil {
		myInstanceCatalog.Cleanup(true)
		logger.Fatalf("read kernel %s catalog failed: %s\n", flKernelName, err)
	}

	i := instance.New(flInstanceName)
	i.Kernel = flKernelName
	i.Cmdline = flCmdline

	if flMemorySize < 512 {
		// FIXME: support huge initrd
		cmdEnv.Logger.Infoln("workaround: force memory size to 512M. ")
		i.MemorySize = 512
	} else {
		i.MemorySize = flMemorySize
	}

	i.InstanceCatalog = myInstanceCatalog
	i.KernelCatalog = myKernelCatalog

	// Find capsuled
	// it should be either placed $CAPSULE_ROOT/capsuled/capsuled or
	// /usr/lib/capsule/libexec/capusled
	// Pass its parent dir to qemu
	capsuledDir := filepath.Join(cmdEnv.BaseCatalog.Path, "capsuled")
	if fi, err := os.Stat(filepath.Join(capsuledDir, "capsuled")); err != nil || !fi.Mode().IsRegular() {
		// Can not find capsuled at $CAPSULE_ROOT/capsuled/capsuled
		if fi, err := os.Stat(GlobalCapsuledPath); err != nil || !fi.Mode().IsRegular() {
			cmdEnv.Logger.Fatalln("can not find capsuled")
		} else {
			capsuledDir = GlobalCapsuledDir
		}
	}
	i.SysinitDir = capsuledDir

	err = i.Create()
	if err != nil {
		panic(err)
	}

	// FIXME: ugly workaround to wait for qemu start
	time.Sleep(2 * time.Second)

	controlSock, err := myInstanceCatalog.File("control.sock", false)
	if err != nil {
		panic(err)
	}

	client, err := rpc.Dial("unix", controlSock)
	if err != nil {
		panic(err)
	}

	var d time.Duration
	err = client.Call("Server.Alive", struct{}{}, &d)
	if err != nil {
		panic(err)
	}

	cmdEnv.Logger.Infoln("Yoo, we are alive.")

	return nil
}

func createUsage() {

}
<commit_msg>commands: create CUI cleanup and add instance cleanup code<commit_after>package commands

import (
	"flag"
	"fmt"
	"net/rpc"
	"os"
	"path/filepath"
	"time"

	"github.com/hamo/capsule/instance"

	"github.com/Sirupsen/logrus"
)

var (
	GlobalCapsuledDir  = filepath.Join("usr", "lib", "capsule", "libexec")
	GlobalCapsuledPath = filepath.Join(GlobalCapsuledDir, "capsuled")
)

var createCommand CapsuleCommand = CapsuleCommand{
	Handler:     cmdCreate,
	Description: "Create a new capsule",
}

func init() {
	RegisterCommand("create", &createCommand)
}

func cmdCreate(args []string, cmdEnv *CommandEnv) error {
	logger := cmdEnv.Logger

	createFlag := flag.NewFlagSet("create command", flag.ExitOnError)

	var (
		flInstanceName string
		flKernelName   string

		flMemorySize int

		flCmdline string
	)

	createFlag.StringVar(&flInstanceName, "name", "", "instance name")
	createFlag.StringVar(&flKernelName, "kernel", "", "kernel name")

	createFlag.IntVar(&flMemorySize, "m", 512, "memory size")

	createFlag.StringVar(&flCmdline, "cmdline", "", "cmdline")

	createFlag.Parse(args)

	if flInstanceName == "" {
		fmt.Fprintf(os.Stderr, "Please provide new instance name.\n\n")
		createFlag.PrintDefaults()
		os.Exit(1)
	}

	if flKernelName == "" {
		fmt.Fprintf(os.Stderr, "Please provide kernel name used by new instance.\n\n")
		createFlag.PrintDefaults()
		os.Exit(1)
	}

	instancesCatalog, err := cmdEnv.BaseCatalog.Dir("instances")
	if err != nil {
		logger.Fatalf("create instances catalog failed: %s", err)
	}

	if _, err := instancesCatalog.TryDir(flInstanceName); err == nil {
		logger.Fatalf("target instance name %s exists", flInstanceName)
	}

	myInstanceCatalog, err := instancesCatalog.Dir(flInstanceName)
	if err != nil {
		logger.Fatalf("create target instance catalog failed: %s", err)
	}

	kernelsCatalog, err := cmdEnv.BaseCatalog.Dir("kernels")
	if err != nil {
		myInstanceCatalog.Cleanup(true)
		logger.Fatalf("read kernels catalog failed: %s", err)
	}

	myKernelCatalog, err := kernelsCatalog.TryDir(flKernelName)
	if err != nil {
		myInstanceCatalog.Cleanup(true)
		logger.Fatalf("read kernel %s catalog failed: %s", flKernelName, err)
	}

	i := instance.New(flInstanceName)
	i.Kernel = flKernelName
	i.Cmdline = flCmdline

	if flMemorySize < 512 {
		// FIXME: support huge initrd
		cmdEnv.Logger.Infoln("workaround: force memory size to 512M")
		i.MemorySize = 512
	} else {
		i.MemorySize = flMemorySize
	}

	i.InstanceCatalog = myInstanceCatalog
	i.KernelCatalog = myKernelCatalog

	// Find capsuled
	// it should be either placed $CAPSULE_ROOT/capsuled/capsuled or
	// /usr/lib/capsule/libexec/capusled
	// Pass its parent dir to qemu
	capsuledDir := filepath.Join(cmdEnv.BaseCatalog.Path, "capsuled")
	if fi, err := os.Stat(filepath.Join(capsuledDir, "capsuled")); err != nil || !fi.Mode().IsRegular() {
		// Can not find capsuled at $CAPSULE_ROOT/capsuled/capsuled
		if fi, err := os.Stat(GlobalCapsuledPath); err != nil || !fi.Mode().IsRegular() {
			myInstanceCatalog.Cleanup(true)
			cmdEnv.Logger.Fatalln("can not find capsuled")
		} else {
			capsuledDir = GlobalCapsuledDir
		}
	}
	i.SysinitDir = capsuledDir

	err = i.Create()
	if err != nil {
		myInstanceCatalog.Cleanup(true)
		cmdEnv.Logger.Fatalf("create instance failed: %s", err)
	}

	retryTimes := 5
	retryTicker := time.NewTicker(2 * time.Second)
	retryPass := false

	var rpcClient *rpc.Client

	for _ = range retryTicker.C {
		if retryTimes == 0 {
			break
		}

		controlSock, err := myInstanceCatalog.TryFile("control.sock", false)
		if err != nil {
			retryTimes -= 1
			cmdEnv.Logger.Debugf("try to open control socket failed: %s", err)
			continue
		}

		rpcClient, err = rpc.Dial("unix", controlSock)
		if err != nil {
			retryTimes -= 1
			cmdEnv.Logger.Debugf("try to dial control socket failed: %s", err)
			continue
		}
		cmdEnv.Logger.Debugf("dial control socket success")
		retryPass = true
		break
	}

	retryTicker.Stop()
	if !retryPass {
		cmdEnv.Logger.Debugln("leave instance catalog for debugging.")
		if cmdEnv.Logger.Level != logrus.DebugLevel {
			myInstanceCatalog.Cleanup(true)
		}
		cmdEnv.Logger.Fatalf("instance starts but can not be connected.")
	}

	var d time.Duration
	err = rpcClient.Call("Server.Alive", struct{}{}, &d)
	if err != nil {
		cmdEnv.Logger.Fatalf("rpc call failed: %s", err)
	}

	cmdEnv.Logger.Infoln("Yoo, we are alive.")

	myInstanceCatalog.Cleanup(false)

	return nil
}

func createUsage() {

}
<|endoftext|>


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

// Package plugins allows users to operate on statistics recorded for each circuit operation.
// Plugins should be careful to be lightweight as they will be called frequently.
package plugins

import (
	"strings"
	"time"

	metricCollector "github.com/afex/hystrix-go/hystrix/metric_collector"
	"github.com/uber-go/tally"
)

// M3Collector fulfills the metricCollector interface allowing users to ship circuit
// stats to a m3 backend. To use users must call InitializeM3Collector before
// circuits are started. Then register NewM3Collector with metricCollector.Registry.Register(NewM3Collector).
type M3Collector struct {
	scope                   tally.Scope
	attemptsPrefix          string
	errorsPrefix            string
	successesPrefix         string
	failuresPrefix          string
	rejectsPrefix           string
	shortCircuitsPrefix     string
	timeoutsPrefix          string
	fallbackSuccessesPrefix string
	fallbackFailuresPrefix  string
	totalDurationPrefix     string
	totalDurationHistPrefix string
	runDurationPrefix       string
	runDurationHistPrefix   string
}

// M3CollectorClient provides configuration that the m3 client will need.
type M3CollectorClient struct {
	scope tally.Scope
}

// InitializeM3Collector creates the connection to the m3
func InitializeM3Collector(scope tally.Scope) *M3CollectorClient {
	return &M3CollectorClient{
		scope: scope,
	}

}

// NewM3Collector creates a collector for a specific circuit. The
// prefix given to this circuit will be circuitbreaker.{metric}...
// Circuits with "/" in their names will have them replaced with ".".
func (m *M3CollectorClient) NewM3Collector(name string) metricCollector.MetricCollector {
	name = strings.Replace(name, "/", "-", -1)
	name = strings.Replace(name, ":", "-", -1)
	name = strings.Replace(name, ".", "-", -1)
	tagMap := map[string]string{"emitter-name": name}
	return &M3Collector{
		scope:                   m.scope.Tagged(tagMap),
		attemptsPrefix:          "circuitbreaker.attempts",
		errorsPrefix:            "circuitbreaker.errors",
		successesPrefix:         "circuitbreaker.successes",
		failuresPrefix:          "circuitbreaker.failures",
		rejectsPrefix:           "circuitbreaker.rejects",
		shortCircuitsPrefix:     "circuitbreaker.shortCircuits",
		timeoutsPrefix:          "circuitbreaker.timeouts",
		fallbackSuccessesPrefix: "circuitbreaker.fallbackSuccesses",
		fallbackFailuresPrefix:  "circuitbreaker.fallbackFailures",
		totalDurationPrefix:     "circuitbreaker.totalDuration",
		totalDurationHistPrefix: "circuitbreaker.totalDurationHist",
		runDurationPrefix:       "circuitbreaker.runDuration",
		runDurationHistPrefix:   "circuitbreaker.runDurationHist",
	}
}

func (g *M3Collector) incrementCounterMetric(prefix string, i float64) {
	if i == 0 {
		return
	}
	g.scope.Counter(prefix).Inc(int64(i))
}

func (g *M3Collector) updateTimerMetric(prefix string, dur time.Duration) {
	g.scope.Timer(prefix).Record(dur)
}

func (g *M3Collector) updateHistogramMetric(prefix string, dur time.Duration) {
	g.scope.Histogram(prefix, tally.DefaultBuckets).RecordDuration(dur)
}

// Update is a callback by hystrix lib to relay the metrics to m3
func (g *M3Collector) Update(r metricCollector.MetricResult) {
	g.incrementCounterMetric(g.attemptsPrefix, r.Attempts)
	g.incrementCounterMetric(g.errorsPrefix, r.Errors)
	g.incrementCounterMetric(g.successesPrefix, r.Successes)
	g.incrementCounterMetric(g.failuresPrefix, r.Failures)
	g.incrementCounterMetric(g.rejectsPrefix, r.Rejects)
	g.incrementCounterMetric(g.shortCircuitsPrefix, r.ShortCircuits)
	g.incrementCounterMetric(g.timeoutsPrefix, r.Timeouts)
	g.incrementCounterMetric(g.fallbackSuccessesPrefix, r.FallbackSuccesses)
	g.incrementCounterMetric(g.fallbackFailuresPrefix, r.FallbackFailures)
	g.updateTimerMetric(g.totalDurationPrefix, r.TotalDuration)
	g.updateHistogramMetric(g.totalDurationHistPrefix, r.TotalDuration)
	g.updateTimerMetric(g.runDurationPrefix, r.RunDuration)
	g.updateHistogramMetric(g.runDurationHistPrefix, r.RunDuration)
}

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

// Package plugins allows users to operate on statistics recorded for each circuit operation.
// Plugins should be careful to be lightweight as they will be called frequently.
package plugins

import (
	"strings"
	"time"

	metricCollector "github.com/afex/hystrix-go/hystrix/metric_collector"
	"github.com/uber-go/tally"
)

// M3Collector fulfills the metricCollector interface allowing users to ship circuit
// stats to a m3 backend. To use users must call InitializeM3Collector before
// circuits are started. Then register NewM3Collector with metricCollector.Registry.Register(NewM3Collector).
type M3Collector struct {
	scope                   tally.Scope
	attemptsPrefix          string
	errorsPrefix            string
	successesPrefix         string
	failuresPrefix          string
	rejectsPrefix           string
	shortCircuitsPrefix     string
	timeoutsPrefix          string
	fallbackSuccessesPrefix string
	fallbackFailuresPrefix  string
	totalDurationPrefix     string
	totalDurationHistPrefix string
	runDurationPrefix       string
	runDurationHistPrefix   string
	contextCanceled         string
	contextDeadlineExceeded string
}

// M3CollectorClient provides configuration that the m3 client will need.
type M3CollectorClient struct {
	scope tally.Scope
}

// InitializeM3Collector creates the connection to the m3
func InitializeM3Collector(scope tally.Scope) *M3CollectorClient {
	return &M3CollectorClient{
		scope: scope,
	}

}

// NewM3Collector creates a collector for a specific circuit. The
// prefix given to this circuit will be circuitbreaker.{metric}...
// Circuits with "/" in their names will have them replaced with ".".
func (m *M3CollectorClient) NewM3Collector(name string) metricCollector.MetricCollector {
	name = strings.Replace(name, "/", "-", -1)
	name = strings.Replace(name, ":", "-", -1)
	name = strings.Replace(name, ".", "-", -1)
	tagMap := map[string]string{"emitter-name": name}
	return &M3Collector{
		scope:                   m.scope.Tagged(tagMap),
		attemptsPrefix:          "circuitbreaker.attempts",
		errorsPrefix:            "circuitbreaker.errors",
		successesPrefix:         "circuitbreaker.successes",
		failuresPrefix:          "circuitbreaker.failures",
		rejectsPrefix:           "circuitbreaker.rejects",
		shortCircuitsPrefix:     "circuitbreaker.shortCircuits",
		timeoutsPrefix:          "circuitbreaker.timeouts",
		fallbackSuccessesPrefix: "circuitbreaker.fallbackSuccesses",
		fallbackFailuresPrefix:  "circuitbreaker.fallbackFailures",
		totalDurationPrefix:     "circuitbreaker.totalDuration",
		totalDurationHistPrefix: "circuitbreaker.totalDurationHist",
		runDurationPrefix:       "circuitbreaker.runDuration",
		runDurationHistPrefix:   "circuitbreaker.runDurationHist",
		contextCanceled:         "circuitbreaker.context",
		contextDeadlineExceeded: "circuitbreaker.contextDeadlineExceeded",
	}
}

func (g *M3Collector) incrementCounterMetric(prefix string, i float64) {
	if i == 0 {
		return
	}
	g.scope.Counter(prefix).Inc(int64(i))
}

func (g *M3Collector) updateTimerMetric(prefix string, dur time.Duration) {
	g.scope.Timer(prefix).Record(dur)
}

func (g *M3Collector) updateHistogramMetric(prefix string, dur time.Duration) {
	g.scope.Histogram(prefix, tally.DefaultBuckets).RecordDuration(dur)
}

// Update is a callback by hystrix lib to relay the metrics to m3
func (g *M3Collector) Update(r metricCollector.MetricResult) {
	g.incrementCounterMetric(g.attemptsPrefix, r.Attempts)
	g.incrementCounterMetric(g.errorsPrefix, r.Errors)
	g.incrementCounterMetric(g.successesPrefix, r.Successes)
	g.incrementCounterMetric(g.failuresPrefix, r.Failures)
	g.incrementCounterMetric(g.rejectsPrefix, r.Rejects)
	g.incrementCounterMetric(g.shortCircuitsPrefix, r.ShortCircuits)
	g.incrementCounterMetric(g.timeoutsPrefix, r.Timeouts)
	g.incrementCounterMetric(g.fallbackSuccessesPrefix, r.FallbackSuccesses)
	g.incrementCounterMetric(g.fallbackFailuresPrefix, r.FallbackFailures)
	g.updateTimerMetric(g.totalDurationPrefix, r.TotalDuration)
	g.updateHistogramMetric(g.totalDurationHistPrefix, r.TotalDuration)
	g.updateTimerMetric(g.runDurationPrefix, r.RunDuration)
	g.updateHistogramMetric(g.runDurationHistPrefix, r.RunDuration)
	g.incrementCounterMetric(g.contextCanceled, r.ContextCanceled)
	g.incrementCounterMetric(g.contextDeadlineExceeded, r.ContextDeadlineExceeded)
}

// Reset is a noop operation in this collector.
func (g *M3Collector) Reset() {}
<|endoftext|>


<commit_before>package feeds

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"time"

	"github.com/caarlos0/env"
	"github.com/joho/godotenv"
	"github.com/sethgrid/pester"
)

// Example only configurable with env variables
//
// u := feeds.NewUser()
// go u.Start()
//
// The feed endpoint accept a parameter called "last" which is used as cursor for the current feed position
// This cursor will be saved when the update process is done
// GET http://example.de/feed?last=1503769504008
// { "items": [{ "name": "peter" }] }
//

var configuration *config

var (
	Feed            = "user"
	ErrUnMarshaling = errors.New("user feed: json parsing error")
	ErrClient       = errors.New("user feed: client connection error")
	ErrReadBody     = errors.New("user feed: response payload error")
)

type (
	config struct {
		URL              string `env:"FEED_USER_URL"`
		Table            string `env:"FEED_USER_TABLE" envDefault:"users"`
		Interval         int64  `env:"FEED_USER_INTERVAL"`
		ConnectionString int    `env:"FEED_USER_CONN_STRING"`
		Dialect          string `env:"FEED_USER_DIALECT" envDefault:"postgres"`
	}
	userFeed struct {
		Last   uint64
		ticker *time.Ticker
	}
	feedItem struct {
		Name string `json:"name"`
	}
	feed struct {
		Items []feedItem `json:"items"`
	}
)

// init loads the config from ENV
func init() {
	pwd, err := os.Getwd()
	if err != nil {
		log.Println(err)
	}

	err = godotenv.Load(path.Join(pwd, "feeds", ".env"))

	if err != nil {
		log.Print("No .env file could be found\n")
	}

	cfg := &config{}
	err = env.Parse(cfg)
	if err != nil {
		log.Fatalf("%+v\n", err)
	}

	configuration = cfg
}

// Start the timer
func NewUser() *userFeed {
	u := &userFeed{}
	u.ticker = time.NewTicker(time.Duration(configuration.Interval) * time.Second)
	return u
}

// Poll starts the mechanism to initiate updates in certain intervals
func (u *userFeed) Start() {
	for _ = range u.ticker.C {
		u.poll(u.Last)
	}
}

func (u *userFeed) poll(last uint64) {
	feed, err := u.request()

	if err != nil {
		switch err.(type) {
		default:
			fmt.Println(err)
		}
	} else if err := u.update(feed); err == nil {
		u.saveLast(last)
	}

	fmt.Println(feed)
}

// update the database with the feed payload
func (u *userFeed) update(f *feed) error {
	return nil
}

// saveLast store the cursor of the current feed position
func (u *userFeed) saveLast(c uint64) {
	u.Last = c
}

// Request the feed endpoint and return the feed results
func (u *userFeed) request() (*feed, error) {
	client := pester.New()
	client.Concurrency = 3
	client.MaxRetries = 5
	client.Backoff = pester.ExponentialBackoff
	client.KeepLog = true

	resp, err := client.Get(configuration.URL)
	defer resp.Body.Close()

	if err != nil {
		return nil, ErrClient
	}

	payload, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return nil, ErrReadBody
	}

	feed := &feed{}
	if err := json.Unmarshal(payload, feed); err != nil {
		return nil, ErrUnMarshaling
	}

	return feed, nil
}
<commit_msg>check err<commit_after>package feeds

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"time"

	"github.com/caarlos0/env"
	"github.com/joho/godotenv"
	"github.com/sethgrid/pester"
)

// Example only configurable with env variables
//
// u := feeds.NewUser()
// go u.Start()
//
// The feed endpoint accept a parameter called "last" which is used as cursor for the current feed position
// This cursor will be saved when the update process is done
// GET http://example.de/feed?last=1503769504008
// { "items": [{ "name": "peter" }] }
//

var configuration *config

var (
	Feed            = "user"
	ErrUnMarshaling = errors.New("user feed: json parsing error")
	ErrClient       = errors.New("user feed: client connection error")
	ErrReadBody     = errors.New("user feed: response payload error")
)

type (
	config struct {
		URL              string `env:"FEED_USER_URL"`
		Table            string `env:"FEED_USER_TABLE" envDefault:"users"`
		Interval         int64  `env:"FEED_USER_INTERVAL"`
		ConnectionString int    `env:"FEED_USER_CONN_STRING"`
		Dialect          string `env:"FEED_USER_DIALECT" envDefault:"postgres"`
	}
	userFeed struct {
		Last   uint64
		ticker *time.Ticker
	}
	feedItem struct {
		Name string `json:"name"`
	}
	feed struct {
		Items []feedItem `json:"items"`
	}
)

// init loads the config from ENV
func init() {
	pwd, err := os.Getwd()
	if err != nil {
		log.Println(err)
	}

	err = godotenv.Load(path.Join(pwd, "feeds", ".env"))

	if err != nil {
		log.Print("No .env file could be found\n")
	}

	cfg := &config{}
	err = env.Parse(cfg)
	if err != nil {
		log.Fatalf("%+v\n", err)
	}

	configuration = cfg
}

// Start the timer
func NewUser() *userFeed {
	u := &userFeed{}
	u.ticker = time.NewTicker(time.Duration(configuration.Interval) * time.Second)
	return u
}

// Poll starts the mechanism to initiate updates in certain intervals
func (u *userFeed) Start() {
	for _ = range u.ticker.C {
		u.poll(u.Last)
	}
}

func (u *userFeed) poll(last uint64) {
	feed, err := u.request()

	if err != nil {
		switch err.(type) {
		default:
			fmt.Println(err)
		}
	} else if err := u.update(feed); err == nil {
		u.saveLast(last)
	}

	fmt.Println(feed)
}

// update the database with the feed payload
func (u *userFeed) update(f *feed) error {
	return nil
}

// saveLast store the cursor of the current feed position
func (u *userFeed) saveLast(c uint64) {
	u.Last = c
}

// Request the feed endpoint and return the feed results
func (u *userFeed) request() (*feed, error) {
	client := pester.New()
	client.Concurrency = 3
	client.MaxRetries = 5
	client.Backoff = pester.ExponentialBackoff
	client.KeepLog = true

	resp, err := client.Get(configuration.URL)
	defer func() {
		err := resp.Body.Close()
		if err != nil {
			log.Printf("error closing response body %q\n", err)
		}
	}()

	if err != nil {
		return nil, ErrClient
	}

	payload, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return nil, ErrReadBody
	}

	feed := &feed{}
	if err := json.Unmarshal(payload, feed); err != nil {
		return nil, ErrUnMarshaling
	}

	return feed, nil
}
<|endoftext|>


<commit_before>// Copyright 2017 Michael Meyling. All rights reserved.

package field

import (
	"fmt"
)

type Field struct {
  	Rows, Columns int
  	Matrix        [][]byte
}

const EMPTY = 32

func New(rows int, columns int) *Field {
	var f Field
	matrix := make([][]byte, rows, columns)
	for i := 0; i < rows; i++ {
		m := make([]byte, columns)
		for j := 0; j < columns; j++ {
			m[j] = EMPTY
		}
		matrix[i] = m
	}
	f.Rows = rows
	f.Columns = columns
	f.Matrix = matrix
	Frame(&f)
	return &f
}

func VLine(f *Field, x, y1, y2 int, v byte) {
	if y1 > y2 {
		return
	}
	for y := y1; y <= y2; y++ {
		if InField(f, x, y) {
			Set(f, x, y, v)
		}
	}
}

func HLine(f *Field, y, x1, x2 int, v byte) {
	if x1 > x2 {
		return
	}
	for x := x1; x <= x2; x++ {
		if InField(f, x, y) {
			Set(f, x, y, v)
		}
	}
}

func Frame(f *Field) {
	Square(f, 0, 0, f.Columns - 1, f.Rows - 1)
}

func Square(f *Field, x1, y1, x2, y2 int) {
	HLine(f, y1, x1 + 1, x2 - 1, byte("-"[0]))
	HLine(f, y2, x1 + 1, x2 - 1, byte("-"[0]))
	VLine(f, x1, y1 + 1, y2 - 1, byte("|"[0]))
	VLine(f, x2, y1 + 1, y2 - 1, byte("|"[0]))
	Set(f, x1, y1,  byte("+"[0]))
	Set(f, x1, y2,  byte("+"[0]))
	Set(f, x2, y1,  byte("+"[0]))
	Set(f, x2, y2,  byte("+"[0]))
}

func Get(f *Field, x, y int) byte {
	if NotInField(f, x, y) {
		panic(fmt.Sprintf("you tried to get at (%d, %d)", x, y))
	}
	return f.Matrix[f.Rows- 1 - y ][x]
}

func Set(f *Field, x, y int, v byte) {
	if NotInField(f, x, y) {
		panic(fmt.Sprintf("you tried to write at (%d, %d)", x, y))
	}
	f.Matrix[f.Rows- 1 - y][x] = v
}

func NotInField(f *Field, x, y int) bool {
	return x >= f.Columns || y >= f.Rows || x < 0 || y < 0
}

func InField(f *Field, x, y int) bool {
	return !NotInField(f, x, y)
}

func Empty(f *Field, x, y int) bool {
	if NotInField(f, x, y) {
		return false
	}
	return Get(f, x, y) == EMPTY
}

// draw field
func Draw(f *Field) {
	for i := 0; i < len(f.Matrix); i++ {
       	for j :=0 ; j < len(f.Matrix[i]); j++ {
		   fmt.Print(string(f.Matrix[i][j]));
	   	}
		fmt.Println()
	}
}
<commit_msg>simplify byte handling<commit_after>// Copyright 2017 Michael Meyling. All rights reserved.

package field

import (
	"fmt"
)

type Field struct {
  	Rows, Columns int
  	Matrix        [][]byte
}

const EMPTY = 32

func New(rows int, columns int) *Field {
	var f Field
	matrix := make([][]byte, rows, columns)
	for i := 0; i < rows; i++ {
		m := make([]byte, columns)
		for j := 0; j < columns; j++ {
			m[j] = EMPTY
		}
		matrix[i] = m
	}
	f.Rows = rows
	f.Columns = columns
	f.Matrix = matrix
	Frame(&f)
	return &f
}

func VLine(f *Field, x, y1, y2 int, v byte) {
	if y1 > y2 {
		return
	}
	for y := y1; y <= y2; y++ {
		if InField(f, x, y) {
			Set(f, x, y, v)
		}
	}
}

func HLine(f *Field, y, x1, x2 int, v byte) {
	if x1 > x2 {
		return
	}
	for x := x1; x <= x2; x++ {
		if InField(f, x, y) {
			Set(f, x, y, v)
		}
	}
}

func Frame(f *Field) {
	Square(f, 0, 0, f.Columns - 1, f.Rows - 1)
}

func Square(f *Field, x1, y1, x2, y2 int) {
	HLine(f, y1, x1 + 1, x2 - 1, '-')
	HLine(f, y2, x1 + 1, x2 - 1, '-')
	VLine(f, x1, y1 + 1, y2 - 1, '|')
	VLine(f, x2, y1 + 1, y2 - 1, '|')
	Set(f, x1, y1,  '+')
	Set(f, x1, y2,  '+')
	Set(f, x2, y1,  '+')
	Set(f, x2, y2,  '+')
}

func Get(f *Field, x, y int) byte {
	if NotInField(f, x, y) {
		panic(fmt.Sprintf("you tried to get at (%d, %d)", x, y))
	}
	return f.Matrix[f.Rows- 1 - y ][x]
}

func Set(f *Field, x, y int, v byte) {
	if NotInField(f, x, y) {
		panic(fmt.Sprintf("you tried to write at (%d, %d)", x, y))
	}
	f.Matrix[f.Rows- 1 - y][x] = v
}

func NotInField(f *Field, x, y int) bool {
	return x >= f.Columns || y >= f.Rows || x < 0 || y < 0
}

func InField(f *Field, x, y int) bool {
	return !NotInField(f, x, y)
}

func Empty(f *Field, x, y int) bool {
	if NotInField(f, x, y) {
		return false
	}
	return Get(f, x, y) == EMPTY
}

// draw field
func Draw(f *Field) {
	for i := 0; i < len(f.Matrix); i++ {
       	for j :=0 ; j < len(f.Matrix[i]); j++ {
		   fmt.Print(string(f.Matrix[i][j]));
	   	}
		fmt.Println()
	}
}
<|endoftext|>


<commit_before>package model

import "github.com/af83/edwig/logger"

type UpdateManager struct {
	ClockConsumer
	UUIDConsumer

	transactionProvider TransactionProvider
}

func NewUpdateManager(transactionProvider TransactionProvider) func(UpdateEvent) {
	manager := &UpdateManager{transactionProvider: transactionProvider}
	return manager.Update
}

func (manager *UpdateManager) Update(event UpdateEvent) {
	switch event.EventKind() {
	case STOP_AREA_EVENT:
		manager.updateStopArea(event.(*StopAreaUpdateEvent))
	case LINE_EVENT:
		manager.updateLine(event.(*LineUpdateEvent))
	case VEHICLE_JOURNEY_EVENT:
		manager.updateVehicleJourney(event.(*VehicleJourneyUpdateEvent))
	case STOP_VISIT_EVENT:
		manager.updateStopVisit(event.(*StopVisitUpdateEvent))
	}
}

func (manager *UpdateManager) updateStopArea(event *StopAreaUpdateEvent) {
	tx := manager.transactionProvider.NewTransaction()

	stopArea, found := tx.Model().StopAreas().FindByObjectId(event.ObjectId)
	if !found {
		stopArea = tx.Model().StopAreas().New()

		stopArea.SetObjectID(event.ObjectId)
		stopArea.CollectGeneralMessages = true

		stopArea.Name = event.Name
		stopArea.CollectedAlways = event.CollectedAlways
		stopArea.Longitude = event.Longitude
		stopArea.Latitude = event.Latitude
	}

	if stopArea.ParentId == "" && event.ParentObjectId.Value() != "" {
		parentSA, _ := tx.Model().StopAreas().FindByObjectId(event.ParentObjectId)
		stopArea.ParentId = parentSA.Id()
	}

	stopArea.Updated(manager.Clock().Now())

	tx.Model().StopAreas().Save(&stopArea)
	tx.Commit()
	tx.Close()
}

func (manager *UpdateManager) updateMonitoredStopArea(stopAreaId StopAreaId, partner string, status bool) {
	tx := manager.transactionProvider.NewTransaction()

	ascendants := tx.Model().StopAreas().FindAscendants(stopAreaId)
	for i := range ascendants {
		stopArea := ascendants[i]
		stopArea.Origins.SetPartnerStatus(partner, status)
		stopArea.Monitored = stopArea.Origins.Monitored()
		tx.Model().StopAreas().Save(&stopArea)
	}

	tx.Commit()
	tx.Close()
}

func (manager *UpdateManager) updateLine(event *LineUpdateEvent) {
	tx := manager.transactionProvider.NewTransaction()

	line, found := tx.Model().Lines().FindByObjectId(event.ObjectId)
	if !found {
		line = tx.Model().Lines().New()

		line.SetObjectID(event.ObjectId)
		line.SetObjectID(NewObjectID("_default", event.ObjectId.HashValue()))

		line.CollectGeneralMessages = true

		line.Name = event.Name

		line.SetOrigin(event.Origin)
	}

	line.Updated(manager.Clock().Now())

	tx.Model().Lines().Save(&line)
	tx.Commit()
	tx.Close()
}

func (manager *UpdateManager) updateVehicleJourney(event *VehicleJourneyUpdateEvent) {
	tx := manager.transactionProvider.NewTransaction()

	vj, found := tx.Model().VehicleJourneys().FindByObjectId(event.ObjectId)
	if !found {
		vj = tx.Model().VehicleJourneys().New()

		vj.SetObjectID(event.ObjectId)
		vj.SetObjectID(NewObjectID("_default", event.ObjectId.HashValue()))

		// LineObjectId
		l, ok := tx.Model().Lines().FindByObjectId(event.LineObjectId)
		if !ok {
			logger.Log.Debugf("VehicleJourney update event without corresponding line: %v", event.LineObjectId.String())
			return
		}
		vj.LineId = l.Id()

		vj.Origin = event.Origin
	}

	vj.References.SetObjectId("OriginRef", NewObjectID(event.ObjectId.Kind(), event.OriginRef))
	vj.OriginName = event.OriginName

	vj.References.SetObjectId("DestinationRef", NewObjectID(event.ObjectId.Kind(), event.DestinationRef))
	vj.DestinationName = event.DestinationName

	vj.Attributes.Set("DirectionName", event.Direction)

	tx.Model().VehicleJourneys().Save(&vj)
	tx.Commit()
	tx.Close()
}

func (manager *UpdateManager) updateStopVisit(event *StopVisitUpdateEvent) {
	tx := manager.transactionProvider.NewTransaction()

	sa, ok := tx.Model().StopAreas().FindByObjectId(event.StopAreaObjectId)
	if !ok {
		logger.Log.Debugf("StopVisit update event without corresponding stop area: %v", event.StopAreaObjectId.String())
		return
	}

	vj, ok := tx.Model().VehicleJourneys().FindByObjectId(event.VehicleJourneyObjectId)
	if !ok {
		logger.Log.Debugf("StopVisit update event without corresponding vehicle journey: %v", event.VehicleJourneyObjectId.String())
		return
	}

	sv, found := tx.Model().StopVisits().FindByObjectId(event.ObjectId)
	if !found {
		sv = tx.Model().StopVisits().New()

		sv.SetObjectID(event.ObjectId)
		sv.SetObjectID(NewObjectID("_default", event.ObjectId.HashValue()))

		// StopAreaObjectId
		sv.StopAreaId = sa.Id()

		// VehicleJourneyObjectId
		sv.VehicleJourneyId = vj.Id()

		sv.Origin = event.Origin
	}

	sv.Schedules.Merge(&event.Schedules)
	sv.Collected(manager.Clock().Now())

	if event.Monitored != vj.Monitored {
		vj.Monitored = event.Monitored
		tx.Model().VehicleJourneys().Save(&vj)
	}

	if event.Origin != "" {
		status, ok := sa.Origins.Origin(event.Origin)
		if status != event.Monitored || !ok {
			manager.updateMonitoredStopArea(sa.Id(), event.Origin, event.Monitored)
		}
	}

	tx.Model().StopVisits().Save(&sv)
	tx.Commit()
	tx.Close()
}
<commit_msg>Fix RecordedAt in UpdateManager#updateStopVisit<commit_after>package model

import "github.com/af83/edwig/logger"

type UpdateManager struct {
	ClockConsumer
	UUIDConsumer

	transactionProvider TransactionProvider
}

func NewUpdateManager(transactionProvider TransactionProvider) func(UpdateEvent) {
	manager := &UpdateManager{transactionProvider: transactionProvider}
	return manager.Update
}

func (manager *UpdateManager) Update(event UpdateEvent) {
	switch event.EventKind() {
	case STOP_AREA_EVENT:
		manager.updateStopArea(event.(*StopAreaUpdateEvent))
	case LINE_EVENT:
		manager.updateLine(event.(*LineUpdateEvent))
	case VEHICLE_JOURNEY_EVENT:
		manager.updateVehicleJourney(event.(*VehicleJourneyUpdateEvent))
	case STOP_VISIT_EVENT:
		manager.updateStopVisit(event.(*StopVisitUpdateEvent))
	}
}

func (manager *UpdateManager) updateStopArea(event *StopAreaUpdateEvent) {
	tx := manager.transactionProvider.NewTransaction()

	stopArea, found := tx.Model().StopAreas().FindByObjectId(event.ObjectId)
	if !found {
		stopArea = tx.Model().StopAreas().New()

		stopArea.SetObjectID(event.ObjectId)
		stopArea.CollectGeneralMessages = true

		stopArea.Name = event.Name
		stopArea.CollectedAlways = event.CollectedAlways
		stopArea.Longitude = event.Longitude
		stopArea.Latitude = event.Latitude
	}

	if stopArea.ParentId == "" && event.ParentObjectId.Value() != "" {
		parentSA, _ := tx.Model().StopAreas().FindByObjectId(event.ParentObjectId)
		stopArea.ParentId = parentSA.Id()
	}

	stopArea.Updated(manager.Clock().Now())

	tx.Model().StopAreas().Save(&stopArea)
	tx.Commit()
	tx.Close()
}

func (manager *UpdateManager) updateMonitoredStopArea(stopAreaId StopAreaId, partner string, status bool) {
	tx := manager.transactionProvider.NewTransaction()

	ascendants := tx.Model().StopAreas().FindAscendants(stopAreaId)
	for i := range ascendants {
		stopArea := ascendants[i]
		stopArea.Origins.SetPartnerStatus(partner, status)
		stopArea.Monitored = stopArea.Origins.Monitored()
		tx.Model().StopAreas().Save(&stopArea)
	}

	tx.Commit()
	tx.Close()
}

func (manager *UpdateManager) updateLine(event *LineUpdateEvent) {
	tx := manager.transactionProvider.NewTransaction()

	line, found := tx.Model().Lines().FindByObjectId(event.ObjectId)
	if !found {
		line = tx.Model().Lines().New()

		line.SetObjectID(event.ObjectId)
		line.SetObjectID(NewObjectID("_default", event.ObjectId.HashValue()))

		line.CollectGeneralMessages = true

		line.Name = event.Name

		line.SetOrigin(event.Origin)
	}

	line.Updated(manager.Clock().Now())

	tx.Model().Lines().Save(&line)
	tx.Commit()
	tx.Close()
}

func (manager *UpdateManager) updateVehicleJourney(event *VehicleJourneyUpdateEvent) {
	tx := manager.transactionProvider.NewTransaction()

	vj, found := tx.Model().VehicleJourneys().FindByObjectId(event.ObjectId)
	if !found {
		vj = tx.Model().VehicleJourneys().New()

		vj.SetObjectID(event.ObjectId)
		vj.SetObjectID(NewObjectID("_default", event.ObjectId.HashValue()))

		// LineObjectId
		l, ok := tx.Model().Lines().FindByObjectId(event.LineObjectId)
		if !ok {
			logger.Log.Debugf("VehicleJourney update event without corresponding line: %v", event.LineObjectId.String())
			return
		}
		vj.LineId = l.Id()

		vj.Origin = event.Origin
	}

	vj.References.SetObjectId("OriginRef", NewObjectID(event.ObjectId.Kind(), event.OriginRef))
	vj.OriginName = event.OriginName

	vj.References.SetObjectId("DestinationRef", NewObjectID(event.ObjectId.Kind(), event.DestinationRef))
	vj.DestinationName = event.DestinationName

	vj.Attributes.Set("DirectionName", event.Direction)

	tx.Model().VehicleJourneys().Save(&vj)
	tx.Commit()
	tx.Close()
}

func (manager *UpdateManager) updateStopVisit(event *StopVisitUpdateEvent) {
	tx := manager.transactionProvider.NewTransaction()

	sa, ok := tx.Model().StopAreas().FindByObjectId(event.StopAreaObjectId)
	if !ok {
		logger.Log.Debugf("StopVisit update event without corresponding stop area: %v", event.StopAreaObjectId.String())
		return
	}

	vj, ok := tx.Model().VehicleJourneys().FindByObjectId(event.VehicleJourneyObjectId)
	if !ok {
		logger.Log.Debugf("StopVisit update event without corresponding vehicle journey: %v", event.VehicleJourneyObjectId.String())
		return
	}

	sv, found := tx.Model().StopVisits().FindByObjectId(event.ObjectId)
	if !found {
		sv = tx.Model().StopVisits().New()

		sv.SetObjectID(event.ObjectId)
		sv.SetObjectID(NewObjectID("_default", event.ObjectId.HashValue()))

		// StopAreaObjectId
		sv.StopAreaId = sa.Id()

		// VehicleJourneyObjectId
		sv.VehicleJourneyId = vj.Id()

		sv.Origin = event.Origin
	}

	sv.Schedules.Merge(&event.Schedules)
	sv.RecordedAt = manager.Clock().Now()
	sv.Collected(manager.Clock().Now())

	if event.Monitored != vj.Monitored {
		vj.Monitored = event.Monitored
		tx.Model().VehicleJourneys().Save(&vj)
	}

	if event.Origin != "" {
		status, ok := sa.Origins.Origin(event.Origin)
		if status != event.Monitored || !ok {
			manager.updateMonitoredStopArea(sa.Id(), event.Origin, event.Monitored)
		}
	}

	tx.Model().StopVisits().Save(&sv)
	tx.Commit()
	tx.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"os"
)

type FileData struct {
	Data
	*HighWaterMark
}

type FileReader struct {
	File *os.File

	// Fields are user-configurable keys/values that are merged into the Data
	// that is sent to the remote system.
	Fields map[string]string

	position int64
	buf      *bufio.Reader

	partialBuf bytes.Buffer
}

func (h *FileReader) ReadLine() (*FileData, error) {
	h.initializePosition()

	if h.buf == nil {
		h.buf = bufio.NewReader(h.File)
	}

	line, err := h.buf.ReadBytes('\n')
	// It's possible to get both a partial line and an error (e.g., EOF). Always
	// write the partial line to the buffer and update the position, then check
	// for error.
	if line != nil {
		h.position += int64(len(line))
	}

	if err != nil {
		if line != nil {
			h.partialBuf.Write(line)
		}

		return nil, err
	} else {
		// If there is a partial buffer, use it
		if h.partialBuf.Len() > 0 {
			h.partialBuf.Write(line)
			line, _ = h.partialBuf.ReadBytes('\n')
		}

		fileData := &FileData{
			Data: h.buildDataWithLine(bytes.TrimRight(line, "\r\n")),
			HighWaterMark: &HighWaterMark{
				FilePath: h.File.Name(),
				Position: h.position,
			},
		}

		return fileData, nil
	}
}

func (h *FileReader) Position() int64 {
	h.initializePosition()

	return h.position
}

func (h *FileReader) initializePosition() error {
	if h.position == 0 {
		h.position, _ = h.File.Seek(0, os.SEEK_CUR)
	}

	return nil
}

func (h *FileReader) buildDataWithLine(line []byte) Data {
	var data Data
	if h.Fields != nil {
		data = make(Data, len(h.Fields)+1)
	} else {
		data = make(Data, 1)
	}
	data["line"] = string(line)

	for k, v := range h.Fields {
		data[k] = v
	}

	return data
}
<commit_msg>Fixes comment<commit_after>package main

import (
	"bufio"
	"bytes"
	"os"
)

type FileData struct {
	Data
	*HighWaterMark
}

type FileReader struct {
	File *os.File

	// Fields are user-configurable keys/values that are merged into the Data
	// that is sent to the remote system.
	Fields map[string]string

	position int64
	buf      *bufio.Reader

	partialBuf bytes.Buffer
}

func (h *FileReader) ReadLine() (*FileData, error) {
	h.initializePosition()

	if h.buf == nil {
		h.buf = bufio.NewReader(h.File)
	}

	line, err := h.buf.ReadBytes('\n')
	// It's possible to get both a partial line and an error (e.g., EOF). If that
	// happens, the partial line is written to a buffer and reused on the next
	// call.
	if line != nil {
		h.position += int64(len(line))
	}

	if err != nil {
		if line != nil {
			h.partialBuf.Write(line)
		}

		return nil, err
	} else {
		// If there is a partial buffer, use it
		if h.partialBuf.Len() > 0 {
			h.partialBuf.Write(line)
			line, _ = h.partialBuf.ReadBytes('\n')
		}

		fileData := &FileData{
			Data: h.buildDataWithLine(bytes.TrimRight(line, "\r\n")),
			HighWaterMark: &HighWaterMark{
				FilePath: h.File.Name(),
				Position: h.position,
			},
		}

		return fileData, nil
	}
}

func (h *FileReader) Position() int64 {
	h.initializePosition()

	return h.position
}

func (h *FileReader) initializePosition() error {
	if h.position == 0 {
		h.position, _ = h.File.Seek(0, os.SEEK_CUR)
	}

	return nil
}

func (h *FileReader) buildDataWithLine(line []byte) Data {
	var data Data
	if h.Fields != nil {
		data = make(Data, len(h.Fields)+1)
	} else {
		data = make(Data, 1)
	}
	data["line"] = string(line)

	for k, v := range h.Fields {
		data[k] = v
	}

	return data
}
<|endoftext|>


<commit_before>package timber

import (
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"strings"
)

/* unbuffered impl
type FileWriter struct {
	file io.WriteCloser
}
func NewFileWriter(name string) (*FileWriter) {
	fw := new(FileWriter)
	file, err := os.OpenFile(name, os.O_WRONLY | os.O_APPEND | os.O_CREATE, 0666)
	if err != nil {
		panic(fmt.Sprintf("TIMBER! Can't open: %v", name))
	}
	fw.file = file
	return fw
}

func (fw *FileWriter) LogWrite(msg string) {
	fw.file.Write([]byte(msg))
}

func (fw *FileWriter) Close() {
	fw.file.Close()
}
*/

// This writer has a buffer that I don't ever bother to flush, so it may take a while
// to see messages.  Filenames ending in .gz will automatically be compressed on write.
func NewFileWriter(name string) (LogWriter, error) {
	file, err := os.OpenFile(name, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return nil, fmt.Errorf("TIMBER! Can't open %v: %v", name, err)
	}
	var output io.WriteCloser = file
	// Wrap in gz writer
	if strings.HasSuffix(name, ".gz") {
		output = &gzFileWriter{
			gzip.NewWriter(output),
			output,
		}
	}
	return NewBufferedWriter(output)
}

type gzFileWriter struct {
	*gzip.Writer // the compressor
	file         io.WriteCloser
}

func (w *gzFileWriter) Close() error {
	w.Writer.Close()
	return w.file.Close()
}
<commit_msg>preprocess filename through a template<commit_after>package timber

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"strings"
	"text/template"
	"time"
)

/* unbuffered impl
type FileWriter struct {
	file io.WriteCloser
}
func NewFileWriter(name string) (*FileWriter) {
	fw := new(FileWriter)
	file, err := os.OpenFile(name, os.O_WRONLY | os.O_APPEND | os.O_CREATE, 0666)
	if err != nil {
		panic(fmt.Sprintf("TIMBER! Can't open: %v", name))
	}
	fw.file = file
	return fw
}

func (fw *FileWriter) LogWrite(msg string) {
	fw.file.Write([]byte(msg))
}

func (fw *FileWriter) Close() {
	fw.file.Close()
}
*/

type FilenameFields struct {
	Hostname string
	Date     time.Time
	Pid      int
}

func GetFilenameFields() *FilenameFields {
	h, _ := os.Hostname()
	return &FilenameFields{
		Hostname: h,
		Date:     time.Now(),
		Pid:      os.Getpid(),
	}
}

func preprocessFilename(name string) string {
	t := template.Must(template.New("filename").Parse(name))
	buf := new(bytes.Buffer)
	t.Execute(buf, GetFilenameFields())
	return buf.String()
}

// This writer has a buffer that I don't ever bother to flush, so it may take a while
// to see messages.  Filenames ending in .gz will automatically be compressed on write.
// Filename string is proccessed through the template library using the FilenameFields
// struct.
func NewFileWriter(name string) (LogWriter, error) {
	name = preprocessFilename(name)
	file, err := os.OpenFile(name, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return nil, fmt.Errorf("TIMBER! Can't open %v: %v", name, err)
	}
	var output io.WriteCloser = file
	// Wrap in gz writer
	if strings.HasSuffix(name, ".gz") {
		output = &gzFileWriter{
			gzip.NewWriter(output),
			output,
		}
	}
	return NewBufferedWriter(output)
}

type gzFileWriter struct {
	*gzip.Writer // the compressor
	file         io.WriteCloser
}

func (w *gzFileWriter) Close() error {
	w.Writer.Close()
	return w.file.Close()
}
<|endoftext|>


<commit_before>package timber

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"math/rand"
	"os"
	"strings"
	"sync"
	"text/template"
	"time"
)

type FilenameFields struct {
	Hostname string
	Date     time.Time
	Pid      int
	Random   int64
}

func GetFilenameFields() *FilenameFields {
	h, _ := os.Hostname()
	return &FilenameFields{
		Hostname: h,
		Date:     time.Now(),
		Pid:      os.Getpid(),
		Random:   rand.Int63(),
	}
}

func preprocessFilename(name string) string {
	t := template.Must(template.New("filename").Parse(name))
	buf := new(bytes.Buffer)
	t.Execute(buf, GetFilenameFields())
	return buf.String()
}

type FileWriter struct {
	wr              *BufferedWriter
	cwr             *countingWriter
	BaseFilename    string
	currentFilename string
	mutex           *sync.RWMutex
	RotateChan      chan string // defaults to nil.  receives previous filename on rotate
	RotateSize      int64       // rotate after RotateSize bytes have been written to the file

	rotateTicker *time.Ticker
	rotateReset  chan int
}

// This writer has a buffer that I don't ever bother to flush, so it may take a while
// to see messages.  Filenames ending in .gz will automatically be compressed on write.
// Filename string is proccessed through the template library using the FilenameFields
// struct.
func NewFileWriter(name string) (*FileWriter, error) {
	w := &FileWriter{
		BaseFilename: name,
		mutex:        new(sync.RWMutex),
	}
	if err := w.open(); err != nil {
		return nil, err
	}
	return w, nil
}

func (w *FileWriter) open() error {
	// No lock here
	name := preprocessFilename(w.BaseFilename)
	file, err := os.OpenFile(name, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return fmt.Errorf("TIMBER! Can't open %v: %v", name, err)
	}

	var cwr = &countingWriter{file, 0}
	var output io.WriteCloser = cwr
	// Wrap in gz writer
	if strings.HasSuffix(name, ".gz") {
		output = &gzFileWriter{
			gzip.NewWriter(output),
			output,
		}
	}

	// Locked from here
	w.mutex.Lock()
	defer w.mutex.Unlock()
	if w.wr != nil {
		w.wr.Close()
		// send previous filename on rotate chan
		if c := w.RotateChan; c != nil {
			c <- w.currentFilename
		}
	}
	w.currentFilename = name
	w.cwr = cwr
	w.wr, _ = NewBufferedWriter(output)

	return nil
}

func (w *FileWriter) LogWrite(m string) {
	w.mutex.RLock()
	defer w.mutex.RUnlock()
	w.wr.LogWrite(m)
	w.checkSize()
}

func (w *FileWriter) Flush() error {
	w.mutex.RLock()
	defer w.mutex.RUnlock()
	e := w.wr.Flush()
	w.checkSize()
	return e
}

// Close and re-open the file.
// You should use the timestamp in the filename if you're going to use rotation
func (w *FileWriter) Rotate() error {
	return w.open()
}

// Automatically rotate every `d`
func (w *FileWriter) RotateEvery(d time.Duration) {
	// reset ticker
	w.mutex.Lock()
	if w.rotateTicker != nil {
		w.rotateTicker.Stop()
		w.rotateReset <- 1
	}
	w.rotateTicker = time.NewTicker(d)
	w.mutex.Unlock()

	// trigger a rotate every X
	go func() {
		for {
			select {
			case <-w.rotateReset:
				return
			case <-w.rotateTicker.C:
				w.Rotate()
			}
		}
	}()
}

func (w *FileWriter) checkSize() {
	if w.RotateSize > 0 && w.cwr.bytesWritten >= w.RotateSize {
		go w.Rotate()
	}
}

func (w *FileWriter) Close() {
	w.mutex.Lock()
	defer w.mutex.Unlock()
	w.wr.Close()
	w.wr = nil
}

type countingWriter struct {
	io.WriteCloser
	bytesWritten int64
}

func (w *countingWriter) Write(b []byte) (int, error) {
	i, e := w.WriteCloser.Write(b)
	w.bytesWritten += int64(i)
	return i, e
}

type gzFileWriter struct {
	*gzip.Writer // the compressor
	file         io.WriteCloser
}

func (w *gzFileWriter) Close() error {
	w.Writer.Close()
	return w.file.Close()
}
<commit_msg>flush before closing<commit_after>package timber

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"math/rand"
	"os"
	"strings"
	"sync"
	"text/template"
	"time"
)

type FilenameFields struct {
	Hostname string
	Date     time.Time
	Pid      int
	Random   int64
}

func GetFilenameFields() *FilenameFields {
	h, _ := os.Hostname()
	return &FilenameFields{
		Hostname: h,
		Date:     time.Now(),
		Pid:      os.Getpid(),
		Random:   rand.Int63(),
	}
}

func preprocessFilename(name string) string {
	t := template.Must(template.New("filename").Parse(name))
	buf := new(bytes.Buffer)
	t.Execute(buf, GetFilenameFields())
	return buf.String()
}

type FileWriter struct {
	wr              *BufferedWriter
	cwr             *countingWriter
	BaseFilename    string
	currentFilename string
	mutex           *sync.RWMutex
	RotateChan      chan string // defaults to nil.  receives previous filename on rotate
	RotateSize      int64       // rotate after RotateSize bytes have been written to the file

	rotateTicker *time.Ticker
	rotateReset  chan int
}

// This writer has a buffer that I don't ever bother to flush, so it may take a while
// to see messages.  Filenames ending in .gz will automatically be compressed on write.
// Filename string is proccessed through the template library using the FilenameFields
// struct.
func NewFileWriter(name string) (*FileWriter, error) {
	w := &FileWriter{
		BaseFilename: name,
		mutex:        new(sync.RWMutex),
	}
	if err := w.open(); err != nil {
		return nil, err
	}
	return w, nil
}

func (w *FileWriter) open() error {
	// No lock here
	name := preprocessFilename(w.BaseFilename)
	file, err := os.OpenFile(name, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return fmt.Errorf("TIMBER! Can't open %v: %v", name, err)
	}

	var cwr = &countingWriter{file, 0}
	var output io.WriteCloser = cwr
	// Wrap in gz writer
	if strings.HasSuffix(name, ".gz") {
		output = &gzFileWriter{
			gzip.NewWriter(output),
			output,
		}
	}

	// Locked from here
	w.mutex.Lock()
	defer w.mutex.Unlock()
	if w.wr != nil {
		w.wr.Close()
		// send previous filename on rotate chan
		if c := w.RotateChan; c != nil {
			c <- w.currentFilename
		}
	}
	w.currentFilename = name
	w.cwr = cwr
	w.wr, _ = NewBufferedWriter(output)

	return nil
}

func (w *FileWriter) LogWrite(m string) {
	w.mutex.RLock()
	defer w.mutex.RUnlock()
	w.wr.LogWrite(m)
	w.checkSize()
}

func (w *FileWriter) Flush() error {
	w.mutex.RLock()
	defer w.mutex.RUnlock()
	e := w.wr.Flush()
	w.checkSize()
	return e
}

// Close and re-open the file.
// You should use the timestamp in the filename if you're going to use rotation
func (w *FileWriter) Rotate() error {
	return w.open()
}

// Automatically rotate every `d`
func (w *FileWriter) RotateEvery(d time.Duration) {
	// reset ticker
	w.mutex.Lock()
	if w.rotateTicker != nil {
		w.rotateTicker.Stop()
		w.rotateReset <- 1
	}
	w.rotateTicker = time.NewTicker(d)
	w.mutex.Unlock()

	// trigger a rotate every X
	go func() {
		for {
			select {
			case <-w.rotateReset:
				return
			case <-w.rotateTicker.C:
				w.Rotate()
			}
		}
	}()
}

func (w *FileWriter) checkSize() {
	if w.RotateSize > 0 && w.cwr.bytesWritten >= w.RotateSize {
		go w.Rotate()
	}
}

func (w *FileWriter) Close() {
	w.mutex.Lock()
	defer w.mutex.Unlock()
	w.wr.Flush()
	w.wr.Close()
	w.wr = nil
}

type countingWriter struct {
	io.WriteCloser
	bytesWritten int64
}

func (w *countingWriter) Write(b []byte) (int, error) {
	i, e := w.WriteCloser.Write(b)
	w.bytesWritten += int64(i)
	return i, e
}

type gzFileWriter struct {
	*gzip.Writer // the compressor
	file         io.WriteCloser
}

func (w *gzFileWriter) Close() error {
	w.Writer.Close()
	return w.file.Close()
}
<|endoftext|>


<commit_before>package filter

import (
	"errors"
	"image"
	"strconv"

	"github.com/jangler/imp/util"
)

var cropHelp = `crop x y w h

Resize the image canvas to start at (x, y) pixels relative to the top-left
corner of the working image, and be w by h pixels in size. It is possible to
enlarge the canvas in this way; pixels that were beyond the borders of the
working image will be blank.`

func cropFunc(img *image.RGBA, args []string) (*image.RGBA, []string) {
	numArgs := 0
	dim := make([]int, 4)
	for numArgs < 4 && len(args) > 0 {
		n, err := strconv.ParseInt(args[0], 10, 0)
		if err != nil {
			break
		}
		dim[numArgs] = int(n)
		args = args[1:]
		numArgs++
	}
	if numArgs != 4 {
		util.Die(errors.New(cropHelp))
	}

	b1 := img.Bounds()
	newImg := image.NewRGBA(image.Rect(0, 0, dim[2], dim[3]))
	b2 := newImg.Bounds()
	for y := 0; y < dim[3]; y++ {
		for x := 0; x < dim[2]; x++ {
			color := img.At(b1.Min.X+dim[0]+x, b1.Min.Y+dim[1]+y)
			newImg.Set(b2.Min.X+x, b2.Min.Y+y, color)
		}
	}

	return newImg, args
}

func init() {
	addFilter(&Filter{"crop", cropHelp, cropFunc})
}
<commit_msg>Allow percentage arguments to crop filter<commit_after>package filter

import (
	"errors"
	"image"
	"strconv"

	"github.com/jangler/imp/util"
)

var cropHelp = `crop x y w h

Resize the image canvas to start at (x, y) pixels relative to the top-left
corner of the working image, and be w by h pixels in size. It is possible to
enlarge the canvas in this way; pixels that were beyond the borders of the
working image will be blank. If an argument ends in %, it is interpreted as a
percentage of the working image's dimension instead of a pixel count.`

func cropFunc(img *image.RGBA, args []string) (*image.RGBA, []string) {
	numArgs := 0
	dim := make([]int, 4)
	b1 := img.Bounds()
	for numArgs < 4 && len(args) > 0 {
		if args[0][len(args[0])-1] == '%' {
			p, err := strconv.ParseFloat(args[0][:len(args[0])-1], 64)
			if err != nil {
				break
			}
			if numArgs % 2 == 0 {
				dim[numArgs] = int(p / 100 * float64(b1.Dx()))
			} else {
				dim[numArgs] = int(p / 100 * float64(b1.Dy()))
			}
		} else {
			n, err := strconv.ParseInt(args[0], 10, 0)
			if err != nil {
				break
			}
			dim[numArgs] = int(n)
		}
		args = args[1:]
		numArgs++
	}
	if numArgs != 4 {
		util.Die(errors.New(cropHelp))
	}

	newImg := image.NewRGBA(image.Rect(0, 0, dim[2], dim[3]))
	b2 := newImg.Bounds()
	for y := 0; y < dim[3]; y++ {
		for x := 0; x < dim[2]; x++ {
			color := img.At(b1.Min.X+dim[0]+x, b1.Min.Y+dim[1]+y)
			newImg.Set(b2.Min.X+x, b2.Min.Y+y, color)
		}
	}

	return newImg, args
}

func init() {
	addFilter(&Filter{"crop", cropHelp, cropFunc})
}
<|endoftext|>


<commit_before>package main

import (
	"sort"
)

type RankedCoordFinder struct { // slow implementation. using only for visualiza
	board     Board
	remaining []*Coord
}

func (f *RankedCoordFinder) NextOpenCoordinate(board Board, coord XY) (*Coord, bool) {
	f.board = board
	f.RefreshCoordinates()

	if len(f.remaining) == 0 {
		return nil, false
	}

	c := f.remaining[0]
	f.remaining = f.remaining[0:]

	return c, true
}

func (f *RankedCoordFinder) RefreshCoordinates() {
	f.remaining = []*Coord{}
	for x := 0; x < len(f.board); x++ {
		for y := 0; y < len(f.board); y++ {
			if f.board[x][y] == 0 {
				f.remaining = append(f.remaining, &Coord{x, y})
			}
		}
	}
	sort.Sort(f)
}

func (f *RankedCoordFinder) Len() int {
	return len(f.remaining)
}
func (f *RankedCoordFinder) Less(i, j int) bool {
	return len(f.board.AvailableValuesAtCoordinate(f.remaining[i])) <
		len(f.board.AvailableValuesAtCoordinate(f.remaining[j]))
}
func (f *RankedCoordFinder) Swap(i, j int) {
	f.remaining[i], f.remaining[j] = f.remaining[j], f.remaining[i]
}
<commit_msg>Update comments in ranked finder<commit_after>package main

import (
	"sort"
)

// Ranked Coordinate Finder is slower for a given coordinate, but faster in solving an entire board. When backtracking is taken into consideration, it is imperative that the first coordinates attempted have the least number of values available to attempt.
type RankedCoordFinder struct {
	board     Board
	remaining []*Coord
}

func (f *RankedCoordFinder) NextOpenCoordinate(board Board, coord XY) (*Coord, bool) {
	f.board = board
	f.RefreshCoordinates()

	if len(f.remaining) == 0 {
		return nil, false
	}

	c := f.remaining[0]
	f.remaining = f.remaining[0:]

	return c, true
}

func (f *RankedCoordFinder) RefreshCoordinates() {
	f.remaining = []*Coord{}
	for x := 0; x < len(f.board); x++ {
		for y := 0; y < len(f.board); y++ {
			if f.board[x][y] == 0 {
				f.remaining = append(f.remaining, &Coord{x, y})
			}
		}
	}
	sort.Sort(f)
}

func (f *RankedCoordFinder) Len() int {
	return len(f.remaining)
}
func (f *RankedCoordFinder) Less(i, j int) bool {
	return len(f.board.AvailableValuesAtCoordinate(f.remaining[i])) <
		len(f.board.AvailableValuesAtCoordinate(f.remaining[j]))
}
func (f *RankedCoordFinder) Swap(i, j int) {
	f.remaining[i], f.remaining[j] = f.remaining[j], f.remaining[i]
}
<|endoftext|>


<commit_before>package mailbox

import (
	"runtime"
	"sync/atomic"

	"github.com/AsynkronIT/protoactor-go/internal/queue/mpsc"
	"github.com/AsynkronIT/protoactor-go/log"
)

type Statistics interface {
	MailboxStarted()
	MessagePosted(message interface{})
	MessageReceived(message interface{})
	MailboxEmpty()
}

// MessageInvoker is the interface used by a mailbox to forward messages for processing
type MessageInvoker interface {
	InvokeSystemMessage(interface{})
	InvokeUserMessage(interface{})
	EscalateFailure(reason interface{}, message interface{})
}

// The Inbound interface is used to enqueue messages to the mailbox
type Inbound interface {
	PostUserMessage(message interface{})
	PostSystemMessage(message interface{})
	Start()
}

// Producer is a function which creates a new mailbox
type Producer func(invoker MessageInvoker, dispatcher Dispatcher) Inbound

const (
	idle int32 = iota
	running
)

type defaultMailbox struct {
	userMailbox     queue
	systemMailbox   *mpsc.Queue
	schedulerStatus int32
	userMessages    int32
	sysMessages     int32
	invoker         MessageInvoker
	dispatcher      Dispatcher
	suspended       bool
	mailboxStats    []Statistics
}

func (m *defaultMailbox) PostUserMessage(message interface{}) {
	for _, ms := range m.mailboxStats {
		ms.MessagePosted(message)
	}
	m.userMailbox.Push(message)
	atomic.AddInt32(&m.userMessages, 1)
	m.schedule()
}

func (m *defaultMailbox) PostSystemMessage(message interface{}) {
	m.systemMailbox.Push(message)
	atomic.AddInt32(&m.sysMessages, 1)
	m.schedule()
}

func (m *defaultMailbox) schedule() {
	if atomic.CompareAndSwapInt32(&m.schedulerStatus, idle, running) {
		m.dispatcher.Schedule(m.processMessages)
	}
}

func (m *defaultMailbox) processMessages() {

process:
	m.run()

	// set mailbox to idle
	atomic.StoreInt32(&m.schedulerStatus, idle)
	sys := atomic.LoadInt32(&m.sysMessages)
	user := atomic.LoadInt32(&m.userMessages)
	// check if there are still messages to process (sent after the message loop ended)
	if sys > 0 || (!m.suspended && user > 0) {
		// try setting the mailbox back to running
		if atomic.CompareAndSwapInt32(&m.schedulerStatus, idle, running) {
			//	fmt.Printf("looping %v %v %v\n", sys, user, m.suspended)
			goto process
		}
	}

	for _, ms := range m.mailboxStats {
		ms.MailboxEmpty()
	}
}

func (m *defaultMailbox) run() {
	var msg interface{}

	defer func() {
		if r := recover(); r != nil {
			plog.Debug("[ACTOR] Recovering", log.Object("actor", m.invoker), log.Object("reason", r), log.Stack())
			m.invoker.EscalateFailure(r, msg)
		}
	}()

	i, t := 0, m.dispatcher.Throughput()
	for {
		if i > t {
			i = 0
			runtime.Gosched()
		}

		i++

		// keep processing system messages until queue is empty
		if msg = m.systemMailbox.Pop(); msg != nil {
			switch msg.(type) {
			case *SuspendMailbox:
				atomic.AddInt32(&m.sysMessages, -1)
				m.suspended = true
			case *ResumeMailbox:
				atomic.AddInt32(&m.sysMessages, -1)
				m.suspended = false
			default:
				atomic.AddInt32(&m.sysMessages, -1)
				m.invoker.InvokeSystemMessage(msg)
			}

			continue
		}

		// didn't process a system message, so break until we are resumed
		if m.suspended {
			return
		}

		if msg = m.userMailbox.Pop(); msg != nil {
			atomic.AddInt32(&m.userMessages, -1)
			m.invoker.InvokeUserMessage(msg)
			for _, ms := range m.mailboxStats {

				ms.MessageReceived(msg)
			}
		} else {
			return
		}
	}

}

func (m *defaultMailbox) Start() {
	for _, ms := range m.mailboxStats {
		ms.MailboxStarted()
	}
}
<commit_msg>decrement at top<commit_after>package mailbox

import (
	"runtime"
	"sync/atomic"

	"github.com/AsynkronIT/protoactor-go/internal/queue/mpsc"
	"github.com/AsynkronIT/protoactor-go/log"
)

type Statistics interface {
	MailboxStarted()
	MessagePosted(message interface{})
	MessageReceived(message interface{})
	MailboxEmpty()
}

// MessageInvoker is the interface used by a mailbox to forward messages for processing
type MessageInvoker interface {
	InvokeSystemMessage(interface{})
	InvokeUserMessage(interface{})
	EscalateFailure(reason interface{}, message interface{})
}

// The Inbound interface is used to enqueue messages to the mailbox
type Inbound interface {
	PostUserMessage(message interface{})
	PostSystemMessage(message interface{})
	Start()
}

// Producer is a function which creates a new mailbox
type Producer func(invoker MessageInvoker, dispatcher Dispatcher) Inbound

const (
	idle int32 = iota
	running
)

type defaultMailbox struct {
	userMailbox     queue
	systemMailbox   *mpsc.Queue
	schedulerStatus int32
	userMessages    int32
	sysMessages     int32
	invoker         MessageInvoker
	dispatcher      Dispatcher
	suspended       bool
	mailboxStats    []Statistics
}

func (m *defaultMailbox) PostUserMessage(message interface{}) {
	for _, ms := range m.mailboxStats {
		ms.MessagePosted(message)
	}
	m.userMailbox.Push(message)
	atomic.AddInt32(&m.userMessages, 1)
	m.schedule()
}

func (m *defaultMailbox) PostSystemMessage(message interface{}) {
	m.systemMailbox.Push(message)
	atomic.AddInt32(&m.sysMessages, 1)
	m.schedule()
}

func (m *defaultMailbox) schedule() {
	if atomic.CompareAndSwapInt32(&m.schedulerStatus, idle, running) {
		m.dispatcher.Schedule(m.processMessages)
	}
}

func (m *defaultMailbox) processMessages() {

process:
	m.run()

	// set mailbox to idle
	atomic.StoreInt32(&m.schedulerStatus, idle)
	sys := atomic.LoadInt32(&m.sysMessages)
	user := atomic.LoadInt32(&m.userMessages)
	// check if there are still messages to process (sent after the message loop ended)
	if sys > 0 || (!m.suspended && user > 0) {
		// try setting the mailbox back to running
		if atomic.CompareAndSwapInt32(&m.schedulerStatus, idle, running) {
			//	fmt.Printf("looping %v %v %v\n", sys, user, m.suspended)
			goto process
		}
	}

	for _, ms := range m.mailboxStats {
		ms.MailboxEmpty()
	}
}

func (m *defaultMailbox) run() {
	var msg interface{}

	defer func() {
		if r := recover(); r != nil {
			plog.Debug("[ACTOR] Recovering", log.Object("actor", m.invoker), log.Object("reason", r), log.Stack())
			m.invoker.EscalateFailure(r, msg)
		}
	}()

	i, t := 0, m.dispatcher.Throughput()
	for {
		if i > t {
			i = 0
			runtime.Gosched()
		}

		i++

		// keep processing system messages until queue is empty
		if msg = m.systemMailbox.Pop(); msg != nil {
			atomic.AddInt32(&m.sysMessages, -1)
			switch msg.(type) {
			case *SuspendMailbox:
				m.suspended = true
			case *ResumeMailbox:
				m.suspended = false
			default:
				m.invoker.InvokeSystemMessage(msg)
			}

			continue
		}

		// didn't process a system message, so break until we are resumed
		if m.suspended {
			return
		}

		if msg = m.userMailbox.Pop(); msg != nil {
			atomic.AddInt32(&m.userMessages, -1)
			m.invoker.InvokeUserMessage(msg)
			for _, ms := range m.mailboxStats {

				ms.MessageReceived(msg)
			}
		} else {
			return
		}
	}

}

func (m *defaultMailbox) Start() {
	for _, ms := range m.mailboxStats {
		ms.MailboxStarted()
	}
}
<|endoftext|>