<commit_before>package hdf5

// #include <stdlib.h>
// #include <string.h>
// #include <hdf5.h>
import "C"

import (
	"errors"
	"reflect"
	"unsafe"
)

// Get reads data from the file.
func (f *File) Get(name string, something interface{}) error {
	value := reflect.ValueOf(something)
	if value.Kind() != reflect.Ptr {
		return errors.New("expected a pointer")
	}

	value = reflect.Indirect(value)

	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	did := C.H5Dopen2(f.fid, cname, C.H5P_DEFAULT)
	if did < 0 {
		return errors.New("cannot find the dataset")
	}
	defer C.H5Dclose(did)

	object := newObject()
	defer object.free()

	object.tid = C.H5Dget_type(did)
	if object.tid < 0 {
		return errors.New("cannot get the datatype of the dataset")
	}

	if err := initializeToGet(object, value); err != nil {
		return err
	}

	if C.H5Dread(did, object.tid, C.H5S_ALL, C.H5S_ALL, C.H5P_DEFAULT, object.data) < 0 {
		return errors.New("cannot read the dataset from the file")
	}

	if err := finalizeToGet(object, value); err != nil {
		return err
	}

	one := C.hsize_t(1)
	sid := C.H5Screate_simple(1, (*C.hsize_t)(unsafe.Pointer(&one)), nil)
	if sid < 0 {
		return errors.New("cannot create a data space")
	}
	defer C.H5Sclose(sid)

	if C.H5Dvlen_reclaim(object.tid, sid, C.H5P_DEFAULT, object.data) < 0 {
		return errors.New("cannot reclaim memory")
	}

	return nil
}

func initializeToGet(object *object, value reflect.Value) error {
	switch value.Kind() {
	case reflect.Slice:
		return initializeSliceToGet(object, value)
	case reflect.Struct:
		return initializeStructToGet(object, value)
	default:
		return initializeScalarToGet(object, value)
	}
}

func finalizeToGet(object *object, value reflect.Value) error {
	switch value.Kind() {
	case reflect.Struct:
		return finalizeStructToGet(object, value)
	default:
		return nil
	}
}

func initializeScalarToGet(object *object, value reflect.Value) error {
	bid, ok := kindTypeMapping[value.Kind()]
	if !ok {
		return errors.New("encountered an unsupported datatype")
	}

	if err := checkArrayType(object.tid, bid); err != nil {
		return err
	}

	if length, err := computeArrayLength(object.tid); err != nil {
		return err
	} else if length != 1 {
		return errors.New("expected an array with a single element")
	}

	object.data = unsafe.Pointer(value.Addr().Pointer())

	return nil
}

func initializeSliceToGet(object *object, value reflect.Value) error {
	typo := value.Type()

	bid, ok := kindTypeMapping[typo.Elem().Kind()]
	if !ok {
		return errors.New("encountered an unsupported datatype")
	}

	if err := checkArrayType(object.tid, bid); err != nil {
		return err
	}

	length, err := computeArrayLength(object.tid)
	if err != nil {
		return err
	}

	buffer := reflect.MakeSlice(typo, int(length), int(length))
	shadow := reflect.Indirect(reflect.New(typo))
	shadow.Set(buffer)

	src := (*reflect.SliceHeader)(unsafe.Pointer(shadow.UnsafeAddr()))
	dst := (*reflect.SliceHeader)(unsafe.Pointer(value.UnsafeAddr()))

	dst.Data, src.Data = src.Data, dst.Data
	dst.Cap, src.Cap = src.Cap, dst.Cap
	dst.Len, src.Len = src.Len, dst.Len

	object.data = unsafe.Pointer(dst.Data)
	object.flag |= flagVariableLength

	return nil
}

func initializeStructToGet(object *object, value reflect.Value) error {
	if tid := C.H5Tget_class(object.tid); tid < 0 {
		return errors.New("cannot get a data class")
	} else if tid != C.H5T_COMPOUND {
		return errors.New("expected a compound datatype")
	}

	size := C.H5Tget_size(object.tid)
	if size < 0 {
		return errors.New("cannot get the size of a compound datatype")
	}

	object.data = C.malloc(size)
	if object.data == nil {
		return errors.New("cannot allocate memory")
	}
	object.flag |= flagOwnedMemory

	return nil
}

func finalizeStructToGet(object *object, value reflect.Value) error {
	typo := value.Type()
	count := typo.NumField()

	for i := 0; i < count; i++ {
		field := typo.Field(i)
		if len(field.PkgPath) > 0 {
			continue
		}

		cname := C.CString(field.Name)
		defer C.free(unsafe.Pointer(cname))

		j := C.H5Tget_member_index(object.tid, cname)
		if j < 0 {
			continue
		}

		o := object.new()

		o.tid = C.H5Tget_member_type(object.tid, C.uint(j))
		if o.tid < 0 {
			return errors.New("cannot get the datatype of a field")
		}

		if cid := C.H5Tget_class(o.tid); cid < 0 {
			return errors.New("cannot get the data class of a field")
		} else if cid == C.H5T_VLEN {
			if tid := C.H5Tget_super(o.tid); tid < 0 { // Close?
				return errors.New("cannot get the base type of a field")
			} else {
				o = object.new()
				o.tid = tid
			}
		}

		if err := initializeToGet(o, value.Field(i)); err != nil {
			return err
		}

		size := C.H5Tget_size(o.tid)
		if size < 0 {
			return errors.New("cannot get a size")
		}

		offset := C.H5Tget_member_offset(object.tid, C.uint(j))
		address := unsafe.Pointer(uintptr(object.data) + uintptr(offset))

		if o.flag&flagVariableLength != 0 {
			h := (*C.hvl_t)(address)
			if h.len != 1 {
				return errors.New("expected a variable-length datatype with a single element")
			}
			address = h.p
		}

		C.memcpy(o.data, address, size)

		if err := finalizeToGet(o, value.Field(i)); err != nil {
			return err
		}
	}

	return nil
}

func checkArrayType(tid C.hid_t, bid C.hid_t) error {
	if cid := C.H5Tget_class(tid); cid < 0 {
		return errors.New("cannot get a data class")
	} else if cid != C.H5T_ARRAY {
		return errors.New("expected an array datatype")
	}

	if tid := C.H5Tget_super(tid); tid < 0 { // Close?
		return errors.New("cannot get the base type of a datatype")
	} else if C.H5Tequal(bid, tid) == 0 {
		return errors.New("the types do not match")
	}

	return nil
}

func computeArrayLength(tid C.hid_t) (C.hsize_t, error) {
	nd := C.H5Tget_array_ndims(tid)
	if nd < 0 {
		return 0, errors.New("cannot get the dimensionality of an array")
	}

	dimensions := make([]C.hsize_t, nd)
	if C.H5Tget_array_dims2(tid, (*C.hsize_t)(unsafe.Pointer(&dimensions[0]))) != nd {
		return 0, errors.New("cannot get the dimensions of an array")
	}

	length := C.hsize_t(1)
	for i := range dimensions {
		length *= dimensions[i]
	}

	return length, nil
}
<commit_msg>Account for the new Go/Cgo rules<commit_after>package hdf5

// #include <stdlib.h>
// #include <string.h>
// #include <hdf5.h>
import "C"

import (
	"errors"
	"reflect"
	"unsafe"
)

// Get reads data from the file.
func (f *File) Get(name string, something interface{}) error {
	value := reflect.ValueOf(something)
	if value.Kind() != reflect.Ptr {
		return errors.New("expected a pointer")
	}

	value = reflect.Indirect(value)

	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	did := C.H5Dopen2(f.fid, cname, C.H5P_DEFAULT)
	if did < 0 {
		return errors.New("cannot find the dataset")
	}
	defer C.H5Dclose(did)

	object := newObject()
	defer object.free()

	object.tid = C.H5Dget_type(did)
	if object.tid < 0 {
		return errors.New("cannot get the datatype of the dataset")
	}

	if err := initializeToGet(object, value); err != nil {
		return err
	}

	if C.H5Dread(did, object.tid, C.H5S_ALL, C.H5S_ALL, C.H5P_DEFAULT, object.data) < 0 {
		return errors.New("cannot read the dataset from the file")
	}

	if err := finalizeToGet(object, value); err != nil {
		return err
	}

	one := C.hsize_t(1)
	sid := C.H5Screate_simple(1, (*C.hsize_t)(unsafe.Pointer(&one)), nil)
	if sid < 0 {
		return errors.New("cannot create a data space")
	}
	defer C.H5Sclose(sid)

	if C.H5Dvlen_reclaim(object.tid, sid, C.H5P_DEFAULT, object.data) < 0 {
		return errors.New("cannot reclaim memory")
	}

	return nil
}

func initializeToGet(object *object, value reflect.Value) error {
	switch value.Kind() {
	case reflect.Slice:
		return initializeSliceToGet(object, value)
	case reflect.Struct:
		return initializeStructToGet(object, value)
	default:
		return initializeScalarToGet(object, value)
	}
}

func finalizeToGet(object *object, value reflect.Value) error {
	switch value.Kind() {
	case reflect.Struct:
		return finalizeStructToGet(object, value)
	default:
		return nil
	}
}

func initializeScalarToGet(object *object, value reflect.Value) error {
	bid, ok := kindTypeMapping[value.Kind()]
	if !ok {
		return errors.New("encountered an unsupported datatype")
	}

	if err := checkArrayType(object.tid, bid); err != nil {
		return err
	}

	if length, err := computeArrayLength(object.tid); err != nil {
		return err
	} else if length != 1 {
		return errors.New("expected an array with a single element")
	}

	object.data = unsafe.Pointer(value.Addr().Pointer())

	return nil
}

func initializeSliceToGet(object *object, value reflect.Value) error {
	typo := value.Type()

	bid, ok := kindTypeMapping[typo.Elem().Kind()]
	if !ok {
		return errors.New("encountered an unsupported datatype")
	}

	if err := checkArrayType(object.tid, bid); err != nil {
		return err
	}

	length, err := computeArrayLength(object.tid)
	if err != nil {
		return err
	}

	buffer := reflect.MakeSlice(typo, int(length), int(length))
	shadow := reflect.Indirect(reflect.New(typo))
	shadow.Set(buffer)

	src := (*reflect.SliceHeader)(unsafe.Pointer(shadow.UnsafeAddr()))
	dst := (*reflect.SliceHeader)(unsafe.Pointer(value.UnsafeAddr()))

	dst.Data, src.Data = src.Data, dst.Data
	dst.Cap, src.Cap = src.Cap, dst.Cap
	dst.Len, src.Len = src.Len, dst.Len

	object.data = unsafe.Pointer(dst.Data)
	object.flag |= flagVariableLength

	return nil
}

func initializeStructToGet(object *object, value reflect.Value) error {
	if tid := C.H5Tget_class(object.tid); tid < 0 {
		return errors.New("cannot get a data class")
	} else if tid != C.H5T_COMPOUND {
		return errors.New("expected a compound datatype")
	}

	size := C.H5Tget_size(object.tid)
	if size < 0 {
		return errors.New("cannot get the size of a compound datatype")
	}

	object.data = C.malloc(size)
	if object.data == nil {
		return errors.New("cannot allocate memory")
	}
	object.flag |= flagOwnedMemory

	return nil
}

func finalizeStructToGet(object *object, value reflect.Value) error {
	typo := value.Type()
	count := typo.NumField()

	for i := 0; i < count; i++ {
		field := typo.Field(i)
		if len(field.PkgPath) > 0 {
			continue
		}

		cname := C.CString(field.Name)
		defer C.free(unsafe.Pointer(cname))

		j := C.H5Tget_member_index(object.tid, cname)
		if j < 0 {
			continue
		}

		o := object.new()

		o.tid = C.H5Tget_member_type(object.tid, C.uint(j))
		if o.tid < 0 {
			return errors.New("cannot get the datatype of a field")
		}

		if cid := C.H5Tget_class(o.tid); cid < 0 {
			return errors.New("cannot get the data class of a field")
		} else if cid == C.H5T_VLEN {
			if tid := C.H5Tget_super(o.tid); tid < 0 { // Close?
				return errors.New("cannot get the base type of a field")
			} else {
				o = object.new()
				o.tid = tid
			}
		}

		if err := initializeToGet(o, value.Field(i)); err != nil {
			return err
		}

		size := C.H5Tget_size(o.tid)
		if size < 0 {
			return errors.New("cannot get a size")
		}

		offset := C.H5Tget_member_offset(object.tid, C.uint(j))
		address := unsafe.Pointer(uintptr(object.data) + uintptr(offset))

		if o.flag&flagVariableLength != 0 {
			h := (*C.hvl_t)(address)
			if h.len != 1 {
				return errors.New("expected a variable-length datatype with a single element")
			}
			address = h.p
		}

		copyMemory(uintptr(o.data), uintptr(address), int(size))

		if err := finalizeToGet(o, value.Field(i)); err != nil {
			return err
		}
	}

	return nil
}

func checkArrayType(tid C.hid_t, bid C.hid_t) error {
	if cid := C.H5Tget_class(tid); cid < 0 {
		return errors.New("cannot get a data class")
	} else if cid != C.H5T_ARRAY {
		return errors.New("expected an array datatype")
	}

	if tid := C.H5Tget_super(tid); tid < 0 { // Close?
		return errors.New("cannot get the base type of a datatype")
	} else if C.H5Tequal(bid, tid) == 0 {
		return errors.New("the types do not match")
	}

	return nil
}

func computeArrayLength(tid C.hid_t) (C.hsize_t, error) {
	nd := C.H5Tget_array_ndims(tid)
	if nd < 0 {
		return 0, errors.New("cannot get the dimensionality of an array")
	}

	dimensions := make([]C.hsize_t, nd)
	if C.H5Tget_array_dims2(tid, (*C.hsize_t)(unsafe.Pointer(&dimensions[0]))) != nd {
		return 0, errors.New("cannot get the dimensions of an array")
	}

	length := C.hsize_t(1)
	for i := range dimensions {
		length *= dimensions[i]
	}

	return length, nil
}

func copyMemory(into, from uintptr, size int) {
	intoHeader := reflect.SliceHeader{
		Data: into,
		Len:  size,
		Cap:  size,
	}
	fromHeader := reflect.SliceHeader{
		Data: from,
		Len:  size,
		Cap:  size,
	}
	copy(*(*[]byte)(unsafe.Pointer(&intoHeader)), *(*[]byte)(unsafe.Pointer(&fromHeader)))
}
<|endoftext|>


<commit_before>package nmea

const (
	// TypeGGA type for GGA sentences
	TypeGGA = "GGA"
	// Invalid fix quality.
	Invalid = "0"
	// GPS fix quality
	GPS = "1"
	// DGPS fix quality
	DGPS = "2"
	// PPS fix
	PPS = "3"
	// RTK real time kinematic fix
	RTK = "4"
	// FRTK float RTK fix
	FRTK = "5"
)

// GGA is the Time, position, and fix related data of the receiver.
type GGA struct {
	BaseSentence
	Time          Time    // Time of fix.
	Latitude      float64 // Latitude.
	Longitude     float64 // Longitude.
	FixQuality    string  // Quality of fix.
	NumSatellites int64   // Number of satellites in use.
	HDOP          float64 // Horizontal dilution of precision.
	Altitude      float64 // Altitude.
	Separation    float64 // Geoidal separation
	DGPSAge       string  // Age of differential GPD data.
	DGPSId        string  // DGPS reference station ID.
}

// newGGA constructor
func newGGA(s BaseSentence) (GGA, error) {
	p := newParser(s)
	p.AssertType(TypeGGA)
	return GGA{
		BaseSentence:  s,
		Time:          p.Time(0, "time"),
		Latitude:      p.LatLong(1, 2, "latitude"),
		Longitude:     p.LatLong(3, 4, "longitude"),
		FixQuality:    p.EnumString(5, "fix quality", Invalid, GPS, DGPS, PPS, RTK, FRTK),
		NumSatellites: p.Int64(6, "number of satellites"),
		HDOP:          p.Float64(7, "hdop"),
		Altitude:      p.Float64(8, "altitude"),
		Separation:    p.Float64(10, "separation"),
		DGPSAge:       p.String(12, "dgps age"),
		DGPSId:        p.String(13, "dgps id"),
	}, p.Err()
}
<commit_msg>added estimated fix which is returned by MTK3339<commit_after>package nmea

const (
	// TypeGGA type for GGA sentences
	TypeGGA = "GGA"
	// Invalid fix quality.
	Invalid = "0"
	// GPS fix quality
	GPS = "1"
	// DGPS fix quality
	DGPS = "2"
	// PPS fix
	PPS = "3"
	// RTK real time kinematic fix
	RTK = "4"
	// FRTK float RTK fix
	FRTK = "5"
	// EST estimated fix.
	EST = "6"
)

// GGA is the Time, position, and fix related data of the receiver.
type GGA struct {
	BaseSentence
	Time          Time    // Time of fix.
	Latitude      float64 // Latitude.
	Longitude     float64 // Longitude.
	FixQuality    string  // Quality of fix.
	NumSatellites int64   // Number of satellites in use.
	HDOP          float64 // Horizontal dilution of precision.
	Altitude      float64 // Altitude.
	Separation    float64 // Geoidal separation
	DGPSAge       string  // Age of differential GPD data.
	DGPSId        string  // DGPS reference station ID.
}

// newGGA constructor
func newGGA(s BaseSentence) (GGA, error) {
	p := newParser(s)
	p.AssertType(TypeGGA)
	return GGA{
		BaseSentence:  s,
		Time:          p.Time(0, "time"),
		Latitude:      p.LatLong(1, 2, "latitude"),
		Longitude:     p.LatLong(3, 4, "longitude"),
		FixQuality:    p.EnumString(5, "fix quality", Invalid, GPS, DGPS, PPS, RTK, FRTK, EST),
		NumSatellites: p.Int64(6, "number of satellites"),
		HDOP:          p.Float64(7, "hdop"),
		Altitude:      p.Float64(8, "altitude"),
		Separation:    p.Float64(10, "separation"),
		DGPSAge:       p.String(12, "dgps age"),
		DGPSId:        p.String(13, "dgps id"),
	}, p.Err()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"net/url"
	"os"
	"os/exec"
	"sort"
	"strings"
	"syscall"
)

func host() string {
	if host := os.Getenv("HEROKU_HOST"); host != "" {
		return host
	}
	return "heroku.com"
}

func apiHost() string {
	h := host()
	if strings.HasPrefix(h, "http") {
		u, err := url.Parse(h)
		if err != nil {
			Errln(err)
		} else {
			return u.Host
		}
	}
	return "api." + host()
}

func apiURL() string {
	h := host()
	if strings.HasPrefix(h, "http") {
		return h
	}
	return "https://api." + h
}

func gitHost() string {
	if host := os.Getenv("HEROKU_GIT_HOST"); host != "" {
		return host
	}
	h := host()
	if strings.HasPrefix(h, "http") {
		u, err := url.Parse(h)
		if err != nil {
			Errln(err)
		} else {
			return u.Host
		}
	}
	return h
}

func httpGitHost() string {
	if host := os.Getenv("HEROKU_HTTP_GIT_HOST"); host != "" {
		return host
	}
	h := host()
	if strings.HasPrefix(h, "http") {
		u, err := url.Parse(h)
		if err != nil {
			Errln(err)
		} else {
			return u.Host
		}
	}
	return "git." + host()
}

func gitURLPre() string {
	return "git@" + gitHost() + ":"
}

func gitAltURLPre() string {
	return "ssh://git@" + gitHost() + "/"
}

func gitHTTPSURLPre() string {
	return "https://" + httpGitHost() + "/"
}

func gitRemotes() (map[string]string, error) {
	b, err := exec.Command("git", "remote", "-v").CombinedOutput()
	if err != nil {
		return nil, errors.New(string(b))
	}

	return parseGitRemoteOutput(b)
}

func appNameFromGitURL(remote string) string {
	switch {
	case strings.HasPrefix(remote, gitHTTPSURLPre()) && strings.HasSuffix(remote, ".git"):
		return remote[len(gitHTTPSURLPre()) : len(remote)-len(".git")]
	case strings.HasPrefix(remote, gitURLPre()) && strings.HasSuffix(remote, ".git"):
		return remote[len(gitURLPre()) : len(remote)-len(".git")]
	case strings.HasPrefix(remote, gitAltURLPre()) && strings.HasSuffix(remote, ".git"):
		return remote[len(gitAltURLPre()) : len(remote)-len(".git")]
	default:
		return ""
	}
}

func parseGitRemoteOutput(b []byte) (results map[string]string, err error) {
	s := bufio.NewScanner(bytes.NewBuffer(b))
	s.Split(bufio.ScanLines)

	results = make(map[string]string)

	for s.Scan() {
		by := s.Bytes()
		f := bytes.Fields(by)
		if len(f) != 3 || string(f[2]) != "(push)" {
			// this should have 3 tuples + be a push remote, skip it if not
			continue
		}

		if appName := appNameFromGitURL(string(f[1])); appName != "" {
			results[string(f[0])] = appName
		}
	}
	if err = s.Err(); err != nil {
		return nil, err
	}
	return
}

func remoteFromGitConfig() string {
	b, err := exec.Command("git", "config", "heroku.remote").Output()
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(b))
}

func errMultipleHerokuRemotes(remotes []string) error {
	sort.Strings(remotes)
	cmd := "heroku " + strings.Join(os.Args[1:], " ")
	remote := remotes[0]
	if remote == "heroku" {
		// easier to understand the concept of --remote when
		// not using the `heroku` remote
		remote = remotes[1]
	}
	app, _ := appFromGitRemote(remote)
	return fmt.Errorf(`Error: Multiple apps in git remotes
Usage: %s
   or: %s

Your local git repository has more than 1 app referenced in git remotes.
Because of this, we can't determine which app you want to run this command against.
Specify the app you want with %s or %s.

Heroku remotes in repo:
%s

https://devcenter.heroku.com/articles/multiple-environments`,
		cyan(cmd+" --remote "+remote),
		cyan(cmd+" --app "+app),
		cyan("--app"),
		cyan("--remote"),
		remoteList(remotes),
	)
}

func remoteList(remotes []string) string {
	lines := make([]string, 0, len(remotes))
	for _, remote := range remotes {
		app, _ := appFromGitRemote(remote)
		lines = append(lines, fmt.Sprintf("%-25s (%s)", yellow(remote), green(app)))
	}
	return strings.Join(lines, "\n")
}

func appFromGitRemote(remote string) (string, error) {
	if remote != "" {
		b, err := exec.Command("git", "config", "remote."+remote+".url").Output()
		if err != nil {
			if isNotFound(err) {
				wdir, _ := os.Getwd()
				remotes, err := gitRemotes()
				if err != nil {
					return "", err
				}
				msg := fmt.Sprintf("could not find git remote %s in %s", remote, wdir)
				if len(remotes) != 0 {
					msg = fmt.Sprintf("%s\nremotes: %s", msg, strings.Join(mapKeys(remotes), " "))
				}
				return "", errors.New(msg)
			}
			return "", err
		}

		out := strings.TrimSpace(string(b))

		appName := appNameFromGitURL(out)
		if appName == "" {
			return "", fmt.Errorf("could not find app name in " + remote + " git remote")
		}
		return appName, nil
	}

	// no remote specified, see if there is a single Heroku app remote
	remotes, err := gitRemotes()
	if err != nil {
		return "", nil // hide this error
	}
	remoteValues := uniqueMapValues(remotes)
	if len(remoteValues) > 1 {
		return "", errMultipleHerokuRemotes(mapKeys(remotes))
	}
	for _, v := range remotes {
		return v, nil
	}
	return "", nil
}

func uniqueMapValues(m map[string]string) []string {
	n := make([]string, 0, len(m))
	ref := make(map[string]bool, len(m))
	for _, v := range m {
		if _, ok := ref[v]; !ok {
			ref[v] = true
			n = append(n, v)
		}
	}
	return n
}

func mapKeys(m map[string]string) []string {
	n := make([]string, 0, len(m))
	for k := range m {
		n = append(n, k)
	}
	return n
}

func isNotFound(err error) bool {
	if ee, ok := err.(*exec.ExitError); ok {
		if ws, ok := ee.ProcessState.Sys().(syscall.WaitStatus); ok {
			return ws.ExitStatus() == 1
		}
	}
	return false
}
<commit_msg>improve error message<commit_after>package main

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"net/url"
	"os"
	"os/exec"
	"sort"
	"strings"
	"syscall"
)

func host() string {
	if host := os.Getenv("HEROKU_HOST"); host != "" {
		return host
	}
	return "heroku.com"
}

func apiHost() string {
	h := host()
	if strings.HasPrefix(h, "http") {
		u, err := url.Parse(h)
		if err != nil {
			Errln(err)
		} else {
			return u.Host
		}
	}
	return "api." + host()
}

func apiURL() string {
	h := host()
	if strings.HasPrefix(h, "http") {
		return h
	}
	return "https://api." + h
}

func gitHost() string {
	if host := os.Getenv("HEROKU_GIT_HOST"); host != "" {
		return host
	}
	h := host()
	if strings.HasPrefix(h, "http") {
		u, err := url.Parse(h)
		if err != nil {
			Errln(err)
		} else {
			return u.Host
		}
	}
	return h
}

func httpGitHost() string {
	if host := os.Getenv("HEROKU_HTTP_GIT_HOST"); host != "" {
		return host
	}
	h := host()
	if strings.HasPrefix(h, "http") {
		u, err := url.Parse(h)
		if err != nil {
			Errln(err)
		} else {
			return u.Host
		}
	}
	return "git." + host()
}

func gitURLPre() string {
	return "git@" + gitHost() + ":"
}

func gitAltURLPre() string {
	return "ssh://git@" + gitHost() + "/"
}

func gitHTTPSURLPre() string {
	return "https://" + httpGitHost() + "/"
}

func gitRemotes() (map[string]string, error) {
	b, err := exec.Command("git", "remote", "-v").CombinedOutput()
	if err != nil {
		return nil, errors.New(string(b))
	}

	return parseGitRemoteOutput(b)
}

func appNameFromGitURL(remote string) string {
	switch {
	case strings.HasPrefix(remote, gitHTTPSURLPre()) && strings.HasSuffix(remote, ".git"):
		return remote[len(gitHTTPSURLPre()) : len(remote)-len(".git")]
	case strings.HasPrefix(remote, gitURLPre()) && strings.HasSuffix(remote, ".git"):
		return remote[len(gitURLPre()) : len(remote)-len(".git")]
	case strings.HasPrefix(remote, gitAltURLPre()) && strings.HasSuffix(remote, ".git"):
		return remote[len(gitAltURLPre()) : len(remote)-len(".git")]
	default:
		return ""
	}
}

func parseGitRemoteOutput(b []byte) (results map[string]string, err error) {
	s := bufio.NewScanner(bytes.NewBuffer(b))
	s.Split(bufio.ScanLines)

	results = make(map[string]string)

	for s.Scan() {
		by := s.Bytes()
		f := bytes.Fields(by)
		if len(f) != 3 || string(f[2]) != "(push)" {
			// this should have 3 tuples + be a push remote, skip it if not
			continue
		}

		if appName := appNameFromGitURL(string(f[1])); appName != "" {
			results[string(f[0])] = appName
		}
	}
	if err = s.Err(); err != nil {
		return nil, err
	}
	return
}

func remoteFromGitConfig() string {
	b, err := exec.Command("git", "config", "heroku.remote").Output()
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(b))
}

func errMultipleHerokuRemotes(remotes []string) error {
	sort.Strings(remotes)
	cmd := "heroku " + strings.Join(os.Args[1:], " ")
	remote := remotes[0]
	if remote == "heroku" {
		// easier to understand the concept of --remote when
		// not using the `heroku` remote
		remote = remotes[1]
	}
	app, _ := appFromGitRemote(remote)
	return fmt.Errorf(`Error: Multiple apps in git remotes
Usage: %s
   or: %s

Your local git repository has more than 1 app referenced in git remotes.
Because of this, we can't determine which app you want to run this command against.
Specify the app you want with %s or %s.

Heroku remotes in repo:
%s

https://devcenter.heroku.com/articles/multiple-environments`,
		cyan(cmd+" --remote "+remote),
		cyan(cmd+" --app "+app),
		cyan("--app"),
		cyan("--remote"),
		remoteList(remotes),
	)
}

func remoteList(remotes []string) string {
	lines := make([]string, 0, len(remotes))
	for _, remote := range remotes {
		app, _ := appFromGitRemote(remote)
		lines = append(lines, fmt.Sprintf("%-25s (%s)", yellow(remote), green(app)))
	}
	return strings.Join(lines, "\n")
}

func appFromGitRemote(remote string) (string, error) {
	if remote != "" {
		b, err := exec.Command("git", "config", "remote."+remote+".url").Output()
		if err != nil {
			if isNotFound(err) {
				wdir, _ := os.Getwd()
				remotes, err := gitRemotes()
				if err != nil {
					return "", err
				}
				msg := fmt.Sprintf("Error: Could not find git remote %s in %s", remote, wdir)
				if len(remotes) != 0 {
					msg = fmt.Sprintf("%s\nremotes: %s", msg, strings.Join(mapKeys(remotes), " "))
				}
				return "", errors.New(msg)
			}
			return "", err
		}

		out := strings.TrimSpace(string(b))

		appName := appNameFromGitURL(out)
		if appName == "" {
			return "", fmt.Errorf("could not find app name in " + remote + " git remote")
		}
		return appName, nil
	}

	// no remote specified, see if there is a single Heroku app remote
	remotes, err := gitRemotes()
	if err != nil {
		return "", nil // hide this error
	}
	remoteValues := uniqueMapValues(remotes)
	if len(remoteValues) > 1 {
		return "", errMultipleHerokuRemotes(mapKeys(remotes))
	}
	for _, v := range remotes {
		return v, nil
	}
	return "", nil
}

func uniqueMapValues(m map[string]string) []string {
	n := make([]string, 0, len(m))
	ref := make(map[string]bool, len(m))
	for _, v := range m {
		if _, ok := ref[v]; !ok {
			ref[v] = true
			n = append(n, v)
		}
	}
	return n
}

func mapKeys(m map[string]string) []string {
	n := make([]string, 0, len(m))
	for k := range m {
		n = append(n, k)
	}
	return n
}

func isNotFound(err error) bool {
	if ee, ok := err.(*exec.ExitError); ok {
		if ws, ok := ee.ProcessState.Sys().(syscall.WaitStatus); ok {
			return ws.ExitStatus() == 1
		}
	}
	return false
}
<|endoftext|>


<commit_before>package gmx

import (
	"encoding/json"
	"io"
	"log"
	"math"
	"net"
	"sync"
)

const GMX_VERSION = 0

var (
	r = &registry{
		entries: make(map[string]func() interface{}),
	}

	localsocket net.Listener
)

func init() {
	s, err := localSocket()
	if err != nil {
		log.Printf("gmx: unable to open local socket: %v", err)
		return
	}

	// register the registries keys for discovery
	Publish("keys", func() interface{} {
		return r.keys()
	})
	go serve(s, r)
	localsocket = s
}

// Publish registers the function f with the supplied key.
func Publish(key string, f func() interface{}) {
	r.register(key, f)
}

// Unpublish unregisters the key. If key is not currently registered it does nothing.
func Unpublish(key string) {
	r.unregister(key)
}

// Exit cleanly shuts down gmx.
// This is useful as a defer'ed function in main(), so the local gmx socket is cleaned up
func Exit() {
	if localsocket != nil {
		localsocket.Close()
		localsocket = nil
	}
}

func serve(l net.Listener, r *registry) {
	defer l.Close()
	for {
		c, err := l.Accept()
		if err != nil {
			return
		}
		go handle(c, r)
	}
}

func handle(nc net.Conn, reg *registry) {
	// conn makes it easier to send and receive json
	type conn struct {
		net.Conn
		*json.Encoder
		*json.Decoder
	}
	c := conn{
		nc,
		json.NewEncoder(nc),
		json.NewDecoder(nc),
	}
	c.SetEscapeHTML(false) // I hate that default
	defer c.Close()
	for {
		var keys []string
		if err := c.Decode(&keys); err != nil {
			if err != io.EOF {
				log.Printf("gmx: client %v sent invalid json request: %v", c.RemoteAddr(), err)
			}
			return
		}
		var result = make(map[string]interface{}, len(keys))
		for _, key := range keys {
			if f, ok := reg.value(key); ok {
				// invoke the function for key and store the result
				val := f()
				if val == nil {
					continue
				}
				switch v := val.(type) {
				case float64:
					if math.IsNaN(v) {
						continue
					}
				case float32:
					if math.IsNaN(float64(v)) {
						continue
					}
				}
				result[key] = val
			}
		}
		if err := c.Encode(result); err != nil {
			log.Printf("gmx: could not send response to client %v: %v", c.RemoteAddr(), err)
			return
		}
	}
}

type registry struct {
	sync.Mutex // protects entries from concurrent mutation
	entries    map[string]func() interface{}
}

func (r *registry) register(key string, f func() interface{}) {
	r.Lock()
	r.entries[key] = f
	r.Unlock()
}

func (r *registry) unregister(key string) {
	r.Lock()
	delete(r.entries, key)
	r.Unlock()
}

func (r *registry) value(key string) (func() interface{}, bool) {
	r.Lock()
	f, ok := r.entries[key]
	r.Unlock()
	return f, ok
}

func (r *registry) keys() []string {
	r.Lock()
	var k = make([]string, 0, len(r.entries))
	for e := range r.entries {
		k = append(k, e)
	}
	r.Unlock()
	return k
}
<commit_msg>Inf has to be treated the same as NaN<commit_after>package gmx

import (
	"encoding/json"
	"io"
	"log"
	"math"
	"net"
	"sync"
)

const GMX_VERSION = 0

var (
	r = &registry{
		entries: make(map[string]func() interface{}),
	}

	localsocket net.Listener
)

func init() {
	s, err := localSocket()
	if err != nil {
		log.Printf("gmx: unable to open local socket: %v", err)
		return
	}

	// register the registries keys for discovery
	Publish("keys", func() interface{} {
		return r.keys()
	})
	go serve(s, r)
	localsocket = s
}

// Publish registers the function f with the supplied key.
func Publish(key string, f func() interface{}) {
	r.register(key, f)
}

// Unpublish unregisters the key. If key is not currently registered it does nothing.
func Unpublish(key string) {
	r.unregister(key)
}

// Exit cleanly shuts down gmx.
// This is useful as a defer'ed function in main(), so the local gmx socket is cleaned up
func Exit() {
	if localsocket != nil {
		localsocket.Close()
		localsocket = nil
	}
}

func serve(l net.Listener, r *registry) {
	defer l.Close()
	for {
		c, err := l.Accept()
		if err != nil {
			return
		}
		go handle(c, r)
	}
}

func handle(nc net.Conn, reg *registry) {
	// conn makes it easier to send and receive json
	type conn struct {
		net.Conn
		*json.Encoder
		*json.Decoder
	}
	c := conn{
		nc,
		json.NewEncoder(nc),
		json.NewDecoder(nc),
	}
	c.SetEscapeHTML(false) // I hate that default
	defer c.Close()
	for {
		var keys []string
		if err := c.Decode(&keys); err != nil {
			if err != io.EOF {
				log.Printf("gmx: client %v sent invalid json request: %v", c.RemoteAddr(), err)
			}
			return
		}
		var result = make(map[string]interface{}, len(keys))
		for _, key := range keys {
			if f, ok := reg.value(key); ok {
				// invoke the function for key and store the result
				val := f()
				if val == nil {
					continue
				}
				switch v := val.(type) {
				case float64:
					if math.IsNaN(v) || math.IsInf(v, 0) {
						// JSON cannot encode NaN, nor Inf. We either skip this metric or
						// convert it to a string. For now I skip it to not cause num->string
						// surprises at the receiving side.
						continue
					}
				case float32:
					if math.IsNaN(float64(v)) || math.IsInf(float64(v), 0) {
						continue
					}
				}
				result[key] = val
			}
		}
		if err := c.Encode(result); err != nil {
			log.Printf("gmx: could not send response to client %v: %v", c.RemoteAddr(), err)
			return
		}
	}
}

type registry struct {
	sync.Mutex // protects entries from concurrent mutation
	entries    map[string]func() interface{}
}

func (r *registry) register(key string, f func() interface{}) {
	r.Lock()
	r.entries[key] = f
	r.Unlock()
}

func (r *registry) unregister(key string) {
	r.Lock()
	delete(r.entries, key)
	r.Unlock()
}

func (r *registry) value(key string) (func() interface{}, bool) {
	r.Lock()
	f, ok := r.entries[key]
	r.Unlock()
	return f, ok
}

func (r *registry) keys() []string {
	r.Lock()
	var k = make([]string, 0, len(r.entries))
	for e := range r.entries {
		k = append(k, e)
	}
	r.Unlock()
	return k
}
<|endoftext|>


<commit_before>// HID package to access Human Interface Devices.
// The platform specific parts of this package are heavily based on
// Signal 11 - HIDAPI. (https://github.com/signal11/hidapi)
package hid

// DeviceInfo provides general information about a device
type DeviceInfo struct {
	// Path contains a Platform-specific device path which is used to identify the device
	Path string
	// VendorId contains the USB Vendor ID of the device
	VendorId uint16
	// ProductId contains the USB Product ID of the device
	ProductId uint16
	// VersionNumber contains the Version / Release Number of the device
	VersionNumber uint16
	// Manufacturer of the USB device
	Manufacturer string
	// Product contains the product name of the device
	Product string

	InputReportLength   uint16
	OutputReportLength  uint16
	FeatureReportLength uint16
}

// Device interface for an opened HID USB device
type Device interface {
	// Close closes the device and release all keept resources.
	Close()
	// Write to the device
	Write([]byte) error
	// WriteFeature set a featurereport on the device.
	WriteFeature([]byte) error
}

// FindDevices iterates through all devices with a given vendor and product id
func FindDevices(vendor uint16, product uint16) <-chan *DeviceInfo {
	result := make(chan *DeviceInfo)
	go func() {
		for dev := range Devices() {
			if dev.VendorId == vendor && dev.ProductId == product {
				result <- dev
			}
		}
		close(result)
	}()
	return result
}
<commit_msg>added some comments, to be more precise<commit_after>// HID package to access Human Interface Devices.
// The platform specific parts of this package are heavily based on
// Signal 11 - HIDAPI. (https://github.com/signal11/hidapi)
package hid

// DeviceInfo provides general information about a device
type DeviceInfo struct {
	// Path contains a Platform-specific device path which is used to identify the device
	Path string
	// VendorId contains the USB Vendor ID of the device
	VendorId uint16
	// ProductId contains the USB Product ID of the device
	ProductId uint16
	// VersionNumber contains the Version / Release Number of the device
	VersionNumber uint16
	// Manufacturer of the USB device
	Manufacturer string
	// Product contains the product name of the device
	Product string

	InputReportLength   uint16
	OutputReportLength  uint16
	FeatureReportLength uint16
}

// Device interface for an opened HID USB device
type Device interface {
	// Close closes the device and release all keept resources.
	Close()
	// Write to the device
	// technically a HID report with type 'output' is written
	Write([]byte) error
	// Write to the device
	// technically a HID report with type 'feature' is written
	WriteFeature([]byte) error
}

// FindDevices iterates through all devices with a given vendor and product id
func FindDevices(vendor uint16, product uint16) <-chan *DeviceInfo {
	result := make(chan *DeviceInfo)
	go func() {
		for dev := range Devices() {
			if dev.VendorId == vendor && dev.ProductId == product {
				result <- dev
			}
		}
		close(result)
	}()
	return result
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"log"
	"net/http"

	"bufio"

	"fmt"
	"net"

	"github.com/gorilla/websocket"
	"github.com/jessevdk/go-flags"
	"github.com/mkevac/hmm/internal/browser"
)

var opts struct {
	Http string `long:"http" description:"Address on which to listen to" default:"localhost:0"`
}

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

func serveWs(w http.ResponseWriter, r *http.Request, input chan string) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	for line := range input {
		if err := conn.WriteJSON(line); err != nil {
			log.Println(err)
			return
		}
	}
}

func main() {
	flags.Parse(&opts)

	var r = bufio.NewReader(os.Stdin)

	output := make(chan string, 1024)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if err := indexHtmlTemplate.Execute(w, nil); err != nil {
			log.Print("Error while executing index.html template")
		}
	})
	http.HandleFunc("/main.js", func(w http.ResponseWriter, r *http.Request) {
		if err := mainJsTemplate.Execute(w, nil); err != nil {
			log.Print("Error while executing main.js template")
		}
	})
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		serveWs(w, r, output)
	})

	ln, err := net.Listen("tcp", opts.Http)
	if err != nil {
		log.Fatalf("Error while listening on '%s': %s", opts.Http, err)
	}

	log.Printf("Opening browser")

	if !browser.Open("http://" + ln.Addr().String()) {
		fmt.Fprintf(os.Stderr, "Hmm is listening on http://%s\n", ln.Addr().String())
	}

	go func() {
		if err := http.Serve(ln, nil); err != nil {
			log.Fatal("Error while serving http: ", err)
		}
	}()

	s := bufio.NewScanner(r)
	for s.Scan() {
		text := s.Text()
		fmt.Println(text)
		output <- text
	}
	if err := s.Err(); err != nil {
		log.Fatalf("Error while scanning file: %s", err)
	}
}
<commit_msg>do not exit when stdin closes or when file ends<commit_after>package main

import (
	"os"

	"log"
	"net/http"

	"bufio"

	"fmt"
	"net"

	"github.com/gorilla/websocket"
	"github.com/jessevdk/go-flags"
	"github.com/mkevac/hmm/internal/browser"
)

var opts struct {
	Http string `long:"http" description:"Address on which to listen to" default:"localhost:0"`
}

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

func serveWs(w http.ResponseWriter, r *http.Request, input chan string) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	for line := range input {
		if err := conn.WriteJSON(line); err != nil {
			log.Println(err)
			return
		}
	}
}

func main() {
	flags.Parse(&opts)

	var r = bufio.NewReader(os.Stdin)

	output := make(chan string, 1024)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if err := indexHtmlTemplate.Execute(w, nil); err != nil {
			log.Print("Error while executing index.html template")
		}
	})
	http.HandleFunc("/main.js", func(w http.ResponseWriter, r *http.Request) {
		if err := mainJsTemplate.Execute(w, nil); err != nil {
			log.Print("Error while executing main.js template")
		}
	})
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		serveWs(w, r, output)
	})

	ln, err := net.Listen("tcp", opts.Http)
	if err != nil {
		log.Fatalf("Error while listening on '%s': %s", opts.Http, err)
	}

	log.Printf("Opening browser")

	if !browser.Open("http://" + ln.Addr().String()) {
		fmt.Fprintf(os.Stderr, "Hmm is listening on http://%s\n", ln.Addr().String())
	}

	go func() {
		if err := http.Serve(ln, nil); err != nil {
			log.Fatal("Error while serving http: ", err)
		}
	}()

	s := bufio.NewScanner(r)
	for s.Scan() {
		text := s.Text()
		fmt.Println(text)
		output <- text
	}
	if err := s.Err(); err != nil {
		log.Fatalf("Error while scanning file: %s", err)
	}

	select {}
}
<|endoftext|>


<commit_before>package gopivo

import (
	"errors"
	"io"
	"net"
	"sync"
	"time"
)

const defaultJoinLimitRatePerSecond = 64
const defaultJoinLimitRateBurst = 32
const defaultJoinMaxQueueSize = 256

var (
	ErrJoinQueueIsFull  = errors.New("join queue is full")
	ErrNoSuchConnector  = errors.New("no such connector")
	ErrPortBufferIsFull = errors.New("port buffer is full")
)

type Connector interface {
	Error() error
	Initialize() (chan []byte, error)
	RemoteAddr() net.Addr

	Closer(error) error
	Receiver(io.ReadCloser) error
	Sender()
}

type Welcomer interface {
	Welcome() ([]byte, error)
}

type Hub struct {
	Name     string
	lock     *sync.Mutex
	ports    Port
	queue    chan chan bool
	throttle chan time.Time
}

type Port map[Connector]chan []byte

func NewHub(name string) *Hub {
	h := &Hub{
		Name:     name,
		lock:     &sync.Mutex{},
		ports:    make(Port),
		queue:    make(chan chan bool, defaultJoinMaxQueueSize),
		throttle: make(chan time.Time, defaultJoinLimitRateBurst),
	}
	go h.run()
	return h
}

func (h Hub) run() {
	go h.ticker(defaultJoinLimitRatePerSecond)
	for waiter := range h.queue {
		<-h.throttle
		waiter <- true
	}
}

func (h Hub) ticker(rate time.Duration) {
	for ns := range time.Tick(time.Second / rate) {
		h.throttle <- ns
	}
}

func (h Hub) waitQueue() error {
	waiter := make(chan bool)
	defer close(waiter)

	select {
	case h.queue <- waiter:
	default:
		return ErrJoinQueueIsFull
	}
	<-waiter
	return nil
}

func (h Hub) Broadcast() chan []byte {
	messages := make(chan []byte)
	go func() {
		defer close(messages)
		for msg := range messages {
			h.lock.Lock()
			for c, port := range h.ports {
				select {
				case port <- msg:
				default:
					err := ErrPortBufferIsFull
					go h.Leave(c, err)
				}
			}
			h.lock.Unlock()
		}
	}()
	return messages
}

func (h Hub) Join(c Connector, r io.ReadCloser, w Welcomer) error {
	if err := h.waitQueue(); err != nil {
		c.Closer(err)
		return err
	}

	port, err := c.Initialize()
	if err != nil {
		c.Closer(err)
		return err
	}

	go c.Sender()
	if w != nil {
		msg, err := w.Welcome()
		if err != nil {
			c.Closer(err)
			return err
		}
		port <- msg
	}

	h.lock.Lock()
	h.ports[c] = port
	h.lock.Unlock()
	go func() { h.Leave(c, c.Receiver(r)) }()
	return nil
}

func (h Hub) Leave(c Connector, reason error) error {
	h.lock.Lock()
	defer h.lock.Unlock()
	if _, ok := h.ports[c]; ok {
		delete(h.ports, c)
		return c.Closer(reason)
	}
	return ErrNoSuchConnector
}

/*
func (h Hub) Kill() (error, []error) {
	atomic.AddUint32(&h.state, 1)
	var errors []error
	for conn, _ := range h.ports {
		if err := conn.Closer(); err != nil {
			errors = append(errors, err)
		}
	}

	if len(errors) > 0 {
		return ErrHubKillWentBad, errors
	}
	return nil, nil
}
*/
<commit_msg>do not send empty welcome message<commit_after>package gopivo

import (
	"errors"
	"io"
	"net"
	"sync"
	"time"
)

const defaultJoinLimitRatePerSecond = 64
const defaultJoinLimitRateBurst = 32
const defaultJoinMaxQueueSize = 256

var (
	ErrJoinQueueIsFull  = errors.New("join queue is full")
	ErrNoSuchConnector  = errors.New("no such connector")
	ErrPortBufferIsFull = errors.New("port buffer is full")
)

type Connector interface {
	Error() error
	Initialize() (chan []byte, error)
	RemoteAddr() net.Addr

	Closer(error) error
	Receiver(io.ReadCloser) error
	Sender()
}

type Welcomer interface {
	Welcome() ([]byte, error)
}

type Hub struct {
	Name     string
	lock     *sync.Mutex
	ports    Port
	queue    chan chan bool
	throttle chan time.Time
}

type Port map[Connector]chan []byte

func NewHub(name string) *Hub {
	h := &Hub{
		Name:     name,
		lock:     &sync.Mutex{},
		ports:    make(Port),
		queue:    make(chan chan bool, defaultJoinMaxQueueSize),
		throttle: make(chan time.Time, defaultJoinLimitRateBurst),
	}
	go h.run()
	return h
}

func (h Hub) run() {
	go h.ticker(defaultJoinLimitRatePerSecond)
	for waiter := range h.queue {
		<-h.throttle
		waiter <- true
	}
}

func (h Hub) ticker(rate time.Duration) {
	for ns := range time.Tick(time.Second / rate) {
		h.throttle <- ns
	}
}

func (h Hub) waitQueue() error {
	waiter := make(chan bool)
	defer close(waiter)

	select {
	case h.queue <- waiter:
	default:
		return ErrJoinQueueIsFull
	}
	<-waiter
	return nil
}

func (h Hub) Broadcast() chan []byte {
	messages := make(chan []byte)
	go func() {
		defer close(messages)
		for msg := range messages {
			h.lock.Lock()
			for c, port := range h.ports {
				select {
				case port <- msg:
				default:
					err := ErrPortBufferIsFull
					go h.Leave(c, err)
				}
			}
			h.lock.Unlock()
		}
	}()
	return messages
}

func (h Hub) Join(c Connector, r io.ReadCloser, w Welcomer) error {
	if err := h.waitQueue(); err != nil {
		c.Closer(err)
		return err
	}

	port, err := c.Initialize()
	if err != nil {
		c.Closer(err)
		return err
	}

	go c.Sender()
	if w != nil {
		msg, err := w.Welcome()
		if err != nil {
			c.Closer(err)
			return err
		} else if len(msg) > 0 {
			port <- msg
		}
	}

	h.lock.Lock()
	h.ports[c] = port
	h.lock.Unlock()
	go func() { h.Leave(c, c.Receiver(r)) }()
	return nil
}

func (h Hub) Leave(c Connector, reason error) error {
	h.lock.Lock()
	defer h.lock.Unlock()
	if _, ok := h.ports[c]; ok {
		delete(h.ports, c)
		return c.Closer(reason)
	}
	return ErrNoSuchConnector
}

/*
func (h Hub) Kill() (error, []error) {
	atomic.AddUint32(&h.state, 1)
	var errors []error
	for conn, _ := range h.ports {
		if err := conn.Closer(); err != nil {
			errors = append(errors, err)
		}
	}

	if len(errors) > 0 {
		return ErrHubKillWentBad, errors
	}
	return nil, nil
}
*/
<|endoftext|>


<commit_before>package HalHandlers

import (
	"time"
	"math/rand"
	"strings"
	"github.com/djosephsen/hal"
)

type ikr struct{
}

func (h *ikr) Method() string {
	return hal.HEAR
}

func (h *ikr) Usage() string {
	return `*ikr* - listens for enthusiasm; responds automatically with validation`
}

func (h *ikr) Pattern() string {
	triggers:=[]string{
		"best.*ev(er|ar)",
		"so good",
		"they have the best",
		"awesome",
		"I love",
		"fantastic|wonderful|outstanding|magnificent|brilliant|genius|amazing|epic|nice!",
		"ZOMG|OMG|OMFG",
		"(so|pretty) great",
		"off the hook",
	}
	pat := "(?i)"+strings.Join(triggers,"|")
	return pat
}

func (h *ikr) Run(res *hal.Response) error {
   now:=time.Now()
	rand.Seed(int64(now.Unix()))
	replies := []string{
		"*I know right?!*",
		"*OMG* couldn't agree more",
		":+1:",
		"+1",
		":arrow_up: THAT",
		":arrow_up: you complete me :arrow_up:",
		"so true",
		"agreed.",
		"that's the fact jack",
		"YUUUUUUP",
		"that's what I'm talkin bout",
		"*IKR?!*",
		"singit",
		"^droppin the truth bombs :boom: :boom: :boom:",
		"#legit",
		"/me nodds emphatically in agreement",
		"for REALZ though",
		"FOR REALSIES",
		"it's like you *literally* just read my mind right now",
	}
	reply := replies[rand.Intn(len(replies)-1)]
	hal.Logger.Debug(" *** ikr:Sending response: %s", reply)
	res.Send(reply)
	return nil
}

// Ping exports
var IKR = &ikr{}
<commit_msg>make IKR fire less often<commit_after>package HalHandlers

import (
	"time"
	"math/rand"
	"strings"
	"github.com/djosephsen/hal"
)

type ikr struct{
}

func (h *ikr) Method() string {
	return hal.HEAR
}

func (h *ikr) Usage() string {
	return `*ikr* - listens for enthusiasm; responds automatically with validation`
}

func (h *ikr) Pattern() string {
	triggers:=[]string{
		"best.*ev(er|ar)",
		"so good",
		"they have the best",
		"awesome",
		"I love",
		"fantastic|wonderful|outstanding|magnificent|brilliant|genius|amazing|epic|nice!",
		"ZOMG|OMG|OMFG",
		"(so|pretty) great",
		"off the hook",
	}
	pat := "(?i)"+strings.Join(triggers,"|")
	return pat
}

func (h *ikr) Run(res *hal.Response) error {
   now:=time.Now()
	rand.Seed(int64(now.Unix()))
	//only fire half the time
 	if rand.Intn(100) >= 50{
		return nil
	}
		replies := []string{
			"*I know right?!*",
			"*OMG* couldn't agree more",
			":+1:",
			"+1",
			":arrow_up: THAT",
			":arrow_up: you complete me :arrow_up:",
			"so true",
			"agreed.",
			"that's the fact jack",
			"YUUUUUUP",
			"that's what I'm talkin bout",
			"*IKR?!*",
			"singit",
			"^droppin the truth bombs :boom: :boom: :boom:",
			"#legit",
			"/me nodds emphatically in agreement",
			"for REALZ though",
			"FOR REALSIES",
			"it's like you *literally* just read my mind right now",
	}

	reply := replies[rand.Intn(len(replies)-1)]
	hal.Logger.Debug(" *** ikr:Sending response: %s", reply)
	res.Send(reply)
	return nil
}

// Ping exports
var IKR = &ikr{}
<|endoftext|>


<commit_before>// Copyright 2014, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package itl defines data types for importing iTunes Library XML (plist) files.
package itl

import (
	"fmt"
	"io"
	"io/ioutil"
	"reflect"
	"time"

	"github.com/dhowden/plist"
)

// Library represents the root iTunes library entity which includes a map of tracks and slice of
// playlists.
type Library struct {
	MajorVersion        int `plist:"Major Version"`
	MinorVersion        int `plist:"Minor Version"`
	Date                time.Time
	ApplicationVersion  string `plist:"Application Version"`
	Features            int
	ShowContentRatings  bool   `plist:"Show Content Ratings"`
	MusicFolder         string `plist:"Music Folder"`
	LibraryPersistentID string `plist:"Library Persistent ID"`
	Tracks              map[string]Track
	Playlists           []Playlist
}

// Track retrieves the library track for the given id, or error if no such
// track exists.
func (l *Library) Track(id string) (t Track, err error) {
	t, ok := l.Tracks[id]
	if !ok {
		err = fmt.Errorf("no track with id: %v", id)
	}
	return
}

// Tracks retrieves a slice containing all of the tracks in the iTunes library
func (l *Library) AllTracks() []Track {
	result := make([]Track, 0, len(l.Tracks))
	for _, t := range l.Tracks {
		result = append(result, t)
	}
	return result
}

// Track represents an iTunes library track, which is a media file which can either be music or video.
// Items are identified in iTunes using the TrackID.
type Track struct {
	TrackID int `plist:"Track ID"`
	Name    string
	Artist  string

	Composer string
	Year     int
	Genre    string
	Kind     string
	Size     int

	BPM int

	TrackNumber int `plist:"Track Number"`
	TrackCount  int `plist:"Track Count"`
	DiscNumber  int `plist:"Disc Number"`
	DiscCount   int `plist:"Disc Count"`

	PartOfGaplessAlbum bool   `plist:"Part Of Gapless Album"`
	ContentRating      string `plist:"Content Rating"`

	Rating         int
	RatingComputed bool `plist:"Rating Computed"`
	Disabled       bool

	Album               string
	AlbumArtist         string `plist:"Album Artist"`
	AlbumRating         int    `plist:"Album Rating"`
	AlbumRatingComputed bool   `plist:"Album Rating Computed"`

	SortName        string `plist:"Sort Name"`
	SortArtist      string `plist:"Sort Artist"`
	SortAlbumArtist string `plist:"Sort Album Artist"`
	SortAlbum       string `plist:"Sort Album"`
	SortComposer    string `plist:"Sort Composer"`

	Clean  bool
	Series string

	TotalTime        int       `plist:"Total Time"`
	DateModified     time.Time `plist:"Date Modified"`
	DateAdded        time.Time `plist:"Date Added"`
	BitRate          int       `plist:"Bit Rate"`
	SampleRate       int       `plist:"Sample Rate"`
	VolumeAdjustment int       `plist:"Volume Adjustment"`
	Comments         string

	PlayCount   int       `plist:"Play Count"`
	PlayDate    int       `plist:"Play Date"`
	PlayDateUTC time.Time `plist:"Play Date UTC"`

	Protected bool
	Purchased bool

	SkipCount int       `plist:"Skip Count"`
	SkipDate  time.Time `plist:"Skip Date"`

	ArtworkCount int `plist:"Artwork Count"`

	Episode      string
	EpisodeOrder int  `plist:"Episode Order"`
	TVShow       bool `plist:"TV Show"`
	Season       int
	Podcast      bool
	ITunesU      bool `plist:"iTunesU"`
	Unplayed     bool

	PersistentID string `plist:"Persistent ID"`
	TrackType    string `plist:"Track Type"`
	Location     string
	FileType     int `plist:"File Type"`
	Movie        bool
	MusicVideo   bool `plist:"Music Video"`
	HD           bool
	HasVideo     bool `plist:"Has Video"`
	VideoHeight  int  `plist:"Video Height"`
	VideoWidth   int  `plist:"Video Width"`

	Grouping    string
	Compilation bool
	ReleaseDate time.Time `plist:"Release Date"`

	FileFolderCount    int `plist:"File Folder Count"`
	LibraryFolderCount int `plist:"Library Folder Count"`
}

func (t *Track) String() string {
	return t.Name
}

func (t Track) GetString(name string) string {
	tt := reflect.TypeOf(t)
	ft, ok := tt.FieldByName(name)
	if !ok {
		panic("invalid field")
	}
	if ft.Type.Kind() != reflect.String {
		panic("field is not a string")
	}

	v := reflect.ValueOf(t)
	f := v.FieldByName(name)
	return f.String()
}

func (t Track) GetInt(name string) int {
	tt := reflect.TypeOf(t)
	ft, ok := tt.FieldByName(name)
	if !ok {
		panic("invalid field")
	}
	if ft.Type.Kind() != reflect.Int {
		panic("field is not an int")
	}

	v := reflect.ValueOf(t)
	f := v.FieldByName(name)
	return int(f.Int())
}

// Playlist represents an iTunes playlist
type Playlist struct {
	Name                 string
	Master               bool
	PlaylistID           int    `plist:"Playlist ID"`
	PlaylistPersistentID string `plist:"Playlist Persistent ID"`
	Visible              bool
	AllItems             bool           `plist:"All Items"`
	PlaylistItems        []PlaylistItem `plist:"Playlist Items"`
}

// PlaylistItem represents an individual track in a an iTunes playlist
type PlaylistItem struct {
	TrackID int `plist:"Track ID"`
}

// ReadFromXML reads iTunes XML (plist) data from the underlying io.Reader
// and returns a Library struct.
func ReadFromXML(r io.Reader) (l Library, err error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return
	}
	err = plist.Unmarshal(b, &l)
	return
}
<commit_msg>Improve documentation.<commit_after>// Copyright 2014, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package itl defines data types for importing iTunes Library XML (plist) files.
package itl

import (
	"fmt"
	"io"
	"io/ioutil"
	"reflect"
	"time"

	"github.com/dhowden/plist"
)

// Library represents the root iTunes library entity which includes a map of tracks and slice of
// playlists.
type Library struct {
	MajorVersion        int `plist:"Major Version"`
	MinorVersion        int `plist:"Minor Version"`
	Date                time.Time
	ApplicationVersion  string `plist:"Application Version"`
	Features            int
	ShowContentRatings  bool   `plist:"Show Content Ratings"`
	MusicFolder         string `plist:"Music Folder"`
	LibraryPersistentID string `plist:"Library Persistent ID"`
	Tracks              map[string]Track
	Playlists           []Playlist
}

// Track retrieves the library track for the given id, or error if no such
// track exists.
func (l *Library) Track(id string) (t Track, err error) {
	t, ok := l.Tracks[id]
	if !ok {
		err = fmt.Errorf("no track with id: %v", id)
	}
	return
}

// Tracks retrieves a slice containing all of the tracks in the iTunes library
func (l *Library) AllTracks() []Track {
	result := make([]Track, 0, len(l.Tracks))
	for _, t := range l.Tracks {
		result = append(result, t)
	}
	return result
}

// Track represents an iTunes library track, which is a media file which can either be music or video.
// Items are identified in iTunes using the TrackID.
type Track struct {
	TrackID int `plist:"Track ID"`
	Name    string
	Artist  string

	Composer string
	Year     int
	Genre    string
	Kind     string
	Size     int

	BPM int

	TrackNumber int `plist:"Track Number"`
	TrackCount  int `plist:"Track Count"`
	DiscNumber  int `plist:"Disc Number"`
	DiscCount   int `plist:"Disc Count"`

	PartOfGaplessAlbum bool   `plist:"Part Of Gapless Album"`
	ContentRating      string `plist:"Content Rating"`

	Rating         int
	RatingComputed bool `plist:"Rating Computed"`
	Disabled       bool

	Album               string
	AlbumArtist         string `plist:"Album Artist"`
	AlbumRating         int    `plist:"Album Rating"`
	AlbumRatingComputed bool   `plist:"Album Rating Computed"`

	SortName        string `plist:"Sort Name"`
	SortArtist      string `plist:"Sort Artist"`
	SortAlbumArtist string `plist:"Sort Album Artist"`
	SortAlbum       string `plist:"Sort Album"`
	SortComposer    string `plist:"Sort Composer"`

	Clean  bool
	Series string

	TotalTime        int       `plist:"Total Time"`
	DateModified     time.Time `plist:"Date Modified"`
	DateAdded        time.Time `plist:"Date Added"`
	BitRate          int       `plist:"Bit Rate"`
	SampleRate       int       `plist:"Sample Rate"`
	VolumeAdjustment int       `plist:"Volume Adjustment"`
	Comments         string

	PlayCount   int       `plist:"Play Count"`
	PlayDate    int       `plist:"Play Date"`
	PlayDateUTC time.Time `plist:"Play Date UTC"`

	Protected bool
	Purchased bool

	SkipCount int       `plist:"Skip Count"`
	SkipDate  time.Time `plist:"Skip Date"`

	ArtworkCount int `plist:"Artwork Count"`

	Episode      string
	EpisodeOrder int  `plist:"Episode Order"`
	TVShow       bool `plist:"TV Show"`
	Season       int
	Podcast      bool
	ITunesU      bool `plist:"iTunesU"`
	Unplayed     bool

	PersistentID string `plist:"Persistent ID"`
	TrackType    string `plist:"Track Type"`
	Location     string
	FileType     int `plist:"File Type"`
	Movie        bool
	MusicVideo   bool `plist:"Music Video"`
	HD           bool
	HasVideo     bool `plist:"Has Video"`
	VideoHeight  int  `plist:"Video Height"`
	VideoWidth   int  `plist:"Video Width"`

	Grouping    string
	Compilation bool
	ReleaseDate time.Time `plist:"Release Date"`

	FileFolderCount    int `plist:"File Folder Count"`
	LibraryFolderCount int `plist:"Library Folder Count"`
}

// String returns a string representation of the Track.
func (t *Track) String() string {
	return t.Name
}

// GetString fetches the given string field in the Track, panics if field doesn't
// exist.
func (t Track) GetString(name string) string {
	tt := reflect.TypeOf(t)
	ft, ok := tt.FieldByName(name)
	if !ok {
		panic("invalid field")
	}
	if ft.Type.Kind() != reflect.String {
		panic("field is not a string")
	}

	v := reflect.ValueOf(t)
	f := v.FieldByName(name)
	return f.String()
}

// GetInt fetches the given int field in the Track, panics if field doesn't exist.
func (t Track) GetInt(name string) int {
	tt := reflect.TypeOf(t)
	ft, ok := tt.FieldByName(name)
	if !ok {
		panic("invalid field")
	}
	if ft.Type.Kind() != reflect.Int {
		panic("field is not an int")
	}

	v := reflect.ValueOf(t)
	f := v.FieldByName(name)
	return int(f.Int())
}

// Playlist represents an iTunes playlist.
type Playlist struct {
	Name                 string
	Master               bool
	PlaylistID           int    `plist:"Playlist ID"`
	PlaylistPersistentID string `plist:"Playlist Persistent ID"`
	Visible              bool
	AllItems             bool           `plist:"All Items"`
	PlaylistItems        []PlaylistItem `plist:"Playlist Items"`
}

// PlaylistItem represents an individual track in a an iTunes playlist.
type PlaylistItem struct {
	TrackID int `plist:"Track ID"`
}

// ReadFromXML reads iTunes XML (plist) data from the underlying io.Reader
// and returns a Library struct.
func ReadFromXML(r io.Reader) (l Library, err error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return
	}
	err = plist.Unmarshal(b, &l)
	return
}
<|endoftext|>


<commit_before>/**
 * 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 realis

import (
	"gen-go/apache/aurora"
	"strconv"
)

// Structure to collect all information pertaining to an Aurora job.
type Job struct {
	jobConfig *aurora.JobConfiguration
	numCpus   *aurora.Resource
	ramMb     *aurora.Resource
	diskMb    *aurora.Resource
	portCount int
}

// Create a Job object with everything initialized.
func NewJob() *Job {
	jobConfig := aurora.NewJobConfiguration()
	taskConfig := aurora.NewTaskConfig()
	jobKey := aurora.NewJobKey()

	//Job Config
	jobConfig.Key = jobKey
	jobConfig.TaskConfig = taskConfig

	//Task Config
	taskConfig.Job = jobKey
	taskConfig.Container = aurora.NewContainer()
	taskConfig.Container.Mesos = aurora.NewMesosContainer()
	taskConfig.ExecutorConfig = aurora.NewExecutorConfig()
	taskConfig.MesosFetcherUris = make(map[*aurora.MesosFetcherURI]bool)
	taskConfig.Metadata = make(map[*aurora.Metadata]bool)
	taskConfig.Constraints = make(map[*aurora.Constraint]bool)

	//Resources
	numCpus := aurora.NewResource()
	ramMb := aurora.NewResource()
	diskMb := aurora.NewResource()

	taskConfig.Resources = make(map[*aurora.Resource]bool)
	taskConfig.Resources[numCpus] = true
	taskConfig.Resources[ramMb] = true
	taskConfig.Resources[diskMb] = true

	return &Job{jobConfig, numCpus, ramMb, diskMb, 0}
}

// Set Job Key environment.
func (a *Job) Environment(env string) *Job {
	a.jobConfig.Key.Environment = env
	return a
}

// Set Job Key Role.
func (a *Job) Role(role string) *Job {
	a.jobConfig.Key.Role = role

	//Will be deprecated
	identity := &aurora.Identity{role}
	a.jobConfig.Owner = identity
	a.jobConfig.TaskConfig.Owner = identity
	return a
}

// Set Job Key Name.
func (a *Job) Name(name string) *Job {
	a.jobConfig.Key.Name = name
	return a
}

// Set name of the executor that will the task will be configured to.
func (a *Job) ExecutorName(name string) *Job {
	a.jobConfig.TaskConfig.ExecutorConfig.Name = name
	return a
}

// Will be included as part of entire task inside the scheduler that will be serialized.
func (a *Job) ExecutorData(data string) *Job {
	a.jobConfig.TaskConfig.ExecutorConfig.Data = data
	return a
}

func (a *Job) CPU(cpus float64) *Job {
	a.numCpus.NumCpus = &cpus
	a.jobConfig.TaskConfig.NumCpus = cpus //Will be deprecated soon

	return a
}

func (a *Job) RAM(ram int64) *Job {
	a.ramMb.RamMb = &ram
	a.jobConfig.TaskConfig.RamMb = ram //Will be deprecated soon

	return a
}

func (a *Job) Disk(disk int64) *Job {
	a.diskMb.DiskMb = &disk
	a.jobConfig.TaskConfig.DiskMb = disk //Will be deprecated

	return a
}

// How many failures to tolerate before giving up.
func (a *Job) MaxFailure(maxFail int32) *Job {
	a.jobConfig.TaskConfig.MaxTaskFailures = maxFail
	return a
}

// How many instances of the job to run
func (a *Job) InstanceCount(instCount int32) *Job {
	a.jobConfig.InstanceCount = instCount
	return a
}

// Restart the job's tasks if they fail
func (a *Job) IsService(isService bool) *Job {
	a.jobConfig.TaskConfig.IsService = isService
	return a
}

// Get the current job configurations key to use for some realis calls.
func (a *Job) JobKey() *aurora.JobKey {
	return a.jobConfig.Key
}

// Add a list of URIs with the same extract and cache configuration. Scheduler must have
// --enable_mesos_fetcher flag enabled. Currently there is no duplicate detection.
func (a *Job) AddURIs(extract bool, cache bool, values ...string) *Job {
	for _, value := range values {
		a.jobConfig.
			TaskConfig.
			MesosFetcherUris[&aurora.MesosFetcherURI{value, &extract, &cache}] = true
	}
	return a
}

// Adds a Mesos label to the job. Note that Aurora will add the
// prefix "org.apache.aurora.metadata." to the beginning of each key.
func (a *Job) AddLabel(key string, value string) *Job {
	a.jobConfig.TaskConfig.Metadata[&aurora.Metadata{key, value}] = true
	return a
}

// Add a named port to the job configuration  These are random ports as it's
// not currently possible to request specific ports using Aurora.
func (a *Job) AddNamedPorts(names ...string) *Job {
	a.portCount += len(names)
	for _, name := range names {
		a.jobConfig.TaskConfig.Resources[&aurora.Resource{NamedPort: &name}] = true
	}

	return a
}

// Adds a request for a number of ports to the job configuration. The names chosen for these ports
// will be org.apache.aurora.portX, where X is the current port count for the job configuration
// starting at 0. These are random ports as it's not currently possible to request
// specific ports using Aurora.
func (a *Job) AddPorts(num int) *Job {
	start := a.portCount
	a.portCount += num
	for i := start; i < a.portCount; i++ {
		portName := "gorealis.port" + strconv.Itoa(i)
		a.jobConfig.TaskConfig.Resources[&aurora.Resource{NamedPort: &portName}] = true
	}

	return a
}

// From Aurora Docs:
// Add a Value constraint
// name - Mesos slave attribute that the constraint is matched against.
// If negated = true , treat this as a 'not' - to avoid specific values.
// Values - list of values we look for in attribute name
func (a *Job) AddValueConstraint(name string,
	negated bool,
	values ...string) *Job {

	constraintValues := make(map[string]bool)
	for _, value := range values {
		constraintValues[value] = true
	}
	a.jobConfig.TaskConfig.Constraints[&aurora.Constraint{name,
		&aurora.TaskConstraint{&aurora.ValueConstraint{negated, constraintValues}, nil}}] = true

	return a
}

// From Aurora Docs:
// A constraint that specifies the maximum number of active tasks on a host with
// a matching attribute that may be scheduled simultaneously.
func (a *Job) AddLimitConstraint(name string, limit int32) *Job {

	a.jobConfig.TaskConfig.Constraints[&aurora.Constraint{name,
		&aurora.TaskConstraint{nil, &aurora.LimitConstraint{limit}}}] = true

	return a
}
<commit_msg>Changing prefix of un-named ports<commit_after>/**
 * 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 realis

import (
	"gen-go/apache/aurora"
	"strconv"
)

// Structure to collect all information pertaining to an Aurora job.
type Job struct {
	jobConfig *aurora.JobConfiguration
	numCpus   *aurora.Resource
	ramMb     *aurora.Resource
	diskMb    *aurora.Resource
	portCount int
}

// Create a Job object with everything initialized.
func NewJob() *Job {
	jobConfig := aurora.NewJobConfiguration()
	taskConfig := aurora.NewTaskConfig()
	jobKey := aurora.NewJobKey()

	//Job Config
	jobConfig.Key = jobKey
	jobConfig.TaskConfig = taskConfig

	//Task Config
	taskConfig.Job = jobKey
	taskConfig.Container = aurora.NewContainer()
	taskConfig.Container.Mesos = aurora.NewMesosContainer()
	taskConfig.ExecutorConfig = aurora.NewExecutorConfig()
	taskConfig.MesosFetcherUris = make(map[*aurora.MesosFetcherURI]bool)
	taskConfig.Metadata = make(map[*aurora.Metadata]bool)
	taskConfig.Constraints = make(map[*aurora.Constraint]bool)

	//Resources
	numCpus := aurora.NewResource()
	ramMb := aurora.NewResource()
	diskMb := aurora.NewResource()

	taskConfig.Resources = make(map[*aurora.Resource]bool)
	taskConfig.Resources[numCpus] = true
	taskConfig.Resources[ramMb] = true
	taskConfig.Resources[diskMb] = true

	return &Job{jobConfig, numCpus, ramMb, diskMb, 0}
}

// Set Job Key environment.
func (a *Job) Environment(env string) *Job {
	a.jobConfig.Key.Environment = env
	return a
}

// Set Job Key Role.
func (a *Job) Role(role string) *Job {
	a.jobConfig.Key.Role = role

	//Will be deprecated
	identity := &aurora.Identity{role}
	a.jobConfig.Owner = identity
	a.jobConfig.TaskConfig.Owner = identity
	return a
}

// Set Job Key Name.
func (a *Job) Name(name string) *Job {
	a.jobConfig.Key.Name = name
	return a
}

// Set name of the executor that will the task will be configured to.
func (a *Job) ExecutorName(name string) *Job {
	a.jobConfig.TaskConfig.ExecutorConfig.Name = name
	return a
}

// Will be included as part of entire task inside the scheduler that will be serialized.
func (a *Job) ExecutorData(data string) *Job {
	a.jobConfig.TaskConfig.ExecutorConfig.Data = data
	return a
}

func (a *Job) CPU(cpus float64) *Job {
	a.numCpus.NumCpus = &cpus
	a.jobConfig.TaskConfig.NumCpus = cpus //Will be deprecated soon

	return a
}

func (a *Job) RAM(ram int64) *Job {
	a.ramMb.RamMb = &ram
	a.jobConfig.TaskConfig.RamMb = ram //Will be deprecated soon

	return a
}

func (a *Job) Disk(disk int64) *Job {
	a.diskMb.DiskMb = &disk
	a.jobConfig.TaskConfig.DiskMb = disk //Will be deprecated

	return a
}

// How many failures to tolerate before giving up.
func (a *Job) MaxFailure(maxFail int32) *Job {
	a.jobConfig.TaskConfig.MaxTaskFailures = maxFail
	return a
}

// How many instances of the job to run
func (a *Job) InstanceCount(instCount int32) *Job {
	a.jobConfig.InstanceCount = instCount
	return a
}

// Restart the job's tasks if they fail
func (a *Job) IsService(isService bool) *Job {
	a.jobConfig.TaskConfig.IsService = isService
	return a
}

// Get the current job configurations key to use for some realis calls.
func (a *Job) JobKey() *aurora.JobKey {
	return a.jobConfig.Key
}

// Add a list of URIs with the same extract and cache configuration. Scheduler must have
// --enable_mesos_fetcher flag enabled. Currently there is no duplicate detection.
func (a *Job) AddURIs(extract bool, cache bool, values ...string) *Job {
	for _, value := range values {
		a.jobConfig.
			TaskConfig.
			MesosFetcherUris[&aurora.MesosFetcherURI{value, &extract, &cache}] = true
	}
	return a
}

// Adds a Mesos label to the job. Note that Aurora will add the
// prefix "org.apache.aurora.metadata." to the beginning of each key.
func (a *Job) AddLabel(key string, value string) *Job {
	a.jobConfig.TaskConfig.Metadata[&aurora.Metadata{key, value}] = true
	return a
}

// Add a named port to the job configuration  These are random ports as it's
// not currently possible to request specific ports using Aurora.
func (a *Job) AddNamedPorts(names ...string) *Job {
	a.portCount += len(names)
	for _, name := range names {
		a.jobConfig.TaskConfig.Resources[&aurora.Resource{NamedPort: &name}] = true
	}

	return a
}

// Adds a request for a number of ports to the job configuration. The names chosen for these ports
// will be org.apache.aurora.port.X, where X is the current port count for the job configuration
// starting at 0. These are random ports as it's not currently possible to request
// specific ports using Aurora.
func (a *Job) AddPorts(num int) *Job {
	start := a.portCount
	a.portCount += num
	for i := start; i < a.portCount; i++ {
		portName := "org.apache.aurora.port." + strconv.Itoa(i)
		a.jobConfig.TaskConfig.Resources[&aurora.Resource{NamedPort: &portName}] = true
	}

	return a
}

// From Aurora Docs:
// Add a Value constraint
// name - Mesos slave attribute that the constraint is matched against.
// If negated = true , treat this as a 'not' - to avoid specific values.
// Values - list of values we look for in attribute name
func (a *Job) AddValueConstraint(name string,
	negated bool,
	values ...string) *Job {

	constraintValues := make(map[string]bool)
	for _, value := range values {
		constraintValues[value] = true
	}
	a.jobConfig.TaskConfig.Constraints[&aurora.Constraint{name,
		&aurora.TaskConstraint{&aurora.ValueConstraint{negated, constraintValues}, nil}}] = true

	return a
}

// From Aurora Docs:
// A constraint that specifies the maximum number of active tasks on a host with
// a matching attribute that may be scheduled simultaneously.
func (a *Job) AddLimitConstraint(name string, limit int32) *Job {

	a.jobConfig.TaskConfig.Constraints[&aurora.Constraint{name,
		&aurora.TaskConstraint{nil, &aurora.LimitConstraint{limit}}}] = true

	return a
}
<|endoftext|>


<commit_before>package lea

import "fmt"

const (
	ENCRYPT_MODE = iota
	DECRYPT_MODE
)

// LEA uses a 128-bit block
type word uint32

func (w word) String() string {
	return fmt.Sprintf("%08x", uint32(w))
}

func ba2w(ba [4]byte) word {
	return word(uint32(ba[3])<<24 |
		uint32(ba[2])<<16 |
		uint32(ba[1])<<8 |
		uint32(ba[0]))
}

func w2ba(w word) (ba [4]byte) {
	ba[0] = byte(w)
	ba[1] = byte(w >> 8)
	ba[2] = byte(w >> 16)
	ba[3] = byte(w >> 24)
	return
}

func rol(w word, r uint) word {
	return (w << (r % 32)) | (w >> (32 - (r % 32)))
}

func ror(w word, r uint) word {
	return (w >> (r % 32)) | (w << (32 - (r % 32)))
}

func RoundKey(K []byte, mode int) (RK [][6]word) {
	delta := [8]word{0xc3efe9db, 0x44626b02, 0x79e27c8a, 0x78df30ec, 0x715ea49e, 0xc785da0a, 0xe04ef22a, 0xe5c40957}
	var Nr uint
	switch len(K) {
	case 16:
		Nr = 24
	case 24:
		Nr = 28
	case 32:
		Nr = 32
	}
	T := make([]word, len(K)/4)
	RK = make([][6]word, Nr)
	for i := 0; i < len(K)/4; i++ {
		var buf [4]byte
		copy(buf[:], K[i*4:(i+1)*4])
		T[i] = ba2w(buf)
	}
	for i := uint(0); i < Nr; i++ {
		var rki uint
		switch mode {
		case ENCRYPT_MODE:
			rki = i
		case DECRYPT_MODE:
			rki = Nr - i - 1
		}
		switch len(K) {
		case 16:
			T[0] = rol(T[0]+rol(delta[i%4], i), 1)
			T[1] = rol(T[1]+rol(delta[i%4], i+1), 3)
			T[2] = rol(T[2]+rol(delta[i%4], i+2), 6)
			T[3] = rol(T[3]+rol(delta[i%4], i+3), 11)
			RK[rki] = [6]word{T[0], T[1], T[2], T[1], T[3], T[1]}
		case 24:
			T[0] = rol(T[0]+rol(delta[i%6], i), 1)
			T[1] = rol(T[1]+rol(delta[i%6], i+1), 3)
			T[2] = rol(T[2]+rol(delta[i%6], i+2), 6)
			T[3] = rol(T[3]+rol(delta[i%6], i+3), 11)
			T[4] = rol(T[4]+rol(delta[i%6], i+4), 13)
			T[5] = rol(T[5]+rol(delta[i%6], i+5), 17)
			RK[rki] = [6]word{T[0], T[1], T[2], T[3], T[4], T[5]}
		case 32:
			T[(6*i)%8] = rol(T[(6*i)%8]+rol(delta[i%8], i), 1)
			T[(6*i+1)%8] = rol(T[(6*i+1)%8]+rol(delta[i%8], i+1), 3)
			T[(6*i+2)%8] = rol(T[(6*i+2)%8]+rol(delta[i%8], i+2), 6)
			T[(6*i+3)%8] = rol(T[(6*i+3)%8]+rol(delta[i%8], i+3), 11)
			T[(6*i+4)%8] = rol(T[(6*i+4)%8]+rol(delta[i%8], i+4), 13)
			T[(6*i+5)%8] = rol(T[(6*i+5)%8]+rol(delta[i%8], i+5), 17)
			RK[rki] = [6]word{T[(6*i)%8], T[(6*i+1)%8], T[(6*i+2)%8], T[(6*i+3)%8], T[(6*i+4)%8], T[(6*i+5)%8]}
		}
	}
	return
}

func EncRound(x [4]word, rk [6]word) (t [4]word) {
	t[0] = rol((x[0]^rk[0])+(x[1]^rk[1]), 9)
	t[1] = ror((x[1]^rk[2])+(x[2]^rk[3]), 5)
	t[2] = ror((x[2]^rk[4])+(x[3]^rk[5]), 3)
	t[3] = x[0]
	return
}

func DecRound(x [4]word, rk [6]word) (t [4]word) {
	t[0] = x[3]
	t[1] = (ror(x[0], 9) - (t[0] ^ rk[0])) ^ rk[1]
	t[2] = (rol(x[1], 5) - (t[1] ^ rk[2])) ^ rk[3]
	t[3] = (rol(x[2], 3) - (t[2] ^ rk[4])) ^ rk[5]
	return
}

func encdec(from [16]byte, RK [][6]word, mode int) (to [16]byte) {
	var X [4]word
	for i := 0; i < 4; i++ {
		var buf [4]byte
		copy(buf[:], from[i*4:(i+1)*4])
		X[i] = ba2w(buf)
	}
	Nr := len(RK)
	for i := 0; i < Nr; i++ {
		switch mode {
		case ENCRYPT_MODE:
			X = EncRound(X, RK[i])
		case DECRYPT_MODE:
			X = DecRound(X, RK[i])
		}
	}
	for i := 0; i < 4; i++ {
		buf := w2ba(X[i])
		copy(to[i*4:(i+1)*4], buf[:])
	}
	return
}

func Encrypt(P [16]byte, RK [][6]word) [16]byte {
	return encdec(P, RK, ENCRYPT_MODE)
}

func Decrypt(C [16]byte, RK [][6]word) [16]byte {
	return encdec(C, RK, DECRYPT_MODE)
}
<commit_msg>adds comments<commit_after>package lea

import "fmt"

const (
	ENCRYPT_MODE = iota
	DECRYPT_MODE
)

// LEA uses a 128-bit block
type word uint32

func (w word) String() string {
	return fmt.Sprintf("%08x", uint32(w))
}

// converts a byte array [B1 B2 B3 B4] to a word B4B3B2B1
func ba2w(ba [4]byte) word {
	return word(uint32(ba[3])<<24 |
		uint32(ba[2])<<16 |
		uint32(ba[1])<<8 |
		uint32(ba[0]))
}

// converts a word B1B2B3B4 to a byte array [B4 B3 B2 B1]
func w2ba(w word) (ba [4]byte) {
	ba[0] = byte(w)
	ba[1] = byte(w >> 8)
	ba[2] = byte(w >> 16)
	ba[3] = byte(w >> 24)
	return
}

// 2 circular shift functions below
// [be careful] # of shift could be larger than 32

// circular left shift
func rol(w word, r uint) word {
	return (w << (r % 32)) | (w >> (32 - (r % 32)))
}

// circular right shift
func ror(w word, r uint) word {
	return (w >> (r % 32)) | (w << (32 - (r % 32)))
}

// returns round keys for encryption or decryption
// param K is a key (128-bit, 192-bit, or 256-bit)
// # of rows of return value (RK) will be different by the given key size
// mode: ENCRYPT_MODE or DECRYPT_MODE
func RoundKey(K []byte, mode int) (RK [][6]word) {
	delta := [8]word{0xc3efe9db, 0x44626b02, 0x79e27c8a, 0x78df30ec, 0x715ea49e, 0xc785da0a, 0xe04ef22a, 0xe5c40957}
	var Nr uint
	switch len(K) {
	case 16:
		Nr = 24
	case 24:
		Nr = 28
	case 32:
		Nr = 32
	}
	T := make([]word, len(K)/4)
	RK = make([][6]word, Nr)
	for i := 0; i < len(K)/4; i++ {
		var buf [4]byte
		copy(buf[:], K[i*4:(i+1)*4])
		T[i] = ba2w(buf)
	}
	for i := uint(0); i < Nr; i++ {
		var rki uint
		// procedures for generating round keys for encryption and decryption are the same
		// when decrypting mode, save them in reverse
		switch mode {
		case ENCRYPT_MODE:
			rki = i
		case DECRYPT_MODE:
			rki = Nr - i - 1
		}
		switch len(K) {
		case 16:
			T[0] = rol(T[0]+rol(delta[i%4], i), 1)
			T[1] = rol(T[1]+rol(delta[i%4], i+1), 3)
			T[2] = rol(T[2]+rol(delta[i%4], i+2), 6)
			T[3] = rol(T[3]+rol(delta[i%4], i+3), 11)
			RK[rki] = [6]word{T[0], T[1], T[2], T[1], T[3], T[1]}
		case 24:
			T[0] = rol(T[0]+rol(delta[i%6], i), 1)
			T[1] = rol(T[1]+rol(delta[i%6], i+1), 3)
			T[2] = rol(T[2]+rol(delta[i%6], i+2), 6)
			T[3] = rol(T[3]+rol(delta[i%6], i+3), 11)
			T[4] = rol(T[4]+rol(delta[i%6], i+4), 13)
			T[5] = rol(T[5]+rol(delta[i%6], i+5), 17)
			RK[rki] = [6]word{T[0], T[1], T[2], T[3], T[4], T[5]}
		case 32:
			T[(6*i)%8] = rol(T[(6*i)%8]+rol(delta[i%8], i), 1)
			T[(6*i+1)%8] = rol(T[(6*i+1)%8]+rol(delta[i%8], i+1), 3)
			T[(6*i+2)%8] = rol(T[(6*i+2)%8]+rol(delta[i%8], i+2), 6)
			T[(6*i+3)%8] = rol(T[(6*i+3)%8]+rol(delta[i%8], i+3), 11)
			T[(6*i+4)%8] = rol(T[(6*i+4)%8]+rol(delta[i%8], i+4), 13)
			T[(6*i+5)%8] = rol(T[(6*i+5)%8]+rol(delta[i%8], i+5), 17)
			RK[rki] = [6]word{T[(6*i)%8], T[(6*i+1)%8], T[(6*i+2)%8], T[(6*i+3)%8], T[(6*i+4)%8], T[(6*i+5)%8]}
		}
	}
	return
}

// one round for encryption
func EncRound(x [4]word, rk [6]word) (t [4]word) {
	t[0] = rol((x[0]^rk[0])+(x[1]^rk[1]), 9)
	t[1] = ror((x[1]^rk[2])+(x[2]^rk[3]), 5)
	t[2] = ror((x[2]^rk[4])+(x[3]^rk[5]), 3)
	t[3] = x[0]
	return
}

// one round for decryption
func DecRound(x [4]word, rk [6]word) (t [4]word) {
	t[0] = x[3]
	t[1] = (ror(x[0], 9) - (t[0] ^ rk[0])) ^ rk[1]
	t[2] = (rol(x[1], 5) - (t[1] ^ rk[2])) ^ rk[3]
	t[3] = (rol(x[2], 3) - (t[2] ^ rk[4])) ^ rk[5]
	return
}

// helper function for encryption and decryption
// LEA uses 4 words (4 bytes * 4 = 16 bytes = 128 bits) for encryption or decryption
// 1. breaks the given 16 bytes into 4 words
// 2. encrypts or decrypts them
// 3. reconstructs 4 words to 16 bytes
func encdec(from [16]byte, RK [][6]word, mode int) (to [16]byte) {
	var X [4]word
	for i := 0; i < 4; i++ {
		var buf [4]byte
		copy(buf[:], from[i*4:(i+1)*4])
		X[i] = ba2w(buf)
	}
	Nr := len(RK)
	for i := 0; i < Nr; i++ {
		switch mode {
		case ENCRYPT_MODE:
			X = EncRound(X, RK[i])
		case DECRYPT_MODE:
			X = DecRound(X, RK[i])
		}
	}
	for i := 0; i < 4; i++ {
		buf := w2ba(X[i])
		copy(to[i*4:(i+1)*4], buf[:])
	}
	return
}

func Encrypt(P [16]byte, RK [][6]word) [16]byte {
	return encdec(P, RK, ENCRYPT_MODE)
}

func Decrypt(C [16]byte, RK [][6]word) [16]byte {
	return encdec(C, RK, DECRYPT_MODE)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 Vulcand Authors

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 predicate

import (
	"reflect"
	"strings"

	"github.com/gravitational/trace"
)

// GetStringMapValue is a helper function that returns property
// from map[string]string or map[string][]string
// GetMapValure returns empty value in case if key not found
// In case if map is nil, returns empty value as well
func GetStringMapValue(mapVal, keyVal interface{}) (interface{}, error) {
	key, ok := keyVal.(string)
	if !ok {
		return nil, trace.BadParameter("")
	}
	switch m := mapVal.(type) {
	case map[string][]string:
		if len(m) == 0 {
			var n []string
			return n, nil
		}
		return m[key], nil
	case map[string]string:
		if len(m) == 0 {
			return "", nil
		}
		return m[key], nil
	default:
		return nil, trace.BadParameter("type %T is not supported", m)
	}
}

// BoolPredicate is a function without arguments that returns
// boolean value when called
type BoolPredicate func() bool

// Equals can compare complex objects, e.g. arrays of strings
// and strings together
func Equals(a interface{}, b interface{}) BoolPredicate {
	return func() bool {
		switch aval := a.(type) {
		case string:
			bval, ok := b.(string)
			return ok && aval == bval
		case []string:
			bval, ok := b.([]string)
			if !ok {
				return false
			}
			if len(aval) != len(bval) {
				return false
			}
			for i := range aval {
				if aval[i] != bval[i] {
					return false
				}
			}
			return true
		default:
			return false
		}
	}
}

// Contains checks if string slice contains a string
// Contains([]string{"a", "b"}, "b") -> true
func Contains(a interface{}, b interface{}) BoolPredicate {
	return func() bool {
		aval, ok := a.([]string)
		if !ok {
			return false
		}
		bval, ok := b.(string)
		if !ok {
			return false
		}
		for _, v := range aval {
			if v == bval {
				return true
			}
		}
		return false
	}
}

// And is a boolean predicate that calls two boolean predicates
// and returns result of && operation on their return values
func And(a, b BoolPredicate) BoolPredicate {
	return func() bool {
		return a() && b()
	}
}

// Or is a boolean predicate that calls two boolean predicates
// and returns result of || operation on their return values
func Or(a, b BoolPredicate) BoolPredicate {
	return func() bool {
		return a() || b()
	}
}

// GetFieldByTag returns a field from the object based on the tag
func GetFieldByTag(ival interface{}, tagName string, fieldNames []string) (interface{}, error) {
	if len(fieldNames) == 0 {
		return nil, trace.BadParameter("missing field names")
	}
	val := reflect.ValueOf(ival)
	if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
		val = val.Elem()
	}
	if val.Kind() != reflect.Struct {
		return nil, trace.NotFound("field name %v is not found", strings.Join(fieldNames, "."))
	}
	fieldName := fieldNames[0]
	rest := fieldNames[1:]

	valType := val.Type()
	for i := 0; i < valType.NumField(); i++ {
		tagValue := valType.Field(i).Tag.Get(tagName)
		parts := strings.Split(tagValue, ",")
		if parts[0] == fieldName {
			value := val.Field(i).Interface()
			if len(rest) == 0 {
				return value, nil
			}
			return GetFieldByTag(value, tagName, rest)
		}
	}
	return nil, trace.NotFound("field name %v is not found", strings.Join(fieldNames, "."))
}
<commit_msg>update comment<commit_after>/*
Copyright 2016 Vulcand Authors

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 predicate

import (
	"reflect"
	"strings"

	"github.com/gravitational/trace"
)

// GetStringMapValue is a helper function that returns property
// from map[string]string or map[string][]string
// the function returns empty value in case if key not found
// In case if map is nil, returns empty value as well
func GetStringMapValue(mapVal, keyVal interface{}) (interface{}, error) {
	key, ok := keyVal.(string)
	if !ok {
		return nil, trace.BadParameter("")
	}
	switch m := mapVal.(type) {
	case map[string][]string:
		if len(m) == 0 {
			var n []string
			return n, nil
		}
		return m[key], nil
	case map[string]string:
		if len(m) == 0 {
			return "", nil
		}
		return m[key], nil
	default:
		return nil, trace.BadParameter("type %T is not supported", m)
	}
}

// BoolPredicate is a function without arguments that returns
// boolean value when called
type BoolPredicate func() bool

// Equals can compare complex objects, e.g. arrays of strings
// and strings together
func Equals(a interface{}, b interface{}) BoolPredicate {
	return func() bool {
		switch aval := a.(type) {
		case string:
			bval, ok := b.(string)
			return ok && aval == bval
		case []string:
			bval, ok := b.([]string)
			if !ok {
				return false
			}
			if len(aval) != len(bval) {
				return false
			}
			for i := range aval {
				if aval[i] != bval[i] {
					return false
				}
			}
			return true
		default:
			return false
		}
	}
}

// Contains checks if string slice contains a string
// Contains([]string{"a", "b"}, "b") -> true
func Contains(a interface{}, b interface{}) BoolPredicate {
	return func() bool {
		aval, ok := a.([]string)
		if !ok {
			return false
		}
		bval, ok := b.(string)
		if !ok {
			return false
		}
		for _, v := range aval {
			if v == bval {
				return true
			}
		}
		return false
	}
}

// And is a boolean predicate that calls two boolean predicates
// and returns result of && operation on their return values
func And(a, b BoolPredicate) BoolPredicate {
	return func() bool {
		return a() && b()
	}
}

// Or is a boolean predicate that calls two boolean predicates
// and returns result of || operation on their return values
func Or(a, b BoolPredicate) BoolPredicate {
	return func() bool {
		return a() || b()
	}
}

// GetFieldByTag returns a field from the object based on the tag
func GetFieldByTag(ival interface{}, tagName string, fieldNames []string) (interface{}, error) {
	if len(fieldNames) == 0 {
		return nil, trace.BadParameter("missing field names")
	}
	val := reflect.ValueOf(ival)
	if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
		val = val.Elem()
	}
	if val.Kind() != reflect.Struct {
		return nil, trace.NotFound("field name %v is not found", strings.Join(fieldNames, "."))
	}
	fieldName := fieldNames[0]
	rest := fieldNames[1:]

	valType := val.Type()
	for i := 0; i < valType.NumField(); i++ {
		tagValue := valType.Field(i).Tag.Get(tagName)
		parts := strings.Split(tagValue, ",")
		if parts[0] == fieldName {
			value := val.Field(i).Interface()
			if len(rest) == 0 {
				return value, nil
			}
			return GetFieldByTag(value, tagName, rest)
		}
	}
	return nil, trace.NotFound("field name %v is not found", strings.Join(fieldNames, "."))
}
<|endoftext|>