<commit_before>package tak

import "errors"

type MoveType byte

const (
	PlaceFlat MoveType = 1 + iota
	PlaceStanding
	PlaceCapstone
	SlideLeft
	SlideRight
	SlideUp
	SlideDown
)

const TypeMask MoveType = 0xf

type Move struct {
	X, Y   int
	Type   MoveType
	Slides []byte
}

func (m *Move) Equal(rhs *Move) bool {
	if m.X != rhs.X || m.Y != rhs.Y {
		return false
	}
	if m.Type != rhs.Type {
		return false
	}
	if m.Type >= SlideLeft {
		return true
	}
	if len(m.Slides) != len(rhs.Slides) {
		return false
	}
	for i, s := range m.Slides {
		if rhs.Slides[i] != s {
			return false
		}
	}
	return true
}

var (
	ErrOccupied       = errors.New("position is occupied")
	ErrIllegalSlide   = errors.New("illegal slide")
	ErrNoCapstone     = errors.New("capstone has already been played")
	ErrIllegalOpening = errors.New("illegal opening move")
)

func (p *Position) Move(m Move) (*Position, error) {
	var place Piece
	dx, dy := 0, 0
	switch m.Type {
	case PlaceFlat:
		place = MakePiece(p.ToMove(), Flat)
	case PlaceStanding:
		place = MakePiece(p.ToMove(), Standing)
	case PlaceCapstone:
		place = MakePiece(p.ToMove(), Capstone)
	case SlideLeft:
		dx = -1
	case SlideRight:
		dx = 1
	case SlideUp:
		dy = 1
	case SlideDown:
		dy = -1
	}
	next := *p
	next.move++
	if p.move < 2 {
		if place.Kind() != Flat {
			return nil, ErrIllegalOpening
		}
		place = MakePiece(place.Color().Flip(), place.Kind())
	}
	if place != 0 {
		if len(p.At(m.X, m.Y)) != 0 {
			return nil, ErrOccupied
		}
		next.board = make([]Square, len(p.board))
		copy(next.board, p.board)
		var stones *byte
		if place.Kind() == Capstone {
			if p.ToMove() == Black {
				stones = &next.blackCaps
			} else {
				stones = &next.whiteCaps
			}
		} else {
			if p.ToMove() == Black {
				stones = &next.blackStones
			} else {
				stones = &next.whiteStones
			}
		}
		if *stones == 0 {
			return nil, ErrNoCapstone
		}
		*stones--
		next.set(m.X, m.Y, []Piece{place})
		return &next, nil
	}

	stack := p.At(m.X, m.Y)
	ct := 0
	for _, c := range m.Slides {
		ct += int(c)
	}
	if ct > p.cfg.Size || ct < 1 || ct > len(stack) {
		return nil, ErrIllegalSlide
	}
	if stack[0].Color() != p.ToMove() {
		return nil, ErrIllegalSlide
	}
	next.board = make([]Square, len(p.board))
	copy(next.board, p.board)
	next.set(m.X, m.Y, stack[ct:])
	stack = stack[:ct]
	for _, c := range m.Slides {
		m.X += dx
		m.Y += dy
		if m.X < 0 || m.X >= next.cfg.Size ||
			m.Y < 0 || m.Y >= next.cfg.Size {
			return nil, ErrIllegalSlide
		}
		if int(c) < 1 || int(c) > len(stack) {
			return nil, ErrIllegalSlide
		}
		base := next.At(m.X, m.Y)
		if len(base) > 0 {
			switch base[0].Kind() {
			case Flat:
			case Capstone:
				return nil, ErrIllegalSlide
			case Standing:
				if len(stack) != 1 || stack[0].Kind() != Capstone {
					return nil, ErrIllegalSlide
				}
			}
		}
		tmp := make([]Piece, int(c)+len(base))
		copy(tmp[:c], stack[len(stack)-int(c):])
		copy(tmp[c:], base)
		if len(tmp) > int(c) {
			tmp[c] = MakePiece(tmp[c].Color(), Flat)
		}
		next.set(m.X, m.Y, tmp)
		stack = stack[:len(stack)-int(c)]
	}

	return &next, nil
}

var slides [][][]byte

func init() {
	slides = make([][][]byte, 10)
	for s := 1; s <= 8; s++ {
		slides[s] = calculateSlides(s)
	}
}

func calculateSlides(stack int) [][]byte {
	var out [][]byte
	for i := byte(1); i <= byte(stack); i++ {
		out = append(out, []byte{i})
		for _, sub := range slides[stack-int(i)] {
			t := make([]byte, len(sub)+1)
			t[0] = i
			copy(t[1:], sub)
			out = append(out, t)
		}
	}
	return out
}

func (p *Position) AllMoves() []Move {
	moves := make([]Move, 0, len(p.board))
	next := p.ToMove()
	cap := false
	if next == White {
		cap = p.whiteCaps > 0
	} else {
		cap = p.blackCaps > 0
	}
	for x := 0; x < p.cfg.Size; x++ {
		for y := 0; y < p.cfg.Size; y++ {
			stack := p.At(x, y)
			if len(stack) == 0 {
				moves = append(moves, Move{x, y, PlaceFlat, nil})
				if p.move >= 2 {
					moves = append(moves, Move{x, y, PlaceStanding, nil})
					if cap {
						moves = append(moves, Move{x, y, PlaceCapstone, nil})
					}
				}
				continue
			}
			if p.move < 2 {
				continue
			}
			if stack[0].Color() != next {
				continue
			}
			type dircnt struct {
				d MoveType
				c int
			}
			dirs := [4]dircnt{
				{SlideLeft, x},
				{SlideRight, p.cfg.Size - x - 1},
				{SlideDown, y},
				{SlideUp, p.cfg.Size - y - 1},
			}
			for _, d := range dirs {
				h := len(stack)
				if h > p.cfg.Size {
					h = p.cfg.Size
				}
				for _, s := range slides[h] {
					if len(s) <= d.c {
						moves = append(moves, Move{x, y, d.d, s})
					}
				}
			}
		}
	}

	return moves
}
<commit_msg>tweak slide code<commit_after>package tak

import "errors"

type MoveType byte

const (
	PlaceFlat MoveType = 1 + iota
	PlaceStanding
	PlaceCapstone
	SlideLeft
	SlideRight
	SlideUp
	SlideDown
)

const TypeMask MoveType = 0xf

type Move struct {
	X, Y   int
	Type   MoveType
	Slides []byte
}

func (m *Move) Equal(rhs *Move) bool {
	if m.X != rhs.X || m.Y != rhs.Y {
		return false
	}
	if m.Type != rhs.Type {
		return false
	}
	if m.Type >= SlideLeft {
		return true
	}
	if len(m.Slides) != len(rhs.Slides) {
		return false
	}
	for i, s := range m.Slides {
		if rhs.Slides[i] != s {
			return false
		}
	}
	return true
}

var (
	ErrOccupied       = errors.New("position is occupied")
	ErrIllegalSlide   = errors.New("illegal slide")
	ErrNoCapstone     = errors.New("capstone has already been played")
	ErrIllegalOpening = errors.New("illegal opening move")
)

func (p *Position) Move(m Move) (*Position, error) {
	var place Piece
	dx, dy := 0, 0
	switch m.Type {
	case PlaceFlat:
		place = MakePiece(p.ToMove(), Flat)
	case PlaceStanding:
		place = MakePiece(p.ToMove(), Standing)
	case PlaceCapstone:
		place = MakePiece(p.ToMove(), Capstone)
	case SlideLeft:
		dx = -1
	case SlideRight:
		dx = 1
	case SlideUp:
		dy = 1
	case SlideDown:
		dy = -1
	}
	next := *p
	next.move++
	if p.move < 2 {
		if place.Kind() != Flat {
			return nil, ErrIllegalOpening
		}
		place = MakePiece(place.Color().Flip(), place.Kind())
	}
	if place != 0 {
		if len(p.At(m.X, m.Y)) != 0 {
			return nil, ErrOccupied
		}
		next.board = make([]Square, len(p.board))
		copy(next.board, p.board)
		var stones *byte
		if place.Kind() == Capstone {
			if p.ToMove() == Black {
				stones = &next.blackCaps
			} else {
				stones = &next.whiteCaps
			}
		} else {
			if p.ToMove() == Black {
				stones = &next.blackStones
			} else {
				stones = &next.whiteStones
			}
		}
		if *stones == 0 {
			return nil, ErrNoCapstone
		}
		*stones--
		next.set(m.X, m.Y, []Piece{place})
		return &next, nil
	}

	stack := p.At(m.X, m.Y)
	ct := 0
	for _, c := range m.Slides {
		ct += int(c)
	}
	if ct > p.cfg.Size || ct < 1 || ct > len(stack) {
		return nil, ErrIllegalSlide
	}
	if stack[0].Color() != p.ToMove() {
		return nil, ErrIllegalSlide
	}
	next.board = make([]Square, len(p.board))
	copy(next.board, p.board)
	next.set(m.X, m.Y, stack[ct:])
	stack = stack[:ct:ct]
	for _, c := range m.Slides {
		m.X += dx
		m.Y += dy
		if m.X < 0 || m.X >= next.cfg.Size ||
			m.Y < 0 || m.Y >= next.cfg.Size {
			return nil, ErrIllegalSlide
		}
		if int(c) < 1 || int(c) > len(stack) {
			return nil, ErrIllegalSlide
		}
		base := next.At(m.X, m.Y)
		if len(base) > 0 {
			switch base[0].Kind() {
			case Flat:
			case Capstone:
				return nil, ErrIllegalSlide
			case Standing:
				if len(stack) != 1 || stack[0].Kind() != Capstone {
					return nil, ErrIllegalSlide
				}
			}
		}
		tmp := append(stack, base...)
		if len(tmp) > int(c) {
			tmp[c] = MakePiece(tmp[c].Color(), Flat)
		}
		next.set(m.X, m.Y, tmp)
		stack = stack[:len(stack)-int(c) : len(stack)-int(c)]
	}

	return &next, nil
}

var slides [][][]byte

func init() {
	slides = make([][][]byte, 10)
	for s := 1; s <= 8; s++ {
		slides[s] = calculateSlides(s)
	}
}

func calculateSlides(stack int) [][]byte {
	var out [][]byte
	for i := byte(1); i <= byte(stack); i++ {
		out = append(out, []byte{i})
		for _, sub := range slides[stack-int(i)] {
			t := make([]byte, len(sub)+1)
			t[0] = i
			copy(t[1:], sub)
			out = append(out, t)
		}
	}
	return out
}

func (p *Position) AllMoves() []Move {
	moves := make([]Move, 0, len(p.board))
	next := p.ToMove()
	cap := false
	if next == White {
		cap = p.whiteCaps > 0
	} else {
		cap = p.blackCaps > 0
	}
	for x := 0; x < p.cfg.Size; x++ {
		for y := 0; y < p.cfg.Size; y++ {
			stack := p.At(x, y)
			if len(stack) == 0 {
				moves = append(moves, Move{x, y, PlaceFlat, nil})
				if p.move >= 2 {
					moves = append(moves, Move{x, y, PlaceStanding, nil})
					if cap {
						moves = append(moves, Move{x, y, PlaceCapstone, nil})
					}
				}
				continue
			}
			if p.move < 2 {
				continue
			}
			if stack[0].Color() != next {
				continue
			}
			type dircnt struct {
				d MoveType
				c int
			}
			dirs := [4]dircnt{
				{SlideLeft, x},
				{SlideRight, p.cfg.Size - x - 1},
				{SlideDown, y},
				{SlideUp, p.cfg.Size - y - 1},
			}
			for _, d := range dirs {
				h := len(stack)
				if h > p.cfg.Size {
					h = p.cfg.Size
				}
				for _, s := range slides[h] {
					if len(s) <= d.c {
						moves = append(moves, Move{x, y, d.d, s})
					}
				}
			}
		}
	}

	return moves
}
<|endoftext|>


<commit_before>package shared

type ImageProperties map[string]string

type ImageAlias struct {
	Name        string `json:"target"`
	Description string `json:"description"`
}

type ImageAliases []ImageAlias

type ImageInfo struct {
	Aliases      ImageAliases      `json:"aliases"`
	Architecture int               `json:"architecture"`
	Fingerprint  string            `json:"fingerprint"`
	Filename     string            `json:"filename"`
	Properties   map[string]string `json:"properties"`
	Public       interface{}       `json:"public"`
	Size         int64             `json:"size"`
	CreationDate int64             `json:"created_at"`
	ExpiryDate   int64             `json:"expires_at"`
	UploadDate   int64             `json:"uploaded_at"`
}

/*
 * BriefImageInfo contains a subset of the fields in
 * ImageInfo, namely those which a user may update
 */
type BriefImageInfo struct {
	Properties map[string]string `json:"properties"`
	Public     interface{}       `json:"public"`
}

func (i *ImageInfo) BriefInfo() BriefImageInfo {
	retstate := BriefImageInfo{
		Properties: i.Properties,
		Public:     i.Public}
	return retstate
}

type ImageBaseInfo struct {
	Id           int
	Fingerprint  string
	Filename     string
	Size         int64
	Public       interface{}
	Architecture int
	CreationDate int64
	ExpiryDate   int64
	UploadDate   int64
}
<commit_msg>Fix image show/edit<commit_after>package shared

type ImageProperties map[string]string

type ImageAlias struct {
	Name        string `json:"target"`
	Description string `json:"description"`
}

type ImageAliases []ImageAlias

type ImageInfo struct {
	Aliases      ImageAliases      `json:"aliases"`
	Architecture int               `json:"architecture"`
	Fingerprint  string            `json:"fingerprint"`
	Filename     string            `json:"filename"`
	Properties   map[string]string `json:"properties"`
	Public       interface{}       `json:"public"`
	Size         int64             `json:"size"`
	CreationDate int64             `json:"created_at"`
	ExpiryDate   int64             `json:"expires_at"`
	UploadDate   int64             `json:"uploaded_at"`
}

/*
 * BriefImageInfo contains a subset of the fields in
 * ImageInfo, namely those which a user may update
 */
type BriefImageInfo struct {
	Properties map[string]string `json:"properties"`
	Public     bool              `json:"public"`
}

func (i *ImageInfo) BriefInfo() BriefImageInfo {
	retstate := BriefImageInfo{
		Properties: i.Properties,
		Public:     InterfaceToBool(i.Public)}
	return retstate
}

type ImageBaseInfo struct {
	Id           int
	Fingerprint  string
	Filename     string
	Size         int64
	Public       interface{}
	Architecture int
	CreationDate int64
	ExpiryDate   int64
	UploadDate   int64
}
<|endoftext|>


<commit_before>package azurerm

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/network"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceArmNetworkInterface() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmNetworkInterfaceCreate,
		Read:   resourceArmNetworkInterfaceRead,
		Update: resourceArmNetworkInterfaceCreate,
		Delete: resourceArmNetworkInterfaceDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"location": &schema.Schema{
				Type:      schema.TypeString,
				Required:  true,
				ForceNew:  true,
				StateFunc: azureRMNormalizeLocation,
			},

			"resource_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"network_security_group_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"mac_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"private_ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"virtual_machine_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"ip_configuration": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"subnet_id": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"private_ip_address": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							Computed: true,
						},

						"private_ip_address_allocation": &schema.Schema{
							Type:         schema.TypeString,
							Required:     true,
							ValidateFunc: validateNetworkInterfacePrivateIpAddressAllocation,
						},

						"public_ip_address_id": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							Computed: true,
						},

						"load_balancer_backend_address_pools_ids": &schema.Schema{
							Type:     schema.TypeSet,
							Optional: true,
							Computed: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
							Set:      schema.HashString,
						},

						"load_balancer_inbound_nat_rules_ids": &schema.Schema{
							Type:     schema.TypeSet,
							Optional: true,
							Computed: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
							Set:      schema.HashString,
						},
					},
				},
				Set: resourceArmNetworkInterfaceIpConfigurationHash,
			},

			"dns_servers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"internal_dns_name_label": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"applied_dns_servers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"internal_fqdn": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient)
	ifaceClient := client.ifaceClient

	log.Printf("[INFO] preparing arguments for Azure ARM Network Interface creation.")

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	tags := d.Get("tags").(map[string]interface{})

	properties := network.InterfacePropertiesFormat{}

	if v, ok := d.GetOk("network_security_group_id"); ok {
		nsgId := v.(string)
		properties.NetworkSecurityGroup = &network.SecurityGroup{
			ID: &nsgId,
		}
	}

	dns, hasDns := d.GetOk("dns_servers")
	nameLabel, hasNameLabel := d.GetOk("internal_dns_name_label")
	if hasDns || hasNameLabel {
		ifaceDnsSettings := network.InterfaceDNSSettings{}

		if hasDns {
			var dnsServers []string
			dns := dns.(*schema.Set).List()
			for _, v := range dns {
				str := v.(string)
				dnsServers = append(dnsServers, str)
			}
			ifaceDnsSettings.DNSServers = &dnsServers
		}

		if hasNameLabel {
			name_label := nameLabel.(string)
			ifaceDnsSettings.InternalDNSNameLabel = &name_label

		}

		properties.DNSSettings = &ifaceDnsSettings
	}

	ipConfigs, sgErr := expandAzureRmNetworkInterfaceIpConfigurations(d)
	if sgErr != nil {
		return fmt.Errorf("Error Building list of Network Interface IP Configurations: %s", sgErr)
	}
	if len(ipConfigs) > 0 {
		properties.IPConfigurations = &ipConfigs
	}

	iface := network.Interface{
		Name:       &name,
		Location:   &location,
		Properties: &properties,
		Tags:       expandTags(tags),
	}

	resp, err := ifaceClient.CreateOrUpdate(resGroup, name, iface)
	if err != nil {
		return err
	}

	d.SetId(*resp.ID)

	log.Printf("[DEBUG] Waiting for Network Interface (%s) to become available", name)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"Accepted", "Updating"},
		Target:  []string{"Succeeded"},
		Refresh: networkInterfaceStateRefreshFunc(client, resGroup, name),
		Timeout: 10 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf("Error waiting for Network Interface (%s) to become available: %s", name, err)
	}

	return resourceArmNetworkInterfaceRead(d, meta)
}

func resourceArmNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) error {
	ifaceClient := meta.(*ArmClient).ifaceClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["networkInterfaces"]

	resp, err := ifaceClient.Get(resGroup, name, "")
	if resp.StatusCode == http.StatusNotFound {
		d.SetId("")
		return nil
	}
	if err != nil {
		return fmt.Errorf("Error making Read request on Azure Network Interface %s: %s", name, err)
	}

	iface := *resp.Properties

	if iface.MacAddress != nil {
		if *iface.MacAddress != "" {
			d.Set("mac_address", iface.MacAddress)
		}
	}

	if iface.IPConfigurations != nil && len(*iface.IPConfigurations) > 0 {
		var privateIPAddress *string
		for _, ipConfig := range *iface.IPConfigurations {
			privateIPAddress = ipConfig.Properties.PrivateIPAddress
		}

		if *privateIPAddress != "" {
			d.Set("private_ip_address", *privateIPAddress)
		}
	}

	if iface.VirtualMachine != nil {
		if *iface.VirtualMachine.ID != "" {
			d.Set("virtual_machine_id", *iface.VirtualMachine.ID)
		}
	}

	if iface.DNSSettings != nil {
		if iface.DNSSettings.AppliedDNSServers != nil && len(*iface.DNSSettings.AppliedDNSServers) > 0 {
			dnsServers := make([]string, 0, len(*iface.DNSSettings.AppliedDNSServers))
			for _, dns := range *iface.DNSSettings.AppliedDNSServers {
				dnsServers = append(dnsServers, dns)
			}

			if err := d.Set("applied_dns_servers", dnsServers); err != nil {
				return err
			}
		}

		if iface.DNSSettings.InternalFqdn != nil && *iface.DNSSettings.InternalFqdn != "" {
			d.Set("internal_fqdn", iface.DNSSettings.InternalFqdn)
		}
	}

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
	ifaceClient := meta.(*ArmClient).ifaceClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["networkInterfaces"]

	_, err = ifaceClient.Delete(resGroup, name)

	return err
}

func networkInterfaceStateRefreshFunc(client *ArmClient, resourceGroupName string, ifaceName string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		res, err := client.ifaceClient.Get(resourceGroupName, ifaceName, "")
		if err != nil {
			return nil, "", fmt.Errorf("Error issuing read request in networkInterfaceStateRefreshFunc to Azure ARM for network interace '%s' (RG: '%s'): %s", ifaceName, resourceGroupName, err)
		}

		return res, *res.Properties.ProvisioningState, nil
	}
}

func resourceArmNetworkInterfaceIpConfigurationHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["subnet_id"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["private_ip_address_allocation"].(string)))

	return hashcode.String(buf.String())
}

func validateNetworkInterfacePrivateIpAddressAllocation(v interface{}, k string) (ws []string, errors []error) {
	value := strings.ToLower(v.(string))
	allocations := map[string]bool{
		"static":  true,
		"dynamic": true,
	}

	if !allocations[value] {
		errors = append(errors, fmt.Errorf("Network Interface Allocations can only be Static or Dynamic"))
	}
	return
}

func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]network.InterfaceIPConfiguration, error) {
	configs := d.Get("ip_configuration").(*schema.Set).List()
	ipConfigs := make([]network.InterfaceIPConfiguration, 0, len(configs))

	for _, configRaw := range configs {
		data := configRaw.(map[string]interface{})

		subnet_id := data["subnet_id"].(string)
		private_ip_allocation_method := data["private_ip_address_allocation"].(string)

		properties := network.InterfaceIPConfigurationPropertiesFormat{
			Subnet: &network.Subnet{
				ID: &subnet_id,
			},
			PrivateIPAllocationMethod: &private_ip_allocation_method,
		}

		if v := data["private_ip_address"].(string); v != "" {
			properties.PrivateIPAddress = &v
		}

		if v := data["public_ip_address_id"].(string); v != "" {
			properties.PublicIPAddress = &network.PublicIPAddress{
				ID: &v,
			}
		}

		if v, ok := data["load_balancer_backend_address_pools_ids"]; ok {
			var ids []network.BackendAddressPool
			pools := v.(*schema.Set).List()
			for _, p := range pools {
				pool_id := p.(string)
				id := network.BackendAddressPool{
					ID: &pool_id,
				}

				ids = append(ids, id)
			}

			properties.LoadBalancerBackendAddressPools = &ids
		}

		if v, ok := data["load_balancer_inbound_nat_rules_ids"]; ok {
			var natRules []network.InboundNatRule
			rules := v.(*schema.Set).List()
			for _, r := range rules {
				rule_id := r.(string)
				rule := network.InboundNatRule{
					ID: &rule_id,
				}

				natRules = append(natRules, rule)
			}

			properties.LoadBalancerInboundNatRules = &natRules
		}

		name := data["name"].(string)
		ipConfig := network.InterfaceIPConfiguration{
			Name:       &name,
			Properties: &properties,
		}

		ipConfigs = append(ipConfigs, ipConfig)
	}

	return ipConfigs, nil
}
<commit_msg>Selecting the first element instead of using a loop for now. Change this to a loop when https://github.com/Azure/azure-sdk-for-go/issues/259 is fixed<commit_after>package azurerm

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/network"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceArmNetworkInterface() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmNetworkInterfaceCreate,
		Read:   resourceArmNetworkInterfaceRead,
		Update: resourceArmNetworkInterfaceCreate,
		Delete: resourceArmNetworkInterfaceDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"location": &schema.Schema{
				Type:      schema.TypeString,
				Required:  true,
				ForceNew:  true,
				StateFunc: azureRMNormalizeLocation,
			},

			"resource_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"network_security_group_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"mac_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"private_ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"virtual_machine_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"ip_configuration": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"subnet_id": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"private_ip_address": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							Computed: true,
						},

						"private_ip_address_allocation": &schema.Schema{
							Type:         schema.TypeString,
							Required:     true,
							ValidateFunc: validateNetworkInterfacePrivateIpAddressAllocation,
						},

						"public_ip_address_id": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							Computed: true,
						},

						"load_balancer_backend_address_pools_ids": &schema.Schema{
							Type:     schema.TypeSet,
							Optional: true,
							Computed: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
							Set:      schema.HashString,
						},

						"load_balancer_inbound_nat_rules_ids": &schema.Schema{
							Type:     schema.TypeSet,
							Optional: true,
							Computed: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
							Set:      schema.HashString,
						},
					},
				},
				Set: resourceArmNetworkInterfaceIpConfigurationHash,
			},

			"dns_servers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"internal_dns_name_label": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"applied_dns_servers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"internal_fqdn": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient)
	ifaceClient := client.ifaceClient

	log.Printf("[INFO] preparing arguments for Azure ARM Network Interface creation.")

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	tags := d.Get("tags").(map[string]interface{})

	properties := network.InterfacePropertiesFormat{}

	if v, ok := d.GetOk("network_security_group_id"); ok {
		nsgId := v.(string)
		properties.NetworkSecurityGroup = &network.SecurityGroup{
			ID: &nsgId,
		}
	}

	dns, hasDns := d.GetOk("dns_servers")
	nameLabel, hasNameLabel := d.GetOk("internal_dns_name_label")
	if hasDns || hasNameLabel {
		ifaceDnsSettings := network.InterfaceDNSSettings{}

		if hasDns {
			var dnsServers []string
			dns := dns.(*schema.Set).List()
			for _, v := range dns {
				str := v.(string)
				dnsServers = append(dnsServers, str)
			}
			ifaceDnsSettings.DNSServers = &dnsServers
		}

		if hasNameLabel {
			name_label := nameLabel.(string)
			ifaceDnsSettings.InternalDNSNameLabel = &name_label

		}

		properties.DNSSettings = &ifaceDnsSettings
	}

	ipConfigs, sgErr := expandAzureRmNetworkInterfaceIpConfigurations(d)
	if sgErr != nil {
		return fmt.Errorf("Error Building list of Network Interface IP Configurations: %s", sgErr)
	}
	if len(ipConfigs) > 0 {
		properties.IPConfigurations = &ipConfigs
	}

	iface := network.Interface{
		Name:       &name,
		Location:   &location,
		Properties: &properties,
		Tags:       expandTags(tags),
	}

	resp, err := ifaceClient.CreateOrUpdate(resGroup, name, iface)
	if err != nil {
		return err
	}

	d.SetId(*resp.ID)

	log.Printf("[DEBUG] Waiting for Network Interface (%s) to become available", name)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"Accepted", "Updating"},
		Target:  []string{"Succeeded"},
		Refresh: networkInterfaceStateRefreshFunc(client, resGroup, name),
		Timeout: 10 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf("Error waiting for Network Interface (%s) to become available: %s", name, err)
	}

	return resourceArmNetworkInterfaceRead(d, meta)
}

func resourceArmNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) error {
	ifaceClient := meta.(*ArmClient).ifaceClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["networkInterfaces"]

	resp, err := ifaceClient.Get(resGroup, name, "")
	if resp.StatusCode == http.StatusNotFound {
		d.SetId("")
		return nil
	}
	if err != nil {
		return fmt.Errorf("Error making Read request on Azure Network Interface %s: %s", name, err)
	}

	iface := *resp.Properties

	if iface.MacAddress != nil {
		if *iface.MacAddress != "" {
			d.Set("mac_address", iface.MacAddress)
		}
	}

	if iface.IPConfigurations != nil && len(*iface.IPConfigurations) > 0 {
		var privateIPAddress *string
		///TODO: Change this to a loop when https://github.com/Azure/azure-sdk-for-go/issues/259 is fixed
		if (*iface.IPConfigurations)[0].Properties != nil {
			privateIPAddress = (*iface.IPConfigurations)[0].Properties.PrivateIPAddress
		}

		if *privateIPAddress != "" {
			d.Set("private_ip_address", *privateIPAddress)
		}
	}

	if iface.VirtualMachine != nil {
		if *iface.VirtualMachine.ID != "" {
			d.Set("virtual_machine_id", *iface.VirtualMachine.ID)
		}
	}

	if iface.DNSSettings != nil {
		if iface.DNSSettings.AppliedDNSServers != nil && len(*iface.DNSSettings.AppliedDNSServers) > 0 {
			dnsServers := make([]string, 0, len(*iface.DNSSettings.AppliedDNSServers))
			for _, dns := range *iface.DNSSettings.AppliedDNSServers {
				dnsServers = append(dnsServers, dns)
			}

			if err := d.Set("applied_dns_servers", dnsServers); err != nil {
				return err
			}
		}

		if iface.DNSSettings.InternalFqdn != nil && *iface.DNSSettings.InternalFqdn != "" {
			d.Set("internal_fqdn", iface.DNSSettings.InternalFqdn)
		}
	}

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
	ifaceClient := meta.(*ArmClient).ifaceClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["networkInterfaces"]

	_, err = ifaceClient.Delete(resGroup, name)

	return err
}

func networkInterfaceStateRefreshFunc(client *ArmClient, resourceGroupName string, ifaceName string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		res, err := client.ifaceClient.Get(resourceGroupName, ifaceName, "")
		if err != nil {
			return nil, "", fmt.Errorf("Error issuing read request in networkInterfaceStateRefreshFunc to Azure ARM for network interace '%s' (RG: '%s'): %s", ifaceName, resourceGroupName, err)
		}

		return res, *res.Properties.ProvisioningState, nil
	}
}

func resourceArmNetworkInterfaceIpConfigurationHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["subnet_id"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["private_ip_address_allocation"].(string)))

	return hashcode.String(buf.String())
}

func validateNetworkInterfacePrivateIpAddressAllocation(v interface{}, k string) (ws []string, errors []error) {
	value := strings.ToLower(v.(string))
	allocations := map[string]bool{
		"static":  true,
		"dynamic": true,
	}

	if !allocations[value] {
		errors = append(errors, fmt.Errorf("Network Interface Allocations can only be Static or Dynamic"))
	}
	return
}

func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]network.InterfaceIPConfiguration, error) {
	configs := d.Get("ip_configuration").(*schema.Set).List()
	ipConfigs := make([]network.InterfaceIPConfiguration, 0, len(configs))

	for _, configRaw := range configs {
		data := configRaw.(map[string]interface{})

		subnet_id := data["subnet_id"].(string)
		private_ip_allocation_method := data["private_ip_address_allocation"].(string)

		properties := network.InterfaceIPConfigurationPropertiesFormat{
			Subnet: &network.Subnet{
				ID: &subnet_id,
			},
			PrivateIPAllocationMethod: &private_ip_allocation_method,
		}

		if v := data["private_ip_address"].(string); v != "" {
			properties.PrivateIPAddress = &v
		}

		if v := data["public_ip_address_id"].(string); v != "" {
			properties.PublicIPAddress = &network.PublicIPAddress{
				ID: &v,
			}
		}

		if v, ok := data["load_balancer_backend_address_pools_ids"]; ok {
			var ids []network.BackendAddressPool
			pools := v.(*schema.Set).List()
			for _, p := range pools {
				pool_id := p.(string)
				id := network.BackendAddressPool{
					ID: &pool_id,
				}

				ids = append(ids, id)
			}

			properties.LoadBalancerBackendAddressPools = &ids
		}

		if v, ok := data["load_balancer_inbound_nat_rules_ids"]; ok {
			var natRules []network.InboundNatRule
			rules := v.(*schema.Set).List()
			for _, r := range rules {
				rule_id := r.(string)
				rule := network.InboundNatRule{
					ID: &rule_id,
				}

				natRules = append(natRules, rule)
			}

			properties.LoadBalancerInboundNatRules = &natRules
		}

		name := data["name"].(string)
		ipConfig := network.InterfaceIPConfiguration{
			Name:       &name,
			Properties: &properties,
		}

		ipConfigs = append(ipConfigs, ipConfig)
	}

	return ipConfigs, nil
}
<|endoftext|>


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

package shell

import (
	"strings"

	"github.com/mgutz/str"
	"github.com/pkg/errors"
	"github.com/sascha-andres/devenv"
)

type (
	// Interpreter contains data for where and what to do
	Interpreter struct {
		ExecuteScriptDirectory string
		EnvConfiguration       devenv.EnvironmentConfiguration
	}
)

var (
	repositoryCommands []Commander
	commands           []Commander
)

// NewInterpreter returns a new interpreter
func NewInterpreter(path string, ev devenv.EnvironmentConfiguration) *Interpreter {
	return &Interpreter{ExecuteScriptDirectory: path, EnvConfiguration: ev}
}

func (i *Interpreter) getProcess() devenv.EnvironmentExternalProcessConfiguration {
	return i.EnvConfiguration.ProcessConfiguration
}

// Execute takes a line entered by the user and calls the command
func (i *Interpreter) Execute(commandline string) error {
	if strings.TrimSpace(commandline) == "" {
		return nil
	}
	tokenize := str.ToArgv(commandline)
	switch tokenize[0] {
	case "repo":
		return i.executeFromCommands(repositoryCommands, true, tokenize[1:])
	}
	return i.executeFromCommands(commands, false, tokenize)
}

func (i *Interpreter) executeFromCommands(commands []Commander, specific bool, arguments []string) error {
	var err error
	var responsible bool
	for _, val := range commands {
		if responsible, err = tryExecuteCommand(val, i, specific, arguments); responsible {
			break
		}
	}
	if err != nil {
		return err
	}
	if specific {
		return errors.New("'" + arguments[0] + "' is not a valid function")
	}
	return errors.New("'" + arguments[1] + "' is not a valid function")
}

func tryExecuteCommand(val Commander, i *Interpreter, specific bool, arguments []string) (bool, error) {
	commandIndex := 0
	if specific {
		commandIndex = 1
	}
	if val.IsResponsible(arguments[commandIndex]) {
		if specific {
			return true, val.Execute(i, arguments[0], arguments[2:])
		}
		return true, val.Execute(i, "%", arguments[1:])
	}
	return false, nil
}
<commit_msg>Fixed interpreter<commit_after>// Copyright © 2017 Sascha Andres <sascha.andres@outlook.com>
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package shell

import (
	"strings"

	"github.com/mgutz/str"
	"github.com/pkg/errors"
	"github.com/sascha-andres/devenv"
)

type (
	// Interpreter contains data for where and what to do
	Interpreter struct {
		ExecuteScriptDirectory string
		EnvConfiguration       devenv.EnvironmentConfiguration
	}
)

var (
	repositoryCommands []Commander
	commands           []Commander
)

// NewInterpreter returns a new interpreter
func NewInterpreter(path string, ev devenv.EnvironmentConfiguration) *Interpreter {
	return &Interpreter{ExecuteScriptDirectory: path, EnvConfiguration: ev}
}

func (i *Interpreter) getProcess() devenv.EnvironmentExternalProcessConfiguration {
	return i.EnvConfiguration.ProcessConfiguration
}

// Execute takes a line entered by the user and calls the command
func (i *Interpreter) Execute(commandline string) error {
	if strings.TrimSpace(commandline) == "" {
		return nil
	}
	tokenize := str.ToArgv(commandline)
	switch tokenize[0] {
	case "repo":
		return i.executeFromCommands(repositoryCommands, true, tokenize[1:])
	}
	return i.executeFromCommands(commands, false, tokenize)
}

func (i *Interpreter) executeFromCommands(commands []Commander, specific bool, arguments []string) error {
	var err error
	for _, val := range commands {
		var responsible bool
		responsible, err = tryExecuteCommand(val, i, specific, arguments)
		if responsible {
			return nil
		}
	}
	if err != nil {
		return err
	}
	if specific {
		return errors.New("'" + arguments[1] + "' is not a valid function")
	}
	return errors.New("'" + arguments[0] + "' is not a valid function")
}

func tryExecuteCommand(val Commander, i *Interpreter, specific bool, arguments []string) (bool, error) {
	commandIndex := 0
	if specific {
		commandIndex = 1
	}
	if val.IsResponsible(arguments[commandIndex]) {
		if specific {
			return true, val.Execute(i, arguments[1], arguments[2:])
		}
		return true, val.Execute(i, "%", arguments[1:])
	}
	return false, nil
}
<|endoftext|>


<commit_before>package gtk

// #include <gtk/gtk.h>
// #include "gtk.go.h"
import "C"
import (
	"errors"
	"unsafe"

	"github.com/gotk3/gotk3/glib"
)

func init() {
	tm := []glib.TypeMarshaler{
		{glib.Type(C.gtk_combo_box_get_type()), marshalComboBox},
		{glib.Type(C.gtk_combo_box_text_get_type()), marshalComboBoxText},
	}

	glib.RegisterGValueMarshalers(tm)

	WrapMap["GtkComboBox"] = wrapComboBox
	WrapMap["GtkComboBoxText"] = wrapComboBoxText
}

/*
 * GtkComboBox
 */

// ComboBox is a representation of GTK's GtkComboBox.
type ComboBox struct {
	Bin

	// Interfaces
	CellLayout
}

// native returns a pointer to the underlying GtkComboBox.
func (v *ComboBox) native() *C.GtkComboBox {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkComboBox(p)
}

func (v *ComboBox) toCellLayout() *C.GtkCellLayout {
	if v == nil {
		return nil
	}
	return C.toGtkCellLayout(unsafe.Pointer(v.GObject))
}

func marshalComboBox(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

func wrapComboBox(obj *glib.Object) *ComboBox {
	cl := wrapCellLayout(obj)
	return &ComboBox{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}, *cl}
}

// ComboBoxNew() is a wrapper around gtk_combo_box_new().
func ComboBoxNew() (*ComboBox, error) {
	c := C.gtk_combo_box_new()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// ComboBoxNewWithEntry() is a wrapper around gtk_combo_box_new_with_entry().
func ComboBoxNewWithEntry() (*ComboBox, error) {
	c := C.gtk_combo_box_new_with_entry()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// ComboBoxNewWithModel() is a wrapper around gtk_combo_box_new_with_model().
func ComboBoxNewWithModel(model ITreeModel) (*ComboBox, error) {
	c := C.gtk_combo_box_new_with_model(model.toTreeModel())
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// GetActive() is a wrapper around gtk_combo_box_get_active().
func (v *ComboBox) GetActive() int {
	c := C.gtk_combo_box_get_active(v.native())
	return int(c)
}

// SetActive() is a wrapper around gtk_combo_box_set_active().
func (v *ComboBox) SetActive(index int) {
	C.gtk_combo_box_set_active(v.native(), C.gint(index))
}

// GetActiveIter is a wrapper around gtk_combo_box_get_active_iter().
func (v *ComboBox) GetActiveIter() (*TreeIter, error) {
	var cIter C.GtkTreeIter
	c := C.gtk_combo_box_get_active_iter(v.native(), &cIter)
	if !gobool(c) {
		return nil, errors.New("unable to get active iter")
	}
	return &TreeIter{cIter}, nil
}

// SetActiveIter is a wrapper around gtk_combo_box_set_active_iter().
func (v *ComboBox) SetActiveIter(iter *TreeIter) {
	var cIter *C.GtkTreeIter
	if iter != nil {
		cIter = &iter.GtkTreeIter
	}
	C.gtk_combo_box_set_active_iter(v.native(), cIter)
}

// GetActiveID is a wrapper around gtk_combo_box_get_active_id().
func (v *ComboBox) GetActiveID() string {
	c := C.gtk_combo_box_get_active_id(v.native())
	return C.GoString((*C.char)(c))
}

// SetActiveID is a wrapper around gtk_combo_box_set_active_id().
func (v *ComboBox) SetActiveID(id string) bool {
	cid := C.CString(id)
	defer C.free(unsafe.Pointer(cid))
	c := C.gtk_combo_box_set_active_id(v.native(), (*C.gchar)(cid))
	return gobool(c)
}

// GetModel is a wrapper around gtk_combo_box_get_model().
func (v *ComboBox) GetModel() (*TreeModel, error) {
	c := C.gtk_combo_box_get_model(v.native())
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapTreeModel(obj), nil
}

// SetModel is a wrapper around gtk_combo_box_set_model().
func (v *ComboBox) SetModel(model ITreeModel) {
	C.gtk_combo_box_set_model(v.native(), model.toTreeModel())
}

/*
 * GtkComboBoxText
 */

// ComboBoxText is a representation of GTK's GtkComboBoxText.
type ComboBoxText struct {
	ComboBox
}

// native returns a pointer to the underlying GtkComboBoxText.
func (v *ComboBoxText) native() *C.GtkComboBoxText {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkComboBoxText(p)
}

func marshalComboBoxText(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

func wrapComboBoxText(obj *glib.Object) *ComboBoxText {
	return &ComboBoxText{*wrapComboBox(obj)}
}

// ComboBoxTextNew is a wrapper around gtk_combo_box_text_new().
func ComboBoxTextNew() (*ComboBoxText, error) {
	c := C.gtk_combo_box_text_new()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

// ComboBoxTextNewWithEntry is a wrapper around gtk_combo_box_text_new_with_entry().
func ComboBoxTextNewWithEntry() (*ComboBoxText, error) {
	c := C.gtk_combo_box_text_new_with_entry()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

// Append is a wrapper around gtk_combo_box_text_append().
func (v *ComboBoxText) Append(id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_append(v.native(), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// Prepend is a wrapper around gtk_combo_box_text_prepend().
func (v *ComboBoxText) Prepend(id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_prepend(v.native(), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// Insert is a wrapper around gtk_combo_box_text_insert().
func (v *ComboBoxText) Insert(position int, id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_insert(v.native(), C.gint(position), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// AppendText is a wrapper around gtk_combo_box_text_append_text().
func (v *ComboBoxText) AppendText(text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_append_text(v.native(), (*C.gchar)(cstr))
}

// PrependText is a wrapper around gtk_combo_box_text_prepend_text().
func (v *ComboBoxText) PrependText(text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_prepend_text(v.native(), (*C.gchar)(cstr))
}

// InsertText is a wrapper around gtk_combo_box_text_insert_text().
func (v *ComboBoxText) InsertText(position int, text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_insert_text(v.native(), C.gint(position), (*C.gchar)(cstr))
}

// Remove is a wrapper around gtk_combo_box_text_remove().
func (v *ComboBoxText) Remove(position int) {
	C.gtk_combo_box_text_remove(v.native(), C.gint(position))
}

// RemoveAll is a wrapper around gtk_combo_box_text_remove_all().
func (v *ComboBoxText) RemoveAll() {
	C.gtk_combo_box_text_remove_all(v.native())
}

// GetActiveText is a wrapper around gtk_combo_box_text_get_active_text().
func (v *ComboBoxText) GetActiveText() string {
	c := (*C.char)(C.gtk_combo_box_text_get_active_text(v.native()))
	defer C.free(unsafe.Pointer(c))
	return C.GoString(c)
}
<commit_msg>Added ComboBox Popup/Popdown methods<commit_after>package gtk

// #include <gtk/gtk.h>
// #include "gtk.go.h"
import "C"
import (
	"errors"
	"unsafe"

	"github.com/gotk3/gotk3/glib"
)

func init() {
	tm := []glib.TypeMarshaler{
		{glib.Type(C.gtk_combo_box_get_type()), marshalComboBox},
		{glib.Type(C.gtk_combo_box_text_get_type()), marshalComboBoxText},
	}

	glib.RegisterGValueMarshalers(tm)

	WrapMap["GtkComboBox"] = wrapComboBox
	WrapMap["GtkComboBoxText"] = wrapComboBoxText
}

/*
 * GtkComboBox
 */

// ComboBox is a representation of GTK's GtkComboBox.
type ComboBox struct {
	Bin

	// Interfaces
	CellLayout
}

// native returns a pointer to the underlying GtkComboBox.
func (v *ComboBox) native() *C.GtkComboBox {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkComboBox(p)
}

func (v *ComboBox) toCellLayout() *C.GtkCellLayout {
	if v == nil {
		return nil
	}
	return C.toGtkCellLayout(unsafe.Pointer(v.GObject))
}

func marshalComboBox(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

func wrapComboBox(obj *glib.Object) *ComboBox {
	cl := wrapCellLayout(obj)
	return &ComboBox{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}, *cl}
}

// ComboBoxNew() is a wrapper around gtk_combo_box_new().
func ComboBoxNew() (*ComboBox, error) {
	c := C.gtk_combo_box_new()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// ComboBoxNewWithEntry() is a wrapper around gtk_combo_box_new_with_entry().
func ComboBoxNewWithEntry() (*ComboBox, error) {
	c := C.gtk_combo_box_new_with_entry()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// ComboBoxNewWithModel() is a wrapper around gtk_combo_box_new_with_model().
func ComboBoxNewWithModel(model ITreeModel) (*ComboBox, error) {
	c := C.gtk_combo_box_new_with_model(model.toTreeModel())
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// GetActive() is a wrapper around gtk_combo_box_get_active().
func (v *ComboBox) GetActive() int {
	c := C.gtk_combo_box_get_active(v.native())
	return int(c)
}

// SetActive() is a wrapper around gtk_combo_box_set_active().
func (v *ComboBox) SetActive(index int) {
	C.gtk_combo_box_set_active(v.native(), C.gint(index))
}

// GetActiveIter is a wrapper around gtk_combo_box_get_active_iter().
func (v *ComboBox) GetActiveIter() (*TreeIter, error) {
	var cIter C.GtkTreeIter
	c := C.gtk_combo_box_get_active_iter(v.native(), &cIter)
	if !gobool(c) {
		return nil, errors.New("unable to get active iter")
	}
	return &TreeIter{cIter}, nil
}

// SetActiveIter is a wrapper around gtk_combo_box_set_active_iter().
func (v *ComboBox) SetActiveIter(iter *TreeIter) {
	var cIter *C.GtkTreeIter
	if iter != nil {
		cIter = &iter.GtkTreeIter
	}
	C.gtk_combo_box_set_active_iter(v.native(), cIter)
}

// GetActiveID is a wrapper around gtk_combo_box_get_active_id().
func (v *ComboBox) GetActiveID() string {
	c := C.gtk_combo_box_get_active_id(v.native())
	return C.GoString((*C.char)(c))
}

// SetActiveID is a wrapper around gtk_combo_box_set_active_id().
func (v *ComboBox) SetActiveID(id string) bool {
	cid := C.CString(id)
	defer C.free(unsafe.Pointer(cid))
	c := C.gtk_combo_box_set_active_id(v.native(), (*C.gchar)(cid))
	return gobool(c)
}

// GetModel is a wrapper around gtk_combo_box_get_model().
func (v *ComboBox) GetModel() (*TreeModel, error) {
	c := C.gtk_combo_box_get_model(v.native())
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapTreeModel(obj), nil
}

// SetModel is a wrapper around gtk_combo_box_set_model().
func (v *ComboBox) SetModel(model ITreeModel) {
	C.gtk_combo_box_set_model(v.native(), model.toTreeModel())
}

func (v *ComboBox) Popup() {
	C.gtk_combo_box_popup(v.native())
}

func (v *ComboBox) Popdown() {
	C.gtk_combo_box_popdown(v.native())
}

/*
 * GtkComboBoxText
 */

// ComboBoxText is a representation of GTK's GtkComboBoxText.
type ComboBoxText struct {
	ComboBox
}

// native returns a pointer to the underlying GtkComboBoxText.
func (v *ComboBoxText) native() *C.GtkComboBoxText {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkComboBoxText(p)
}

func marshalComboBoxText(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

func wrapComboBoxText(obj *glib.Object) *ComboBoxText {
	return &ComboBoxText{*wrapComboBox(obj)}
}

// ComboBoxTextNew is a wrapper around gtk_combo_box_text_new().
func ComboBoxTextNew() (*ComboBoxText, error) {
	c := C.gtk_combo_box_text_new()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

// ComboBoxTextNewWithEntry is a wrapper around gtk_combo_box_text_new_with_entry().
func ComboBoxTextNewWithEntry() (*ComboBoxText, error) {
	c := C.gtk_combo_box_text_new_with_entry()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

// Append is a wrapper around gtk_combo_box_text_append().
func (v *ComboBoxText) Append(id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_append(v.native(), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// Prepend is a wrapper around gtk_combo_box_text_prepend().
func (v *ComboBoxText) Prepend(id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_prepend(v.native(), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// Insert is a wrapper around gtk_combo_box_text_insert().
func (v *ComboBoxText) Insert(position int, id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_insert(v.native(), C.gint(position), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// AppendText is a wrapper around gtk_combo_box_text_append_text().
func (v *ComboBoxText) AppendText(text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_append_text(v.native(), (*C.gchar)(cstr))
}

// PrependText is a wrapper around gtk_combo_box_text_prepend_text().
func (v *ComboBoxText) PrependText(text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_prepend_text(v.native(), (*C.gchar)(cstr))
}

// InsertText is a wrapper around gtk_combo_box_text_insert_text().
func (v *ComboBoxText) InsertText(position int, text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_insert_text(v.native(), C.gint(position), (*C.gchar)(cstr))
}

// Remove is a wrapper around gtk_combo_box_text_remove().
func (v *ComboBoxText) Remove(position int) {
	C.gtk_combo_box_text_remove(v.native(), C.gint(position))
}

// RemoveAll is a wrapper around gtk_combo_box_text_remove_all().
func (v *ComboBoxText) RemoveAll() {
	C.gtk_combo_box_text_remove_all(v.native())
}

// GetActiveText is a wrapper around gtk_combo_box_text_get_active_text().
func (v *ComboBoxText) GetActiveText() string {
	c := (*C.char)(C.gtk_combo_box_text_get_active_text(v.native()))
	defer C.free(unsafe.Pointer(c))
	return C.GoString(c)
}
<|endoftext|>


<commit_before>package jeebie

import (
	"github.com/valep27/go-jeebie/jeebie/cpu"
	"github.com/valep27/go-jeebie/jeebie/memory"
	"github.com/valep27/go-jeebie/jeebie/video"
	"github.com/veandco/go-sdl2/sdl"
	"io/ioutil"
)

// Emulator represents the root struct and entry point for running the emulation
type Emulator struct {
	cpu    *cpu.CPU
	gpu    *video.GPU
	mem    *memory.MMU
	screen *video.Screen
}

func (e *Emulator) init() {
	e.mem = memory.New()
	e.screen = video.NewScreen()

	e.cpu = cpu.New(e.mem)
	e.gpu = video.NewGpu(e.screen, e.mem)
}

// New creates a new emulator instance
func New() *Emulator {
	e := &Emulator{}
	e.init()

	return e
}

// NewWithFile creates a new emulator instance and loads the file specified into it.
func NewWithFile(path string) (*Emulator, error) {
	_, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	// TODO: detect cartridge type and map to memory

	e := &Emulator{}
	e.init()

	return e, nil
}

func (e *Emulator) Tick() {
	cycles := e.cpu.Tick()
	e.gpu.Tick(cycles)
}

// Run executes the main loop of the emulator
func (e *Emulator) Run() {
	for {
		e.Tick()

		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {

			switch t := event.(type) {
			case *sdl.KeyDownEvent:
				if t.Keysym.Sym == sdl.K_ESCAPE {
					defer e.screen.Destroy()
					defer sdl.Quit()
					return
				}
			case *sdl.KeyUpEvent:

			}
		}
	}
}
<commit_msg>add cartridge type and loading of data<commit_after>package jeebie

import (
	"github.com/valep27/go-jeebie/jeebie/cpu"
	"github.com/valep27/go-jeebie/jeebie/memory"
	"github.com/valep27/go-jeebie/jeebie/video"
	"github.com/veandco/go-sdl2/sdl"
	"io/ioutil"
	"log"
)

// Emulator represents the root struct and entry point for running the emulation
type Emulator struct {
	cpu    *cpu.CPU
	gpu    *video.GPU
	mem    *memory.MMU
	cart   *Cartridge
	screen *video.Screen
}

func (e *Emulator) init() {
	e.mem = memory.New()
	e.screen = video.NewScreen()

	e.cpu = cpu.New(e.mem)
	e.gpu = video.NewGpu(e.screen, e.mem)
	e.cart = nil
}

// New creates a new emulator instance
func New() *Emulator {
	e := &Emulator{}
	e.init()

	return e
}

// NewWithFile creates a new emulator instance and loads the file specified into it.
func NewWithFile(path string) (*Emulator, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	log.Printf("Loaded %f bytes of ROM data\n", len(data))

	e := &Emulator{}
	e.init()
	e.cart = NewCartridgeWithData(data)

	return e, nil
}

func (e *Emulator) Tick() {
	cycles := e.cpu.Tick()
	e.gpu.Tick(cycles)
}

// Run executes the main loop of the emulator
func (e *Emulator) Run() {
	for {
		e.Tick()

		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {

			switch t := event.(type) {
			case *sdl.KeyDownEvent:
				if t.Keysym.Sym == sdl.K_ESCAPE {
					defer e.screen.Destroy()
					defer sdl.Quit()
					return
				}
			case *sdl.KeyUpEvent:

			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package sync

import (
	"fmt"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/sasha-s/go-deadlock"
)

type Mutex interface {
	Lock()
	Unlock()
}

type RWMutex interface {
	Mutex
	RLock()
	RUnlock()
}

type WaitGroup interface {
	Add(int)
	Done()
	Wait()
}

func NewMutex() Mutex {
	if useDeadlock {
		return &deadlock.Mutex{}
	}
	if debug {
		mutex := &loggedMutex{}
		mutex.holder.Store(holder{})
		return mutex
	}
	return &sync.Mutex{}
}

func NewRWMutex() RWMutex {
	if useDeadlock {
		return &deadlock.RWMutex{}
	}
	if debug {
		mutex := &loggedRWMutex{
			readHolders: make(map[int][]holder),
			unlockers:   make(chan holder, 1024),
		}
		mutex.holder.Store(holder{})
		return mutex
	}
	return &sync.RWMutex{}
}

func NewWaitGroup() WaitGroup {
	if debug {
		return &loggedWaitGroup{}
	}
	return &sync.WaitGroup{}
}

type holder struct {
	at   string
	time time.Time
	goid int
}

func (h holder) String() string {
	if h.at == "" {
		return "not held"
	}
	return fmt.Sprintf("at %s goid: %d for %s", h.at, h.goid, time.Since(h.time))
}

type loggedMutex struct {
	sync.Mutex
	holder atomic.Value
}

func (m *loggedMutex) Lock() {
	m.Mutex.Lock()
	m.holder.Store(getHolder())
}

func (m *loggedMutex) Unlock() {
	currentHolder := m.holder.Load().(holder)
	duration := time.Since(currentHolder.time)
	if duration >= threshold {
		l.Debugf("Mutex held for %v. Locked at %s unlocked at %s", duration, currentHolder.at, getHolder().at)
	}
	m.holder.Store(holder{})
	m.Mutex.Unlock()
}

func (m *loggedMutex) Holders() string {
	return m.holder.Load().(holder).String()
}

type loggedRWMutex struct {
	sync.RWMutex
	holder atomic.Value

	readHolders    map[int][]holder
	readHoldersMut sync.Mutex

	logUnlockers int32
	unlockers    chan holder
}

func (m *loggedRWMutex) Lock() {
	start := time.Now()

	atomic.StoreInt32(&m.logUnlockers, 1)
	m.RWMutex.Lock()
	m.logUnlockers = 0

	holder := getHolder()
	m.holder.Store(holder)

	duration := holder.time.Sub(start)

	if duration > threshold {
		var unlockerStrings []string
	loop:
		for {
			select {
			case holder := <-m.unlockers:
				unlockerStrings = append(unlockerStrings, holder.String())
			default:
				break loop
			}
		}
		l.Debugf("RWMutex took %v to lock. Locked at %s. RUnlockers while locking:\n%s", duration, holder.at, strings.Join(unlockerStrings, "\n"))
	}
}

func (m *loggedRWMutex) Unlock() {
	currentHolder := m.holder.Load().(holder)
	duration := time.Since(currentHolder.time)
	if duration >= threshold {
		l.Debugf("RWMutex held for %v. Locked at %s unlocked at %s", duration, currentHolder.at, getHolder().at)
	}
	m.holder.Store(holder{})
	m.RWMutex.Unlock()
}

func (m *loggedRWMutex) RLock() {
	m.RWMutex.RLock()
	holder := getHolder()
	m.readHoldersMut.Lock()
	m.readHolders[holder.goid] = append(m.readHolders[holder.goid], holder)
	m.readHoldersMut.Unlock()
}

func (m *loggedRWMutex) RUnlock() {
	id := goid()
	m.readHoldersMut.Lock()
	current := m.readHolders[id]
	if len(current) > 0 {
		m.readHolders[id] = current[:len(current)-1]
	}
	m.readHoldersMut.Unlock()
	if atomic.LoadInt32(&m.logUnlockers) == 1 {
		holder := getHolder()
		select {
		case m.unlockers <- holder:
		default:
			l.Debugf("Dropped holder %s as channel full", holder)
		}
	}
	m.RWMutex.RUnlock()
}

func (m *loggedRWMutex) Holders() string {
	output := m.holder.Load().(holder).String() + " (writer)"
	m.readHoldersMut.Lock()
	for _, holders := range m.readHolders {
		for _, holder := range holders {
			output += "\n" + holder.String() + " (reader)"
		}
	}
	m.readHoldersMut.Unlock()
	return output
}

type loggedWaitGroup struct {
	sync.WaitGroup
}

func (wg *loggedWaitGroup) Wait() {
	start := time.Now()
	wg.WaitGroup.Wait()
	duration := time.Since(start)
	if duration >= threshold {
		l.Debugf("WaitGroup took %v at %s", duration, getHolder())
	}
}

func getHolder() holder {
	_, file, line, _ := runtime.Caller(2)
	file = filepath.Join(filepath.Base(filepath.Dir(file)), filepath.Base(file))
	return holder{
		at:   fmt.Sprintf("%s:%d", file, line),
		goid: goid(),
		time: time.Now(),
	}
}

func goid() int {
	var buf [64]byte
	n := runtime.Stack(buf[:], false)
	idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
	id, err := strconv.Atoi(idField)
	if err != nil {
		return -1
	}
	return id
}

// TimeoutCond is a variant on Cond. It has roughly the same semantics regarding 'L' - it must be held
// both when broadcasting and when calling TimeoutCondWaiter.Wait()
// Call Broadcast() to broadcast to all waiters on the TimeoutCond. Call SetupWait to create a
// TimeoutCondWaiter configured with the given timeout, which can then be used to listen for
// broadcasts.
type TimeoutCond struct {
	L  sync.Locker
	ch chan struct{}
}

// TimeoutCondWaiter is a type allowing a consumer to wait on a TimeoutCond with a timeout. Wait() may be called multiple times,
// and will return true every time that the TimeoutCond is broadcast to. Once the configured timeout
// expires, Wait() will return false.
// Call Stop() to release resources once this TimeoutCondWaiter is no longer needed.
type TimeoutCondWaiter struct {
	c     *TimeoutCond
	timer *time.Timer
}

func NewTimeoutCond(l sync.Locker) *TimeoutCond {
	return &TimeoutCond{
		L: l,
	}
}

func (c *TimeoutCond) Broadcast() {
	// ch.L must be locked when calling this function

	if c.ch != nil {
		close(c.ch)
		c.ch = nil
	}
}

func (c *TimeoutCond) SetupWait(timeout time.Duration) *TimeoutCondWaiter {
	timer := time.NewTimer(timeout)

	return &TimeoutCondWaiter{
		c:     c,
		timer: timer,
	}
}

func (w *TimeoutCondWaiter) Wait() bool {
	// ch.L must be locked when calling this function

	// Ensure that the channel exists, since we're going to be waiting on it
	if w.c.ch == nil {
		w.c.ch = make(chan struct{})
	}
	ch := w.c.ch

	w.c.L.Unlock()
	defer w.c.L.Lock()

	select {
	case <-w.timer.C:
		return false
	case <-ch:
		return true
	}
}

func (w *TimeoutCondWaiter) Stop() {
	w.timer.Stop()
}
<commit_msg>lib/sync: Fix a race in unlocker logging (fixes #3884)<commit_after>// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package sync

import (
	"fmt"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/sasha-s/go-deadlock"
)

type Mutex interface {
	Lock()
	Unlock()
}

type RWMutex interface {
	Mutex
	RLock()
	RUnlock()
}

type WaitGroup interface {
	Add(int)
	Done()
	Wait()
}

func NewMutex() Mutex {
	if useDeadlock {
		return &deadlock.Mutex{}
	}
	if debug {
		mutex := &loggedMutex{}
		mutex.holder.Store(holder{})
		return mutex
	}
	return &sync.Mutex{}
}

func NewRWMutex() RWMutex {
	if useDeadlock {
		return &deadlock.RWMutex{}
	}
	if debug {
		mutex := &loggedRWMutex{
			readHolders: make(map[int][]holder),
			unlockers:   make(chan holder, 1024),
		}
		mutex.holder.Store(holder{})
		return mutex
	}
	return &sync.RWMutex{}
}

func NewWaitGroup() WaitGroup {
	if debug {
		return &loggedWaitGroup{}
	}
	return &sync.WaitGroup{}
}

type holder struct {
	at   string
	time time.Time
	goid int
}

func (h holder) String() string {
	if h.at == "" {
		return "not held"
	}
	return fmt.Sprintf("at %s goid: %d for %s", h.at, h.goid, time.Since(h.time))
}

type loggedMutex struct {
	sync.Mutex
	holder atomic.Value
}

func (m *loggedMutex) Lock() {
	m.Mutex.Lock()
	m.holder.Store(getHolder())
}

func (m *loggedMutex) Unlock() {
	currentHolder := m.holder.Load().(holder)
	duration := time.Since(currentHolder.time)
	if duration >= threshold {
		l.Debugf("Mutex held for %v. Locked at %s unlocked at %s", duration, currentHolder.at, getHolder().at)
	}
	m.holder.Store(holder{})
	m.Mutex.Unlock()
}

func (m *loggedMutex) Holders() string {
	return m.holder.Load().(holder).String()
}

type loggedRWMutex struct {
	sync.RWMutex
	holder atomic.Value

	readHolders    map[int][]holder
	readHoldersMut sync.Mutex

	logUnlockers int32
	unlockers    chan holder
}

func (m *loggedRWMutex) Lock() {
	start := time.Now()

	atomic.StoreInt32(&m.logUnlockers, 1)
	m.RWMutex.Lock()
	atomic.StoreInt32(&m.logUnlockers, 0)

	holder := getHolder()
	m.holder.Store(holder)

	duration := holder.time.Sub(start)

	if duration > threshold {
		var unlockerStrings []string
	loop:
		for {
			select {
			case holder := <-m.unlockers:
				unlockerStrings = append(unlockerStrings, holder.String())
			default:
				break loop
			}
		}
		l.Debugf("RWMutex took %v to lock. Locked at %s. RUnlockers while locking:\n%s", duration, holder.at, strings.Join(unlockerStrings, "\n"))
	}
}

func (m *loggedRWMutex) Unlock() {
	currentHolder := m.holder.Load().(holder)
	duration := time.Since(currentHolder.time)
	if duration >= threshold {
		l.Debugf("RWMutex held for %v. Locked at %s unlocked at %s", duration, currentHolder.at, getHolder().at)
	}
	m.holder.Store(holder{})
	m.RWMutex.Unlock()
}

func (m *loggedRWMutex) RLock() {
	m.RWMutex.RLock()
	holder := getHolder()
	m.readHoldersMut.Lock()
	m.readHolders[holder.goid] = append(m.readHolders[holder.goid], holder)
	m.readHoldersMut.Unlock()
}

func (m *loggedRWMutex) RUnlock() {
	id := goid()
	m.readHoldersMut.Lock()
	current := m.readHolders[id]
	if len(current) > 0 {
		m.readHolders[id] = current[:len(current)-1]
	}
	m.readHoldersMut.Unlock()
	if atomic.LoadInt32(&m.logUnlockers) == 1 {
		holder := getHolder()
		select {
		case m.unlockers <- holder:
		default:
			l.Debugf("Dropped holder %s as channel full", holder)
		}
	}
	m.RWMutex.RUnlock()
}

func (m *loggedRWMutex) Holders() string {
	output := m.holder.Load().(holder).String() + " (writer)"
	m.readHoldersMut.Lock()
	for _, holders := range m.readHolders {
		for _, holder := range holders {
			output += "\n" + holder.String() + " (reader)"
		}
	}
	m.readHoldersMut.Unlock()
	return output
}

type loggedWaitGroup struct {
	sync.WaitGroup
}

func (wg *loggedWaitGroup) Wait() {
	start := time.Now()
	wg.WaitGroup.Wait()
	duration := time.Since(start)
	if duration >= threshold {
		l.Debugf("WaitGroup took %v at %s", duration, getHolder())
	}
}

func getHolder() holder {
	_, file, line, _ := runtime.Caller(2)
	file = filepath.Join(filepath.Base(filepath.Dir(file)), filepath.Base(file))
	return holder{
		at:   fmt.Sprintf("%s:%d", file, line),
		goid: goid(),
		time: time.Now(),
	}
}

func goid() int {
	var buf [64]byte
	n := runtime.Stack(buf[:], false)
	idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
	id, err := strconv.Atoi(idField)
	if err != nil {
		return -1
	}
	return id
}

// TimeoutCond is a variant on Cond. It has roughly the same semantics regarding 'L' - it must be held
// both when broadcasting and when calling TimeoutCondWaiter.Wait()
// Call Broadcast() to broadcast to all waiters on the TimeoutCond. Call SetupWait to create a
// TimeoutCondWaiter configured with the given timeout, which can then be used to listen for
// broadcasts.
type TimeoutCond struct {
	L  sync.Locker
	ch chan struct{}
}

// TimeoutCondWaiter is a type allowing a consumer to wait on a TimeoutCond with a timeout. Wait() may be called multiple times,
// and will return true every time that the TimeoutCond is broadcast to. Once the configured timeout
// expires, Wait() will return false.
// Call Stop() to release resources once this TimeoutCondWaiter is no longer needed.
type TimeoutCondWaiter struct {
	c     *TimeoutCond
	timer *time.Timer
}

func NewTimeoutCond(l sync.Locker) *TimeoutCond {
	return &TimeoutCond{
		L: l,
	}
}

func (c *TimeoutCond) Broadcast() {
	// ch.L must be locked when calling this function

	if c.ch != nil {
		close(c.ch)
		c.ch = nil
	}
}

func (c *TimeoutCond) SetupWait(timeout time.Duration) *TimeoutCondWaiter {
	timer := time.NewTimer(timeout)

	return &TimeoutCondWaiter{
		c:     c,
		timer: timer,
	}
}

func (w *TimeoutCondWaiter) Wait() bool {
	// ch.L must be locked when calling this function

	// Ensure that the channel exists, since we're going to be waiting on it
	if w.c.ch == nil {
		w.c.ch = make(chan struct{})
	}
	ch := w.c.ch

	w.c.L.Unlock()
	defer w.c.L.Lock()

	select {
	case <-w.timer.C:
		return false
	case <-ch:
		return true
	}
}

func (w *TimeoutCondWaiter) Stop() {
	w.timer.Stop()
}
<|endoftext|>


<commit_before>package util

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

const (
	CO_POD_NAME     = "CO_POD_NAME"
	CO_RUN_ID       = "CO_RUN_ID"
	CO_EVENT_LIST   = "CO_EVENT_LIST"
	CO_SERVICE_ADDR = "CO_SERVICE_ADDR"

	CO_COMPONENT_START = "CO_COMPONENT_START"
	CO_COMPONENT_STOP  = "CO_COMPONENT_STOP"

	CO_TASK_START  = "CO_TASK_START"
	CO_TASK_RESULT = "CO_TASK_RESULT"
	CO_TASK_STATUS = "CO_TASK_STATUS"

	CO_REGISTER_URL = "CO_register"

	CO_DATA = "CO_DATA"

	CO_SET_GLOBAL_VAR_URL = "CO_SET_GLOBAL_VAR_URL"

	CO_LINKSTART_TOKEN = "CO_LINKSTART_TOKEN"
	CO_LINKSTART_URL   = "CO_LINKSTART_URL"
)

var (
	eventIDMap   map[string]int64
	eventURLMap  map[string]string
	eventINFOMap map[string]string

	isWaitData      bool
	receiveDataChan chan map[string]interface{}
)

func init() {
	isWaitData = false
	receiveDataChan = make(chan map[string]interface{}, 1)
	eventIDMap = make(map[string]int64)
	eventURLMap = make(map[string]string)
	eventINFOMap = make(map[string]string)

	// init component env info
	log.Println("[component util]", "===>start init...")

	eventINFOMap[CO_POD_NAME] = os.Getenv(CO_POD_NAME)
	eventINFOMap[CO_RUN_ID] = os.Getenv(CO_RUN_ID)
	eventINFOMap[CO_DATA] = os.Getenv(CO_DATA)
	eventINFOMap[CO_SERVICE_ADDR] = os.Getenv(CO_SERVICE_ADDR)

	eventINFOMap[CO_EVENT_LIST] = os.Getenv(CO_EVENT_LIST)
	eventINFOMap[CO_COMPONENT_START] = os.Getenv(CO_COMPONENT_START)
	eventINFOMap[CO_COMPONENT_STOP] = os.Getenv(CO_COMPONENT_STOP)
	eventINFOMap[CO_TASK_START] = os.Getenv(CO_TASK_START)
	eventINFOMap[CO_TASK_RESULT] = os.Getenv(CO_TASK_RESULT)
	eventINFOMap[CO_TASK_STATUS] = os.Getenv(CO_TASK_STATUS)
	eventINFOMap[CO_REGISTER_URL] = os.Getenv(CO_REGISTER_URL)

	for _, eventInfo := range strings.Split(eventINFOMap[CO_EVENT_LIST], ";") {
		if len(strings.Split(eventInfo, ",")) > 1 {
			eventKey := strings.Split(eventInfo, ",")[0]
			eventId := strings.Split(eventInfo, ",")[1]

			eventIdInt, _ := strconv.ParseInt(eventId, 10, 64)
			eventIDMap[eventKey] = eventIdInt
			eventURLMap[eventKey] = os.Getenv(eventKey)
		}
	}

	eventURLMap[CO_SET_GLOBAL_VAR_URL] = os.Getenv(CO_SET_GLOBAL_VAR_URL)
	eventINFOMap[CO_LINKSTART_TOKEN] = os.Getenv(CO_LINKSTART_TOKEN)
	eventURLMap[CO_LINKSTART_URL] = os.Getenv(CO_LINKSTART_URL)

	log.Println("[component util]", "<===init done")
	log.Println("[component util]", "<===got event map:", eventINFOMap)
}

func NotifyEvent(eventName string, status bool, result, output string) error {
	if eventURLMap[eventName] == "" || eventIDMap[eventName] == int64(0) {
		log.Println("[component util]", "===>error when notify event:", eventName, " because event info is illegal, got evnet id:", eventIDMap[eventName], " and event url:", eventURLMap[eventName])
		return errors.New("event is illegal")
	}

	reqBody := make(map[string]interface{})
	reqBody["EVENT"] = eventName
	reqBody["EVENT_ID"] = eventIDMap[eventName]
	reqBody["RUN_ID"] = eventINFOMap[CO_RUN_ID]
	reqBody["INFO"] = map[string]interface{}{"status": status, "result": result, "output": output}

	reqBodyBytes, _ := json.Marshal(reqBody)

	log.Println("[component util]", "===>component start notify event:", eventName, " to ", eventURLMap[eventName], "reqBody:", reqBody)
	resp, err := http.Post(eventURLMap[eventName], "application/json", bytes.NewReader(reqBodyBytes))

	if err != nil {
		log.Println("[component util]", "===>component send event:", eventName, " to:", eventURLMap[eventName], " \t error, error is:", err.Error())
		return errors.New("error when send req to workflow")
	}

	respBody, _ := ioutil.ReadAll(resp.Body)

	log.Println("[component util]", "===>component send event:", eventName, " got resp:\n", string(respBody), "\n")
	return nil
}

func ComponentStart(info string) error {
	return NotifyEvent(CO_COMPONENT_START, true, info, "")
}

func ComponentStop(info string) error {
	return NotifyEvent(CO_COMPONENT_STOP, true, info, "")
}

func TaskStart(info string) error {
	return NotifyEvent(CO_TASK_START, true, info, "")
}

func TaskResult(info string) error {
	return NotifyEvent(CO_TASK_RESULT, true, info, "")
}

func TaskStatus(status bool, info, output string) error {
	return NotifyEvent(CO_TASK_STATUS, status, info, output)
}

func GetData(port int64, forceRefresh bool, dataChan chan map[string]interface{}) error {
	if !forceRefresh {
		dataMap := make(map[string]interface{})
		err := json.Unmarshal([]byte(eventINFOMap[CO_DATA]), &dataMap)
		if err == nil {
			dataChan <- dataMap
			return nil
		}

		log.Println("[component util]", "===>error when get CO_DATA:", err.Error(), " get data from server ...")
	}

	reqBody := make(map[string]interface{})
	reqBody["RUN_ID"] = eventINFOMap[CO_RUN_ID]
	reqBody["POD_NAME"] = eventINFOMap[CO_POD_NAME]
	reqBody["RECEIVE_URL"] = "/receivedata"

	reqBodyBytes, _ := json.Marshal(reqBody)

	log.Println("[component util]", "===>component send register req to:", eventURLMap[CO_REGISTER_URL], " with body:", string(reqBodyBytes))
	resp, err := http.Post(eventURLMap[CO_REGISTER_URL], "application/json", bytes.NewReader(reqBodyBytes))
	if err != nil {
		log.Println("[component util]", "===>error when get data from workflow:", err.Error())
		return errors.New("error when get data from workflow")
	}

	respBody, _ := ioutil.ReadAll(resp.Body)
	log.Println("[component util]", "===>component get register resp:", string(respBody), "\nstart wait workflow send data")

	// get data from workflow
	go waitData(port)

	data := <-receiveDataChan
	dataChan <- data

	return nil
}

func HoldProj(port int64) {
	if isWaitData {
		return
	}

	isWaitData = true
	http.ListenAndServe(":"+strconv.FormatInt(port, 10), nil)
}

func ChangeGlobalVar(varName, value string) error {
	reqBody := make(map[string]interface{})

	reqBody["RUN_ID"] = eventINFOMap[CO_RUN_ID]
	reqBody["varMap"] = map[string]interface{}{"KEY": varName, "VALUE": value}

	reqBodyBytes, _ := json.Marshal(reqBody)

	log.Println("[component util]", "===>component start change global var info, \nvar name:", varName, "\nvalue:", value, "\nreqBody:", reqBody, "\nto:", eventURLMap[CO_SET_GLOBAL_VAR_URL])
	resp, err := http.Post(eventURLMap[CO_SET_GLOBAL_VAR_URL], "application/json", bytes.NewReader(reqBodyBytes))

	if err != nil {
		log.Println("[component util]", "===>component send event:", CO_SET_GLOBAL_VAR_URL, " to:", eventURLMap[CO_SET_GLOBAL_VAR_URL], " \t error, error is:", err.Error())
		return errors.New("error when send req to workflow")
	}

	respBody, _ := ioutil.ReadAll(resp.Body)

	log.Println("[component util]", "===>component send event:", CO_SET_GLOBAL_VAR_URL, " got resp:\n", string(respBody), "\n")
	return nil
}

func LinkStart(workflowName, workflowVersion string, startJson map[string]interface{}) error {
	reqBody := make(map[string]interface{})

	startJsonBytes, _ := json.Marshal(startJson)

	reqBody["RUN_ID"] = eventINFOMap[CO_RUN_ID]
	reqBody["linkInfoMap"] = map[string]interface{}{"token": eventINFOMap[CO_LINKSTART_TOKEN], "workflowName": workflowName, "workflowVersion": workflowVersion, "startJson": string(startJsonBytes)}

	reqBodyBytes, _ := json.Marshal(reqBody)

	log.Println("[component util]", "===>component start link start, \ntoken:", eventINFOMap[CO_LINKSTART_TOKEN], "\nworkflow:", workflowName, ":", workflowVersion, "\nstartjson:", startJson, "\nbody:", string(reqBodyBytes), "\nto:", eventURLMap[CO_LINKSTART_URL]+workflowName)
	resp, err := http.Post(eventURLMap[CO_LINKSTART_URL]+workflowName, "application/json", bytes.NewReader(reqBodyBytes))
	if err != nil {
		log.Println("[component util]", "===>component send event:", CO_LINKSTART_URL, " to:", eventURLMap[CO_LINKSTART_URL]+workflowName, " \t error, error is:", err.Error())
		return errors.New("error when send req to workflow")
	}

	respBody, _ := ioutil.ReadAll(resp.Body)

	log.Println("[component util]", "===>component send event:", CO_LINKSTART_URL, " got resp:\n", string(respBody), "\n")
	return nil
}

func waitData(port int64) {
	if isWaitData {
		return
	}
	isWaitData = true

	http.HandleFunc("/receivedata", receiveDataHandler)
	http.ListenAndServe(":"+strconv.FormatInt(port, 10), nil)
}

func receiveDataHandler(w http.ResponseWriter, r *http.Request) {
	result, _ := json.Marshal(map[string]string{"message": "ok"})

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println("error when get data body:" + err.Error())
	}

	codePathMap := make(map[string]interface{})
	json.Unmarshal([]byte(body), &codePathMap)
	receiveDataChan <- codePathMap

	w.Write(result)
}
<commit_msg>Modify HoldProj: block forever or sleep for some time<commit_after>package util

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	CO_POD_NAME     = "CO_POD_NAME"
	CO_RUN_ID       = "CO_RUN_ID"
	CO_EVENT_LIST   = "CO_EVENT_LIST"
	CO_SERVICE_ADDR = "CO_SERVICE_ADDR"

	CO_COMPONENT_START = "CO_COMPONENT_START"
	CO_COMPONENT_STOP  = "CO_COMPONENT_STOP"

	CO_ACTION_TIMEOUT = "CO_ACTION_TIMEOUT"

	CO_TASK_START  = "CO_TASK_START"
	CO_TASK_RESULT = "CO_TASK_RESULT"
	CO_TASK_STATUS = "CO_TASK_STATUS"

	CO_REGISTER_URL = "CO_register"

	CO_DATA = "CO_DATA"

	CO_SET_GLOBAL_VAR_URL = "CO_SET_GLOBAL_VAR_URL"

	CO_LINKSTART_TOKEN = "CO_LINKSTART_TOKEN"
	CO_LINKSTART_URL   = "CO_LINKSTART_URL"
)

var (
	eventIDMap   map[string]int64
	eventURLMap  map[string]string
	eventINFOMap map[string]string

	isWaitData      bool
	receiveDataChan chan map[string]interface{}
)

func init() {
	isWaitData = false
	receiveDataChan = make(chan map[string]interface{}, 1)
	eventIDMap = make(map[string]int64)
	eventURLMap = make(map[string]string)
	eventINFOMap = make(map[string]string)

	// init component env info
	log.Println("[component util]", "===>start init...")

	eventINFOMap[CO_POD_NAME] = os.Getenv(CO_POD_NAME)
	eventINFOMap[CO_RUN_ID] = os.Getenv(CO_RUN_ID)
	eventINFOMap[CO_DATA] = os.Getenv(CO_DATA)
	eventINFOMap[CO_SERVICE_ADDR] = os.Getenv(CO_SERVICE_ADDR)

	eventINFOMap[CO_EVENT_LIST] = os.Getenv(CO_EVENT_LIST)
	eventINFOMap[CO_COMPONENT_START] = os.Getenv(CO_COMPONENT_START)
	eventINFOMap[CO_COMPONENT_STOP] = os.Getenv(CO_COMPONENT_STOP)
	eventINFOMap[CO_ACTION_TIMEOUT] = os.Getenv(CO_ACTION_TIMEOUT)
	eventINFOMap[CO_TASK_START] = os.Getenv(CO_TASK_START)
	eventINFOMap[CO_TASK_RESULT] = os.Getenv(CO_TASK_RESULT)
	eventINFOMap[CO_TASK_STATUS] = os.Getenv(CO_TASK_STATUS)
	eventINFOMap[CO_REGISTER_URL] = os.Getenv(CO_REGISTER_URL)

	for _, eventInfo := range strings.Split(eventINFOMap[CO_EVENT_LIST], ";") {
		if len(strings.Split(eventInfo, ",")) > 1 {
			eventKey := strings.Split(eventInfo, ",")[0]
			eventId := strings.Split(eventInfo, ",")[1]

			eventIdInt, _ := strconv.ParseInt(eventId, 10, 64)
			eventIDMap[eventKey] = eventIdInt
			eventURLMap[eventKey] = os.Getenv(eventKey)
		}
	}

	eventURLMap[CO_SET_GLOBAL_VAR_URL] = os.Getenv(CO_SET_GLOBAL_VAR_URL)
	eventINFOMap[CO_LINKSTART_TOKEN] = os.Getenv(CO_LINKSTART_TOKEN)
	eventURLMap[CO_LINKSTART_URL] = os.Getenv(CO_LINKSTART_URL)

	log.Println("[component util]", "<===init done")
	log.Println("[component util]", "<===got event map:", eventINFOMap)
}

func NotifyEvent(eventName string, status bool, result, output string) error {
	if eventURLMap[eventName] == "" || eventIDMap[eventName] == int64(0) {
		log.Println("[component util]", "===>error when notify event:", eventName, " because event info is illegal, got evnet id:", eventIDMap[eventName], " and event url:", eventURLMap[eventName])
		return errors.New("event is illegal")
	}

	reqBody := make(map[string]interface{})
	reqBody["EVENT"] = eventName
	reqBody["EVENT_ID"] = eventIDMap[eventName]
	reqBody["RUN_ID"] = eventINFOMap[CO_RUN_ID]
	reqBody["INFO"] = map[string]interface{}{"status": status, "result": result, "output": output}

	reqBodyBytes, _ := json.Marshal(reqBody)

	log.Println("[component util]", "===>component start notify event:", eventName, " to ", eventURLMap[eventName], "reqBody:", reqBody)
	resp, err := http.Post(eventURLMap[eventName], "application/json", bytes.NewReader(reqBodyBytes))

	if err != nil {
		log.Println("[component util]", "===>component send event:", eventName, " to:", eventURLMap[eventName], " \t error, error is:", err.Error())
		return errors.New("error when send req to workflow")
	}

	respBody, _ := ioutil.ReadAll(resp.Body)

	log.Println("[component util]", "===>component send event:", eventName, " got resp:\n", string(respBody), "\n")
	return nil
}

func ComponentStart(info string) error {
	return NotifyEvent(CO_COMPONENT_START, true, info, "")
}

func ComponentStop(info string) error {
	return NotifyEvent(CO_COMPONENT_STOP, true, info, "")
}

func TaskStart(info string) error {
	return NotifyEvent(CO_TASK_START, true, info, "")
}

func TaskResult(info string) error {
	return NotifyEvent(CO_TASK_RESULT, true, info, "")
}

func TaskStatus(status bool, info, output string) error {
	return NotifyEvent(CO_TASK_STATUS, status, info, output)
}

func GetData(port int64, forceRefresh bool, dataChan chan map[string]interface{}) error {
	if !forceRefresh {
		dataMap := make(map[string]interface{})
		err := json.Unmarshal([]byte(eventINFOMap[CO_DATA]), &dataMap)
		if err == nil {
			dataChan <- dataMap
			return nil
		}

		log.Println("[component util]", "===>error when get CO_DATA:", err.Error(), " get data from server ...")
	}

	reqBody := make(map[string]interface{})
	reqBody["RUN_ID"] = eventINFOMap[CO_RUN_ID]
	reqBody["POD_NAME"] = eventINFOMap[CO_POD_NAME]
	reqBody["RECEIVE_URL"] = "/receivedata"

	reqBodyBytes, _ := json.Marshal(reqBody)

	log.Println("[component util]", "===>component send register req to:", eventURLMap[CO_REGISTER_URL], " with body:", string(reqBodyBytes))
	resp, err := http.Post(eventURLMap[CO_REGISTER_URL], "application/json", bytes.NewReader(reqBodyBytes))
	if err != nil {
		log.Println("[component util]", "===>error when get data from workflow:", err.Error())
		return errors.New("error when get data from workflow")
	}

	respBody, _ := ioutil.ReadAll(resp.Body)
	log.Println("[component util]", "===>component get register resp:", string(respBody), "\nstart wait workflow send data")

	// get data from workflow
	go waitData(port)

	data := <-receiveDataChan
	dataChan <- data

	return nil
}

func HoldProj() {
	timeout, err := strconv.Atoi(eventINFOMap[CO_ACTION_TIMEOUT])
	if err != nil {
		timeout = 0
	}
	if timeout <= 0 {
		c := make(chan bool, 1)
		<- c
	} else {
		time.Sleep(timeout * time.Second)
	}
}

func ChangeGlobalVar(varName, value string) error {
	reqBody := make(map[string]interface{})

	reqBody["RUN_ID"] = eventINFOMap[CO_RUN_ID]
	reqBody["varMap"] = map[string]interface{}{"KEY": varName, "VALUE": value}

	reqBodyBytes, _ := json.Marshal(reqBody)

	log.Println("[component util]", "===>component start change global var info, \nvar name:", varName, "\nvalue:", value, "\nreqBody:", reqBody, "\nto:", eventURLMap[CO_SET_GLOBAL_VAR_URL])
	resp, err := http.Post(eventURLMap[CO_SET_GLOBAL_VAR_URL], "application/json", bytes.NewReader(reqBodyBytes))

	if err != nil {
		log.Println("[component util]", "===>component send event:", CO_SET_GLOBAL_VAR_URL, " to:", eventURLMap[CO_SET_GLOBAL_VAR_URL], " \t error, error is:", err.Error())
		return errors.New("error when send req to workflow")
	}

	respBody, _ := ioutil.ReadAll(resp.Body)

	log.Println("[component util]", "===>component send event:", CO_SET_GLOBAL_VAR_URL, " got resp:\n", string(respBody), "\n")
	return nil
}

func LinkStart(workflowName, workflowVersion string, startJson map[string]interface{}) error {
	reqBody := make(map[string]interface{})

	startJsonBytes, _ := json.Marshal(startJson)

	reqBody["RUN_ID"] = eventINFOMap[CO_RUN_ID]
	reqBody["linkInfoMap"] = map[string]interface{}{"token": eventINFOMap[CO_LINKSTART_TOKEN], "workflowName": workflowName, "workflowVersion": workflowVersion, "startJson": string(startJsonBytes)}

	reqBodyBytes, _ := json.Marshal(reqBody)

	log.Println("[component util]", "===>component start link start, \ntoken:", eventINFOMap[CO_LINKSTART_TOKEN], "\nworkflow:", workflowName, ":", workflowVersion, "\nstartjson:", startJson, "\nbody:", string(reqBodyBytes), "\nto:", eventURLMap[CO_LINKSTART_URL]+workflowName)
	resp, err := http.Post(eventURLMap[CO_LINKSTART_URL]+workflowName, "application/json", bytes.NewReader(reqBodyBytes))
	if err != nil {
		log.Println("[component util]", "===>component send event:", CO_LINKSTART_URL, " to:", eventURLMap[CO_LINKSTART_URL]+workflowName, " \t error, error is:", err.Error())
		return errors.New("error when send req to workflow")
	}

	respBody, _ := ioutil.ReadAll(resp.Body)

	log.Println("[component util]", "===>component send event:", CO_LINKSTART_URL, " got resp:\n", string(respBody), "\n")
	return nil
}

func waitData(port int64) {
	if isWaitData {
		return
	}
	isWaitData = true

	http.HandleFunc("/receivedata", receiveDataHandler)
	http.ListenAndServe(":"+strconv.FormatInt(port, 10), nil)
}

func receiveDataHandler(w http.ResponseWriter, r *http.Request) {
	result, _ := json.Marshal(map[string]string{"message": "ok"})

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println("error when get data body:" + err.Error())
	}

	codePathMap := make(map[string]interface{})
	json.Unmarshal([]byte(body), &codePathMap)
	receiveDataChan <- codePathMap

	w.Write(result)
}
<|endoftext|>