<commit_before>package victor

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/brettbuddin/victor/pkg/chat"
	// Blank import used init adapters which registers them with victor
	_ "github.com/brettbuddin/victor/pkg/chat/campfire"
	_ "github.com/brettbuddin/victor/pkg/chat/hipchat"
	_ "github.com/brettbuddin/victor/pkg/chat/shell"
	_ "github.com/brettbuddin/victor/pkg/chat/slack"
	_ "github.com/brettbuddin/victor/pkg/chat/slackRealtime"
	"github.com/brettbuddin/victor/pkg/httpserver"
	"github.com/brettbuddin/victor/pkg/store"
	// Blank import used init adapters which registers them with victor
	_ "github.com/brettbuddin/victor/pkg/store/boltstore"
	_ "github.com/brettbuddin/victor/pkg/store/memory"
	"github.com/gorilla/mux"
)

// Robot provides an interface for a victor chat robot.
type Robot interface {
	Run()
	Stop()
	Name() string
	HandleFunc(string, HandlerFunc)
	Handle(string, Handler)
	Direct(string) string
	Receive(chat.Message)
	Chat() chat.Adapter
	Store() store.Adapter
	HTTP() *mux.Router
	AdapterConfig() (interface{}, bool)
	StoreConfig() (interface{}, bool)
}

// Config provides all of the configuration parameters needed in order to
// initialize a robot. It also allows for optional configuration structs for
// both the chat and storage adapters which they may or may not require.
type Config struct {
	Name,
	ChatAdapter,
	StoreAdapter,
	HTTPAddr string
	AdapterConfig,
	StoreConfig interface{}
}

type robot struct {
	*dispatch
	name       string
	http       *httpserver.Server
	httpAddr   string
	httpRouter *mux.Router
	store      store.Adapter
	chat       chat.Adapter
	incoming   chan chat.Message
	stop       chan struct{}
	adapterConfig,
	storeConfig interface{}
}

// New returns a robot
func New(config Config) *robot {
	chatAdapter := config.ChatAdapter
	if chatAdapter == "" {
		chatAdapter = "shell"
	}

	chatInitFunc, err := chat.Load(config.ChatAdapter)

	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	storeAdapter := config.StoreAdapter
	if storeAdapter == "" {
		storeAdapter = "memory"
	}

	storeInitFunc, err := store.Load(storeAdapter)

	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	botName := config.Name
	if botName == "" {
		botName = "victor"
	}

	httpAddr := config.HTTPAddr
	if httpAddr == "" {
		httpAddr = ":9000"
	}

	bot := &robot{
		name:     botName,
		httpAddr: httpAddr,
		incoming: make(chan chat.Message),
		stop:     make(chan struct{}),
	}

	bot.store = storeInitFunc(bot)
	bot.adapterConfig = config.AdapterConfig
	bot.dispatch = newDispatch(bot)
	bot.chat = chatInitFunc(bot)
	return bot
}

// Receive accepts messages for processing
func (r *robot) Receive(m chat.Message) {
	r.incoming <- m
}

// Run starts the robot.
func (r *robot) Run() {
	go r.chat.Run()
	go func() {
		for {
			select {
			case <-r.stop:
				close(r.incoming)
				return
			case m := <-r.incoming:
				if strings.ToLower(m.UserName()) != r.name {
					go r.ProcessMessage(m)
				}
			}
		}
	}()
}

// Stop shuts down the bot
func (r *robot) Stop() {
	r.chat.Stop()
	close(r.stop)
	r.http.Stop()
}

// Name returns the name of the bot
func (r *robot) Name() string {
	return r.name
}

// Store returns the data store adapter
func (r *robot) Store() store.Adapter {
	return r.store
}

// HTTP returns the HTTP router.
// The HTTP router is disabled (uninitialized) by default but is created upon
// the first call to HTTP().
//
// TODO consider having one explicitly enable the storage access endpoints
// (defined in http_handlers.go) since, as far as I can tell, a chat/storage
// adapter might want to use the included http router without enabling access
// to the entire store via those endpoints. At the moment these are coupled
// together.
func (r *robot) HTTP() *mux.Router {
	if r.httpRouter == nil {
		r.initHTTP()
	}
	return r.httpRouter
}

// Chat returns the chat adapter
func (r *robot) Chat() chat.Adapter {
	return r.chat
}

func (r *robot) AdapterConfig() (interface{}, bool) {
	return r.adapterConfig, r.adapterConfig != nil
}

func (r *robot) StoreConfig() (interface{}, bool) {
	return r.storeConfig, r.storeConfig != nil
}

func (r *robot) initHTTP() {
	log.Println("Initializing victor's HTTP server.")
	r.http = httpserver.New()
	r.httpRouter = handlers(r)
	r.http.Handle("/", r.httpRouter)
	r.http.ListenAndServe(r.httpAddr)
}

// OnlyAllow provides a way of permitting specific users
// to execute a handler registered with the bot
func OnlyAllow(userNames []string, action func(s State)) func(State) {
	return func(s State) {
		actual := s.Message().UserName()
		for _, name := range userNames {
			if name == actual {
				action(s)
				return
			}
		}

		s.Chat().Send(s.Message().ChannelID(), fmt.Sprintf("Sorry, %s. I can't let you do that.", actual))
	}
}
<commit_msg>Fixed nil pointer panic upon Stop call with uninitialized HTTP server<commit_after>package victor

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/brettbuddin/victor/pkg/chat"
	// Blank import used init adapters which registers them with victor
	_ "github.com/brettbuddin/victor/pkg/chat/campfire"
	_ "github.com/brettbuddin/victor/pkg/chat/hipchat"
	_ "github.com/brettbuddin/victor/pkg/chat/shell"
	_ "github.com/brettbuddin/victor/pkg/chat/slack"
	_ "github.com/brettbuddin/victor/pkg/chat/slackRealtime"
	"github.com/brettbuddin/victor/pkg/httpserver"
	"github.com/brettbuddin/victor/pkg/store"
	// Blank import used init adapters which registers them with victor
	_ "github.com/brettbuddin/victor/pkg/store/boltstore"
	_ "github.com/brettbuddin/victor/pkg/store/memory"
	"github.com/gorilla/mux"
)

// Robot provides an interface for a victor chat robot.
type Robot interface {
	Run()
	Stop()
	Name() string
	HandleFunc(string, HandlerFunc)
	Handle(string, Handler)
	Direct(string) string
	Receive(chat.Message)
	Chat() chat.Adapter
	Store() store.Adapter
	HTTP() *mux.Router
	AdapterConfig() (interface{}, bool)
	StoreConfig() (interface{}, bool)
}

// Config provides all of the configuration parameters needed in order to
// initialize a robot. It also allows for optional configuration structs for
// both the chat and storage adapters which they may or may not require.
type Config struct {
	Name,
	ChatAdapter,
	StoreAdapter,
	HTTPAddr string
	AdapterConfig,
	StoreConfig interface{}
}

type robot struct {
	*dispatch
	name       string
	http       *httpserver.Server
	httpAddr   string
	httpRouter *mux.Router
	store      store.Adapter
	chat       chat.Adapter
	incoming   chan chat.Message
	stop       chan struct{}
	adapterConfig,
	storeConfig interface{}
}

// New returns a robot
func New(config Config) *robot {
	chatAdapter := config.ChatAdapter
	if chatAdapter == "" {
		chatAdapter = "shell"
	}

	chatInitFunc, err := chat.Load(config.ChatAdapter)

	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	storeAdapter := config.StoreAdapter
	if storeAdapter == "" {
		storeAdapter = "memory"
	}

	storeInitFunc, err := store.Load(storeAdapter)

	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	botName := config.Name
	if botName == "" {
		botName = "victor"
	}

	httpAddr := config.HTTPAddr
	if httpAddr == "" {
		httpAddr = ":9000"
	}

	bot := &robot{
		name:     botName,
		httpAddr: httpAddr,
		incoming: make(chan chat.Message),
		stop:     make(chan struct{}),
	}

	bot.store = storeInitFunc(bot)
	bot.adapterConfig = config.AdapterConfig
	bot.dispatch = newDispatch(bot)
	bot.chat = chatInitFunc(bot)
	return bot
}

// Receive accepts messages for processing
func (r *robot) Receive(m chat.Message) {
	r.incoming <- m
}

// Run starts the robot.
func (r *robot) Run() {
	go r.chat.Run()
	go func() {
		for {
			select {
			case <-r.stop:
				close(r.incoming)
				return
			case m := <-r.incoming:
				if strings.ToLower(m.UserName()) != r.name {
					go r.ProcessMessage(m)
				}
			}
		}
	}()
}

// Stop shuts down the bot
func (r *robot) Stop() {
	r.chat.Stop()
	close(r.stop)
	if r.http != nil {
		r.http.Stop()
	}
}

// Name returns the name of the bot
func (r *robot) Name() string {
	return r.name
}

// Store returns the data store adapter
func (r *robot) Store() store.Adapter {
	return r.store
}

// HTTP returns the HTTP router.
// The HTTP router is disabled (uninitialized) by default but is created upon
// the first call to HTTP().
//
// TODO consider having one explicitly enable the storage access endpoints
// (defined in http_handlers.go) since, as far as I can tell, a chat/storage
// adapter might want to use the included http router without enabling access
// to the entire store via those endpoints. At the moment these are coupled
// together.
func (r *robot) HTTP() *mux.Router {
	if r.httpRouter == nil {
		r.initHTTP()
	}
	return r.httpRouter
}

// Chat returns the chat adapter
func (r *robot) Chat() chat.Adapter {
	return r.chat
}

func (r *robot) AdapterConfig() (interface{}, bool) {
	return r.adapterConfig, r.adapterConfig != nil
}

func (r *robot) StoreConfig() (interface{}, bool) {
	return r.storeConfig, r.storeConfig != nil
}

func (r *robot) initHTTP() {
	log.Println("Initializing victor's HTTP server.")
	r.http = httpserver.New()
	r.httpRouter = handlers(r)
	r.http.Handle("/", r.httpRouter)
	r.http.ListenAndServe(r.httpAddr)
}

// OnlyAllow provides a way of permitting specific users
// to execute a handler registered with the bot
func OnlyAllow(userNames []string, action func(s State)) func(State) {
	return func(s State) {
		actual := s.Message().UserName()
		for _, name := range userNames {
			if name == actual {
				action(s)
				return
			}
		}

		s.Chat().Send(s.Message().ChannelID(), fmt.Sprintf("Sorry, %s. I can't let you do that.", actual))
	}
}
<|endoftext|>


<commit_before>package mt

// Scales
var (
	ChromaticIntervals,
	MajorIntervals,
	MinorIntervals,
	IonianIntervals,
	DorianIntervals,
	PhrygianIntervals,
	AeolianIntervals,
	LydianIntervals,
	MixolydianIntervals,
	LocrianIntervals Intervals
)

func init() {
	P1 := Perfect(1)
	P4 := Perfect(4)
	P5 := Perfect(5)

	M2 := Major(2)
	M3 := Major(3)
	M6 := Major(6)
	M7 := Major(7)

	m2 := Minor(2)
	m3 := Minor(3)
	m6 := Minor(6)
	m7 := Minor(7)

	A4 := Augmented(4)
	d5 := Diminished(5)

	ChromaticIntervals = Intervals{P1, m2, M2, m3, M3, P4, A4, P5, m6, M6, m7, M7}

	IonianIntervals = Intervals{P1, M2, M3, P4, P5, M6, M7}
	MajorIntervals = IonianIntervals

	DorianIntervals = Intervals{P1, M2, m3, P4, P5, M6, m7}
	PhrygianIntervals = Intervals{P1, m2, m3, P4, P5, m6, m7}
	LydianIntervals = Intervals{P1, M2, M3, A4, P5, M6, M7}
	MixolydianIntervals = Intervals{P1, M2, M3, P4, P5, M6, m7}

	AeolianIntervals = Intervals{P1, M2, m3, P4, P5, m6, m7}
	MinorIntervals = AeolianIntervals

	LocrianIntervals = Intervals{P1, m2, m3, P4, d5, m6, m7}
}

// Intervals is a set of intervals
type Intervals []Interval

// Scale is a series of pitches
type Scale []Pitch

// NewScale returns a Scale built using a set of intervals
func NewScale(root Pitch, intervals Intervals) Scale {
	scale := Scale{}
	for _, i := range intervals {
		scale = append(scale, root.Transpose(i))
	}
	return scale
}
<commit_msg>Give these their own declarations.<commit_after>package mt

// Scales
var (
	ChromaticIntervals  Intervals
	MajorIntervals      Intervals
	MinorIntervals      Intervals
	IonianIntervals     Intervals
	DorianIntervals     Intervals
	PhrygianIntervals   Intervals
	AeolianIntervals    Intervals
	LydianIntervals     Intervals
	MixolydianIntervals Intervals
	LocrianIntervals    Intervals
)

func init() {
	P1 := Perfect(1)
	P4 := Perfect(4)
	P5 := Perfect(5)

	M2 := Major(2)
	M3 := Major(3)
	M6 := Major(6)
	M7 := Major(7)

	m2 := Minor(2)
	m3 := Minor(3)
	m6 := Minor(6)
	m7 := Minor(7)

	A4 := Augmented(4)
	d5 := Diminished(5)

	ChromaticIntervals = Intervals{P1, m2, M2, m3, M3, P4, A4, P5, m6, M6, m7, M7}

	IonianIntervals = Intervals{P1, M2, M3, P4, P5, M6, M7}
	MajorIntervals = IonianIntervals

	DorianIntervals = Intervals{P1, M2, m3, P4, P5, M6, m7}
	PhrygianIntervals = Intervals{P1, m2, m3, P4, P5, m6, m7}
	LydianIntervals = Intervals{P1, M2, M3, A4, P5, M6, M7}
	MixolydianIntervals = Intervals{P1, M2, M3, P4, P5, M6, m7}

	AeolianIntervals = Intervals{P1, M2, m3, P4, P5, m6, m7}
	MinorIntervals = AeolianIntervals

	LocrianIntervals = Intervals{P1, m2, m3, P4, d5, m6, m7}
}

// Intervals is a set of intervals
type Intervals []Interval

// Scale is a series of pitches
type Scale []Pitch

// NewScale returns a Scale built using a set of intervals
func NewScale(root Pitch, intervals Intervals) Scale {
	scale := Scale{}
	for _, i := range intervals {
		scale = append(scale, root.Transpose(i))
	}
	return scale
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

/* This is used for both profiles post and profile put */
type profilesPostReq struct {
	Name    string            `json:"name"`
	Config  map[string]string `json:"config"`
	Devices shared.Devices    `json:"devices"`
}

func profilesGet(d *Daemon, r *http.Request) Response {
	results, err := dbProfiles(d.db)
	if err != nil {
		return SmartError(err)
	}

	recursion := d.isRecursionRequest(r)

	resultString := make([]string, len(results))
	resultMap := make([]*shared.ProfileConfig, len(results))
	i := 0
	for _, name := range results {
		if !recursion {
			url := fmt.Sprintf("/%s/profiles/%s", shared.APIVersion, name)
			resultString[i] = url
		} else {
			profile, err := doProfileGet(d, name)
			if err != nil {
				shared.Log.Error("Failed to get profile", log.Ctx{"profile": name})
				continue
			}
			resultMap[i] = profile
		}
		i++
	}

	if !recursion {
		return SyncResponse(true, resultString)
	}

	return SyncResponse(true, resultMap)
}

func profilesPost(d *Daemon, r *http.Request) Response {
	req := profilesPostReq{}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return BadRequest(err)
	}

	// Sanity checks
	if req.Name == "" {
		return BadRequest(fmt.Errorf("No name provided"))
	}

	err := containerValidConfig(req.Config, true, false)
	if err != nil {
		return BadRequest(err)
	}

	err = containerValidDevices(req.Devices, true, false)
	if err != nil {
		return BadRequest(err)
	}

	// Update DB entry
	_, err = dbProfileCreate(d.db, req.Name, req.Config, req.Devices)
	if err != nil {
		return InternalError(
			fmt.Errorf("Error inserting %s into database: %s", req.Name, err))
	}

	return EmptySyncResponse
}

var profilesCmd = Command{
	name: "profiles",
	get:  profilesGet,
	post: profilesPost}

func doProfileGet(d *Daemon, name string) (*shared.ProfileConfig, error) {
	config, err := dbProfileConfig(d.db, name)
	if err != nil {
		return nil, err
	}

	devices, err := dbDevices(d.db, name, true)
	if err != nil {
		return nil, err
	}

	return &shared.ProfileConfig{
		Name:    name,
		Config:  config,
		Devices: devices,
	}, nil
}

func profileGet(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]

	resp, err := doProfileGet(d, name)
	if err != nil {
		return SmartError(err)
	}

	return SyncResponse(true, resp)
}

func getRunningContainersWithProfile(d *Daemon, profile string) []container {
	results := []container{}

	output, err := dbProfileContainersGet(d.db, profile)
	if err != nil {
		return results
	}

	for _, name := range output {
		c, err := containerLoadByName(d, name)
		if err != nil {
			shared.Log.Error("Failed opening container", log.Ctx{"container": name})
			continue
		}
		results = append(results, c)
	}
	return results
}

func profilePut(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]

	req := profilesPostReq{}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return BadRequest(err)
	}

	// Sanity checks
	err := containerValidConfig(req.Config, true, false)
	if err != nil {
		return BadRequest(err)
	}

	err = containerValidDevices(req.Devices, true, false)
	if err != nil {
		return BadRequest(err)
	}

	// Update the database
	id, err := dbProfileID(d.db, name)
	if err != nil {
		return InternalError(fmt.Errorf("Failed to retrieve profile='%s'", name))
	}

	tx, err := dbBegin(d.db)
	if err != nil {
		return InternalError(err)
	}

	err = dbProfileConfigClear(tx, id)
	if err != nil {
		tx.Rollback()
		return InternalError(err)
	}

	err = dbProfileConfigAdd(tx, id, req.Config)
	if err != nil {
		tx.Rollback()
		return SmartError(err)
	}

	err = dbDevicesAdd(tx, "profile", id, req.Devices)
	if err != nil {
		tx.Rollback()
		return SmartError(err)
	}

	err = txCommit(tx)
	if err != nil {
		return InternalError(err)
	}

	// Update all the containers using the profile. Must be done after txCommit due to DB lock.
	clist := getRunningContainersWithProfile(d, name)
	for _, c := range clist {
		if !c.IsRunning() {
			continue
		}

		err = c.Update(containerArgs{
			Architecture: c.Architecture(),
			Ephemeral:    c.IsEphemeral(),
			Config:       c.LocalConfig(),
			Devices:      c.LocalDevices(),
			Profiles:     c.Profiles()}, true)

		if err != nil {
			return SmartError(fmt.Errorf("Failed to update container '%s': %s", c.Name(), err))
		}
	}

	return EmptySyncResponse
}

// The handler for the delete operation.
func profileDelete(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	err := dbProfileDelete(d.db, name)

	if err != nil {
		return InternalError(err)
	}

	return EmptySyncResponse
}

var profileCmd = Command{name: "profiles/{name}", get: profileGet, put: profilePut, delete: profileDelete}
<commit_msg>Fix container update on profile change<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

/* This is used for both profiles post and profile put */
type profilesPostReq struct {
	Name    string            `json:"name"`
	Config  map[string]string `json:"config"`
	Devices shared.Devices    `json:"devices"`
}

func profilesGet(d *Daemon, r *http.Request) Response {
	results, err := dbProfiles(d.db)
	if err != nil {
		return SmartError(err)
	}

	recursion := d.isRecursionRequest(r)

	resultString := make([]string, len(results))
	resultMap := make([]*shared.ProfileConfig, len(results))
	i := 0
	for _, name := range results {
		if !recursion {
			url := fmt.Sprintf("/%s/profiles/%s", shared.APIVersion, name)
			resultString[i] = url
		} else {
			profile, err := doProfileGet(d, name)
			if err != nil {
				shared.Log.Error("Failed to get profile", log.Ctx{"profile": name})
				continue
			}
			resultMap[i] = profile
		}
		i++
	}

	if !recursion {
		return SyncResponse(true, resultString)
	}

	return SyncResponse(true, resultMap)
}

func profilesPost(d *Daemon, r *http.Request) Response {
	req := profilesPostReq{}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return BadRequest(err)
	}

	// Sanity checks
	if req.Name == "" {
		return BadRequest(fmt.Errorf("No name provided"))
	}

	err := containerValidConfig(req.Config, true, false)
	if err != nil {
		return BadRequest(err)
	}

	err = containerValidDevices(req.Devices, true, false)
	if err != nil {
		return BadRequest(err)
	}

	// Update DB entry
	_, err = dbProfileCreate(d.db, req.Name, req.Config, req.Devices)
	if err != nil {
		return InternalError(
			fmt.Errorf("Error inserting %s into database: %s", req.Name, err))
	}

	return EmptySyncResponse
}

var profilesCmd = Command{
	name: "profiles",
	get:  profilesGet,
	post: profilesPost}

func doProfileGet(d *Daemon, name string) (*shared.ProfileConfig, error) {
	config, err := dbProfileConfig(d.db, name)
	if err != nil {
		return nil, err
	}

	devices, err := dbDevices(d.db, name, true)
	if err != nil {
		return nil, err
	}

	return &shared.ProfileConfig{
		Name:    name,
		Config:  config,
		Devices: devices,
	}, nil
}

func profileGet(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]

	resp, err := doProfileGet(d, name)
	if err != nil {
		return SmartError(err)
	}

	return SyncResponse(true, resp)
}

func getRunningContainersWithProfile(d *Daemon, profile string) []container {
	results := []container{}

	output, err := dbProfileContainersGet(d.db, profile)
	if err != nil {
		return results
	}

	for _, name := range output {
		c, err := containerLoadByName(d, name)
		if err != nil {
			shared.Log.Error("Failed opening container", log.Ctx{"container": name})
			continue
		}
		results = append(results, c)
	}
	return results
}

func profilePut(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]

	req := profilesPostReq{}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return BadRequest(err)
	}

	// Sanity checks
	err := containerValidConfig(req.Config, true, false)
	if err != nil {
		return BadRequest(err)
	}

	err = containerValidDevices(req.Devices, true, false)
	if err != nil {
		return BadRequest(err)
	}

	// Get the running container list
	clist := getRunningContainersWithProfile(d, name)
	var containers []container
	for _, c := range clist {
		if !c.IsRunning() {
			continue
		}

		containers = append(containers, c)
	}

	// Update the database
	id, err := dbProfileID(d.db, name)
	if err != nil {
		return InternalError(fmt.Errorf("Failed to retrieve profile='%s'", name))
	}

	tx, err := dbBegin(d.db)
	if err != nil {
		return InternalError(err)
	}

	err = dbProfileConfigClear(tx, id)
	if err != nil {
		tx.Rollback()
		return InternalError(err)
	}

	err = dbProfileConfigAdd(tx, id, req.Config)
	if err != nil {
		tx.Rollback()
		return SmartError(err)
	}

	err = dbDevicesAdd(tx, "profile", id, req.Devices)
	if err != nil {
		tx.Rollback()
		return SmartError(err)
	}

	err = txCommit(tx)
	if err != nil {
		return InternalError(err)
	}

	// Update all the containers using the profile. Must be done after txCommit due to DB lock.
	failures := map[string]error{}
	for _, c := range containers {
		err = c.Update(containerArgs{
			Architecture: c.Architecture(),
			Ephemeral:    c.IsEphemeral(),
			Config:       c.LocalConfig(),
			Devices:      c.LocalDevices(),
			Profiles:     c.Profiles()}, true)

		if err != nil {
			failures[c.Name()] = err
		}
	}

	if len(failures) != 0 {
		msg := "The following containers failed to update (profile change still saved):\n"
		for cname, err := range failures {
			msg += fmt.Sprintf(" - %s: %s\n", cname, err)
		}
		return InternalError(fmt.Errorf("%s", msg))
	}

	return EmptySyncResponse
}

// The handler for the delete operation.
func profileDelete(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	err := dbProfileDelete(d.db, name)

	if err != nil {
		return InternalError(err)
	}

	return EmptySyncResponse
}

var profileCmd = Command{name: "profiles/{name}", get: profileGet, put: profilePut, delete: profileDelete}
<|endoftext|>


<commit_before>package wrap

import (
	"fmt"
	"os"

	"github.com/mackerelio/mackerel-agent/config"
	cli "gopkg.in/urfave/cli.v1"
)

// CommandPlugin is definition of mkr plugin
var Command = cli.Command{
	Name:      "wrap",
	Usage:     "wrap command status",
	ArgsUsage: "[--verbose | -v] [--name | -n <name>] [--memo | -m <memo>] -- /path/to/batch",
	Description: `
    wrap command line
`,
	Action: doWrap,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "name, n", Value: "", Usage: "monitor <name>"},
		cli.BoolFlag{Name: "verbose, v", Usage: "verbose output mode"},
		cli.StringFlag{Name: "memo, m", Value: "", Usage: "monitor <memo>"},
		cli.StringFlag{Name: "H, host", Value: "", Usage: "<hostId>"},
		cli.BoolFlag{Name: "warning, w", Usage: "alert as warning"},
	},
}

func doWrap(c *cli.Context) error {
	confFile := c.GlobalString("conf")
	conf, err := config.LoadConfig(confFile)
	if err != nil {
		return err
	}
	apibase := c.GlobalString("apibase")
	apikey := conf.Apikey
	if apikey == "" {
		apikey = os.Getenv("MACKEREL_APIKEY")
	}
	if apikey == "" {
		return fmt.Errorf(`MACKEREL_APIKEY environment variable is not set. (Try "export MACKEREL_APIKEY='<Your apikey>'`)
	}
	hostID, _ := conf.LoadHostID()
	if c.String("host") != "" {
		hostID = c.String("host")
	}
	if hostID == "" {
		return fmt.Errorf("failed to load hostID. (Try to specify -host option explicitly)")
	}
	cmd := c.Args()
	if len(cmd) > 0 && cmd[0] == "--" {
		cmd = cmd[1:]
	}
	if len(cmd) < 1 {
		return fmt.Errorf("no command specified")
	}

	return (&app{
		apibase: apibase,
		name:    c.String("name"),
		verbose: c.Bool("verbose"),
		memo:    c.String("memo"),
		warning: c.Bool("warning"),
		hostID:  hostID,
		apikey:  apikey,
		cmd:     cmd,
	}).run()
}

type app struct {
	apibase string
	name    string
	verbose bool
	memo    string
	warning bool
	hostID  string
	apikey  string
	cmd     []string
}

func (ap *app) run() error {
	return nil
}
<commit_msg>run the wrapping command<commit_after>package wrap

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"time"

	"github.com/Songmu/wrapcommander"
	"github.com/mackerelio/mackerel-agent/config"
	"golang.org/x/sync/errgroup"
	cli "gopkg.in/urfave/cli.v1"
)

// CommandPlugin is definition of mkr plugin
var Command = cli.Command{
	Name:      "wrap",
	Usage:     "wrap command status",
	ArgsUsage: "[--verbose | -v] [--name | -n <name>] [--memo | -m <memo>] -- /path/to/batch",
	Description: `
    wrap command line
`,
	Action: doWrap,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "name, n", Value: "", Usage: "monitor <name>"},
		cli.BoolFlag{Name: "verbose, v", Usage: "verbose output mode"},
		cli.StringFlag{Name: "memo, m", Value: "", Usage: "monitor <memo>"},
		cli.StringFlag{Name: "H, host", Value: "", Usage: "<hostId>"},
		cli.BoolFlag{Name: "warning, w", Usage: "alert as warning"},
	},
}

func doWrap(c *cli.Context) error {
	confFile := c.GlobalString("conf")
	conf, err := config.LoadConfig(confFile)
	if err != nil {
		return err
	}
	apibase := c.GlobalString("apibase")
	apikey := conf.Apikey
	if apikey == "" {
		apikey = os.Getenv("MACKEREL_APIKEY")
	}
	if apikey == "" {
		return fmt.Errorf(`MACKEREL_APIKEY environment variable is not set. (Try "export MACKEREL_APIKEY='<Your apikey>'`)
	}
	hostID, _ := conf.LoadHostID()
	if c.String("host") != "" {
		hostID = c.String("host")
	}
	if hostID == "" {
		return fmt.Errorf("failed to load hostID. (Try to specify -host option explicitly)")
	}
	cmd := c.Args()
	if len(cmd) > 0 && cmd[0] == "--" {
		cmd = cmd[1:]
	}
	if len(cmd) < 1 {
		return fmt.Errorf("no command specified")
	}

	return (&app{
		apibase: apibase,
		name:    c.String("name"),
		verbose: c.Bool("verbose"),
		memo:    c.String("memo"),
		warning: c.Bool("warning"),
		hostID:  hostID,
		apikey:  apikey,
		cmd:     cmd,
	}).run()
}

type app struct {
	apibase string
	name    string
	verbose bool
	memo    string
	warning bool
	hostID  string
	apikey  string
	cmd     []string
}

type result struct {
	cmd        []string
	name, memo string

	output, stdout, stderr string
	pid, exitCode          *int
	signaled               bool
	startAt, endAt         time.Time

	msg     string
	success bool
}

func (ap *app) run() error {
	re := ap.runCmd()
	_ = re
	return nil
}

func (ap *app) runCmd() *result {
	cmd := exec.Command(ap.cmd[0], ap.cmd[1:]...)
	re := &result{
		cmd:  ap.cmd,
		name: ap.name,
		memo: ap.memo,
	}

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		re.msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stdoutPipe.Close()

	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		re.msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stderrPipe.Close()

	var (
		bufStdout = &bytes.Buffer{}
		bufStderr = &bytes.Buffer{}
		bufMerged = &bytes.Buffer{}
	)
	stdoutPipe2 := io.TeeReader(stdoutPipe, io.MultiWriter(bufStdout, bufMerged))
	stderrPipe2 := io.TeeReader(stderrPipe, io.MultiWriter(bufStderr, bufMerged))

	re.startAt = time.Now()
	err = cmd.Start()
	if err != nil {
		re.msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	re.pid = &cmd.Process.Pid
	eg := &errgroup.Group{}

	eg.Go(func() error {
		defer stdoutPipe.Close()
		_, err := io.Copy(os.Stdout, stdoutPipe2)
		return err
	})
	eg.Go(func() error {
		defer stderrPipe.Close()
		_, err := io.Copy(os.Stderr, stderrPipe2)
		return err
	})
	eg.Wait()

	cmdErr := cmd.Wait()
	re.endAt = time.Now()
	ex := wrapcommander.ResolveExitCode(cmdErr)
	re.exitCode = &ex
	if *re.exitCode > 128 {
		w, ok := wrapcommander.ErrorToWaitStatus(cmdErr)
		if ok {
			re.signaled = w.Signaled()
		}
	}
	if !re.signaled {
		re.msg = fmt.Sprintf("command exited with code: %d", *re.exitCode)
	} else {
		re.msg = fmt.Sprintf("command died with signal: %d", *re.exitCode&127)
	}
	re.stdout = bufStdout.String()
	re.stderr = bufStderr.String()
	re.output = bufMerged.String()

	re.success = *re.exitCode == 0
	return re
}
<|endoftext|>


<commit_before>package gorm

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"

	"reflect"
)

type Scope struct {
	Search          *search
	Value           interface{}
	Sql             string
	SqlVars         []interface{}
	db              *DB
	indirectValue   *reflect.Value
	instanceId      string
	primaryKeyField *Field
	skipLeft        bool
	fields          map[string]*Field
	selectAttrs     *[]string
}

func (scope *Scope) IndirectValue() reflect.Value {
	if scope.indirectValue == nil {
		value := reflect.Indirect(reflect.ValueOf(scope.Value))
		if value.Kind() == reflect.Ptr {
			value = value.Elem()
		}
		scope.indirectValue = &value
	}
	return *scope.indirectValue
}

func (scope *Scope) NeedPtr() *Scope {
	reflectKind := reflect.ValueOf(scope.Value).Kind()
	if !((reflectKind == reflect.Invalid) || (reflectKind == reflect.Ptr)) {
		err := fmt.Errorf("%v %v\n", fileWithLineNum(), "using unaddressable value")
		scope.Err(err)
		fmt.Printf(err.Error())
	}
	return scope
}

// New create a new Scope without search information
func (scope *Scope) New(value interface{}) *Scope {
	return &Scope{db: scope.NewDB(), Search: &search{}, Value: value}
}

// NewDB create a new DB without search information
func (scope *Scope) NewDB() *DB {
	if scope.db != nil {
		db := scope.db.clone()
		db.search = nil
		db.Value = nil
		return db
	}
	return nil
}

func (scope *Scope) DB() *DB {
	return scope.db
}

// SqlDB return *sql.DB
func (scope *Scope) SqlDB() sqlCommon {
	return scope.db.db
}

// SkipLeft skip remaining callbacks
func (scope *Scope) SkipLeft() {
	scope.skipLeft = true
}

// Quote used to quote database column name according to database dialect
func (scope *Scope) Quote(str string) string {
	if strings.Index(str, ".") != -1 {
		newStrs := []string{}
		for _, str := range strings.Split(str, ".") {
			newStrs = append(newStrs, scope.Dialect().Quote(str))
		}
		return strings.Join(newStrs, ".")
	} else {
		return scope.Dialect().Quote(str)
	}
}

func (scope *Scope) QuoteIfPossible(str string) string {
	if regexp.MustCompile("^[a-zA-Z]+(.[a-zA-Z]+)*$").MatchString(str) {
		return scope.Quote(str)
	}
	return str
}

// Dialect get dialect
func (scope *Scope) Dialect() Dialect {
	return scope.db.parent.dialect
}

// Err write error
func (scope *Scope) Err(err error) error {
	if err != nil {
		scope.db.err(err)
	}
	return err
}

// Log print log message
func (scope *Scope) Log(v ...interface{}) {
	scope.db.log(v...)
}

// HasError check if there are any error
func (scope *Scope) HasError() bool {
	return scope.db.Error != nil
}

func (scope *Scope) PrimaryFields() []*Field {
	var fields = []*Field{}
	for _, field := range scope.GetModelStruct().PrimaryFields {
		fields = append(fields, scope.Fields()[field.DBName])
	}
	return fields
}

func (scope *Scope) PrimaryField() *Field {
	if primaryFields := scope.GetModelStruct().PrimaryFields; len(primaryFields) > 0 {
		if len(primaryFields) > 1 {
			if field, ok := scope.Fields()["id"]; ok {
				return field
			}
		}
		return scope.Fields()[primaryFields[0].DBName]
	}
	return nil
}

// PrimaryKey get the primary key's column name
func (scope *Scope) PrimaryKey() string {
	if field := scope.PrimaryField(); field != nil {
		return field.DBName
	}
	return ""
}

// PrimaryKeyZero check the primary key is blank or not
func (scope *Scope) PrimaryKeyZero() bool {
	field := scope.PrimaryField()
	return field == nil || field.IsBlank
}

// PrimaryKeyValue get the primary key's value
func (scope *Scope) PrimaryKeyValue() interface{} {
	if field := scope.PrimaryField(); field != nil && field.Field.IsValid() {
		return field.Field.Interface()
	}
	return 0
}

// HasColumn to check if has column
func (scope *Scope) HasColumn(column string) bool {
	for _, field := range scope.GetStructFields() {
		if field.IsNormal && (field.Name == column || field.DBName == column) {
			return true
		}
	}
	return false
}

// SetColumn to set the column's value
func (scope *Scope) SetColumn(column interface{}, value interface{}) error {
	if field, ok := column.(*Field); ok {
		return field.Set(value)
	} else if name, ok := column.(string); ok {

		if field, ok := scope.Fields()[name]; ok {
			return field.Set(value)
		}

		dbName := ToDBName(name)
		if field, ok := scope.Fields()[dbName]; ok {
			return field.Set(value)
		}

		if field, ok := scope.FieldByName(name); ok {
			return field.Set(value)
		}
	}
	return errors.New("could not convert column to field")
}

func (scope *Scope) CallMethod(name string, checkError bool) {
	if scope.Value == nil || (checkError && scope.HasError()) {
		return
	}

	call := func(value interface{}) {
		if fm := reflect.ValueOf(value).MethodByName(name); fm.IsValid() {
			switch f := fm.Interface().(type) {
			case func():
				f()
			case func(s *Scope):
				f(scope)
			case func(s *DB):
				newDB := scope.NewDB()
				f(newDB)
				scope.Err(newDB.Error)
			case func() error:
				scope.Err(f())
			case func(s *Scope) error:
				scope.Err(f(scope))
			case func(s *DB) error:
				scope.Err(f(scope.NewDB()))
			default:
				scope.Err(fmt.Errorf("unsupported function %v", name))
			}
		}
	}

	if values := scope.IndirectValue(); values.Kind() == reflect.Slice {
		for i := 0; i < values.Len(); i++ {
			call(values.Index(i).Addr().Interface())
		}
	} else {
		call(scope.Value)
	}
}

func (scope *Scope) CallMethodWithErrorCheck(name string) {
	scope.CallMethod(name, true)
}

// AddToVars add value as sql's vars, gorm will escape them
func (scope *Scope) AddToVars(value interface{}) string {
	if expr, ok := value.(*expr); ok {
		exp := expr.expr
		for _, arg := range expr.args {
			exp = strings.Replace(exp, "?", scope.AddToVars(arg), 1)
		}
		return exp
	} else {
		scope.SqlVars = append(scope.SqlVars, value)
		return scope.Dialect().BinVar(len(scope.SqlVars))
	}
}

type tabler interface {
	TableName() string
}

type dbTabler interface {
	TableName(*DB) string
}

// TableName get table name
func (scope *Scope) TableName() string {
	if scope.Search != nil && len(scope.Search.tableName) > 0 {
		return scope.Search.tableName
	}

	if tabler, ok := scope.Value.(tabler); ok {
		return tabler.TableName()
	}

	if tabler, ok := scope.Value.(dbTabler); ok {
		return tabler.TableName(scope.db)
	}

	return scope.GetModelStruct().TableName(scope.db.Model(scope.Value))
}

func (scope *Scope) QuotedTableName() (name string) {
	if scope.Search != nil && len(scope.Search.tableName) > 0 {
		if strings.Index(scope.Search.tableName, " ") != -1 {
			return scope.Search.tableName
		}
		return scope.Quote(scope.Search.tableName)
	} else {
		return scope.Quote(scope.TableName())
	}
}

// CombinedConditionSql get combined condition sql
func (scope *Scope) CombinedConditionSql() string {
	return scope.joinsSql() + scope.whereSql() + scope.groupSql() +
		scope.havingSql() + scope.orderSql() + scope.limitSql() + scope.offsetSql()
}

func (scope *Scope) FieldByName(name string) (field *Field, ok bool) {
	for _, field := range scope.Fields() {
		if field.Name == name || field.DBName == name {
			return field, true
		}
	}
	return nil, false
}

// Raw set sql
func (scope *Scope) Raw(sql string) *Scope {
	scope.Sql = strings.Replace(sql, "$$", "?", -1)
	return scope
}

// Exec invoke sql
func (scope *Scope) Exec() *Scope {
	defer scope.Trace(NowFunc())

	if !scope.HasError() {
		if result, err := scope.SqlDB().Exec(scope.Sql, scope.SqlVars...); scope.Err(err) == nil {
			if count, err := result.RowsAffected(); scope.Err(err) == nil {
				scope.db.RowsAffected = count
			}
		}
	}
	return scope
}

// Set set value by name
func (scope *Scope) Set(name string, value interface{}) *Scope {
	scope.db.InstantSet(name, value)
	return scope
}

// Get get value by name
func (scope *Scope) Get(name string) (interface{}, bool) {
	return scope.db.Get(name)
}

// InstanceId get InstanceId for scope
func (scope *Scope) InstanceId() string {
	if scope.instanceId == "" {
		scope.instanceId = fmt.Sprintf("%v%v", &scope, &scope.db)
	}
	return scope.instanceId
}

func (scope *Scope) InstanceSet(name string, value interface{}) *Scope {
	return scope.Set(name+scope.InstanceId(), value)
}

func (scope *Scope) InstanceGet(name string) (interface{}, bool) {
	return scope.Get(name + scope.InstanceId())
}

// Trace print sql log
func (scope *Scope) Trace(t time.Time) {
	if len(scope.Sql) > 0 {
		scope.db.slog(scope.Sql, t, scope.SqlVars...)
	}
}

// Begin start a transaction
func (scope *Scope) Begin() *Scope {
	if db, ok := scope.SqlDB().(sqlDb); ok {
		if tx, err := db.Begin(); err == nil {
			scope.db.db = interface{}(tx).(sqlCommon)
			scope.InstanceSet("gorm:started_transaction", true)
		}
	}
	return scope
}

// CommitOrRollback commit current transaction if there is no error, otherwise rollback it
func (scope *Scope) CommitOrRollback() *Scope {
	if _, ok := scope.InstanceGet("gorm:started_transaction"); ok {
		if db, ok := scope.db.db.(sqlTx); ok {
			if scope.HasError() {
				db.Rollback()
			} else {
				db.Commit()
			}
			scope.db.db = scope.db.parent.db
		}
	}
	return scope
}

func (scope *Scope) SelectAttrs() []string {
	if scope.selectAttrs == nil {
		attrs := []string{}
		for _, value := range scope.Search.selects {
			if str, ok := value.(string); ok {
				attrs = append(attrs, str)
			} else if strs, ok := value.([]string); ok {
				attrs = append(attrs, strs...)
			} else if strs, ok := value.([]interface{}); ok {
				for _, str := range strs {
					attrs = append(attrs, fmt.Sprintf("%v", str))
				}
			}
		}
		scope.selectAttrs = &attrs
	}
	return *scope.selectAttrs
}

func (scope *Scope) OmitAttrs() []string {
	return scope.Search.omits
}

func (scope *Scope) changeableDBColumn(column string) bool {
	selectAttrs := scope.SelectAttrs()
	omitAttrs := scope.OmitAttrs()

	if len(selectAttrs) > 0 {
		for _, attr := range selectAttrs {
			if column == ToDBName(attr) {
				return true
			}
		}
		return false
	}

	for _, attr := range omitAttrs {
		if column == ToDBName(attr) {
			return false
		}
	}
	return true
}

func (scope *Scope) changeableField(field *Field) bool {
	selectAttrs := scope.SelectAttrs()
	omitAttrs := scope.OmitAttrs()

	if len(selectAttrs) > 0 {
		for _, attr := range selectAttrs {
			if field.Name == attr || field.DBName == attr {
				return true
			}
		}
		return false
	}

	for _, attr := range omitAttrs {
		if field.Name == attr || field.DBName == attr {
			return false
		}
	}

	return !field.IsIgnored
}

func (scope *Scope) shouldSaveAssociations() bool {
	saveAssociations, ok := scope.Get("gorm:save_associations")
	if ok && !saveAssociations.(bool) {
		return false
	}
	return true
}
<commit_msg>Fix can't call callbacks for embedded pointers<commit_after>package gorm

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"

	"reflect"
)

type Scope struct {
	Search          *search
	Value           interface{}
	Sql             string
	SqlVars         []interface{}
	db              *DB
	indirectValue   *reflect.Value
	instanceId      string
	primaryKeyField *Field
	skipLeft        bool
	fields          map[string]*Field
	selectAttrs     *[]string
}

func (scope *Scope) IndirectValue() reflect.Value {
	if scope.indirectValue == nil {
		value := reflect.Indirect(reflect.ValueOf(scope.Value))
		if value.Kind() == reflect.Ptr {
			value = value.Elem()
		}
		scope.indirectValue = &value
	}
	return *scope.indirectValue
}

func (scope *Scope) NeedPtr() *Scope {
	reflectKind := reflect.ValueOf(scope.Value).Kind()
	if !((reflectKind == reflect.Invalid) || (reflectKind == reflect.Ptr)) {
		err := fmt.Errorf("%v %v\n", fileWithLineNum(), "using unaddressable value")
		scope.Err(err)
		fmt.Printf(err.Error())
	}
	return scope
}

// New create a new Scope without search information
func (scope *Scope) New(value interface{}) *Scope {
	return &Scope{db: scope.NewDB(), Search: &search{}, Value: value}
}

// NewDB create a new DB without search information
func (scope *Scope) NewDB() *DB {
	if scope.db != nil {
		db := scope.db.clone()
		db.search = nil
		db.Value = nil
		return db
	}
	return nil
}

func (scope *Scope) DB() *DB {
	return scope.db
}

// SqlDB return *sql.DB
func (scope *Scope) SqlDB() sqlCommon {
	return scope.db.db
}

// SkipLeft skip remaining callbacks
func (scope *Scope) SkipLeft() {
	scope.skipLeft = true
}

// Quote used to quote database column name according to database dialect
func (scope *Scope) Quote(str string) string {
	if strings.Index(str, ".") != -1 {
		newStrs := []string{}
		for _, str := range strings.Split(str, ".") {
			newStrs = append(newStrs, scope.Dialect().Quote(str))
		}
		return strings.Join(newStrs, ".")
	} else {
		return scope.Dialect().Quote(str)
	}
}

func (scope *Scope) QuoteIfPossible(str string) string {
	if regexp.MustCompile("^[a-zA-Z]+(.[a-zA-Z]+)*$").MatchString(str) {
		return scope.Quote(str)
	}
	return str
}

// Dialect get dialect
func (scope *Scope) Dialect() Dialect {
	return scope.db.parent.dialect
}

// Err write error
func (scope *Scope) Err(err error) error {
	if err != nil {
		scope.db.err(err)
	}
	return err
}

// Log print log message
func (scope *Scope) Log(v ...interface{}) {
	scope.db.log(v...)
}

// HasError check if there are any error
func (scope *Scope) HasError() bool {
	return scope.db.Error != nil
}

func (scope *Scope) PrimaryFields() []*Field {
	var fields = []*Field{}
	for _, field := range scope.GetModelStruct().PrimaryFields {
		fields = append(fields, scope.Fields()[field.DBName])
	}
	return fields
}

func (scope *Scope) PrimaryField() *Field {
	if primaryFields := scope.GetModelStruct().PrimaryFields; len(primaryFields) > 0 {
		if len(primaryFields) > 1 {
			if field, ok := scope.Fields()["id"]; ok {
				return field
			}
		}
		return scope.Fields()[primaryFields[0].DBName]
	}
	return nil
}

// PrimaryKey get the primary key's column name
func (scope *Scope) PrimaryKey() string {
	if field := scope.PrimaryField(); field != nil {
		return field.DBName
	}
	return ""
}

// PrimaryKeyZero check the primary key is blank or not
func (scope *Scope) PrimaryKeyZero() bool {
	field := scope.PrimaryField()
	return field == nil || field.IsBlank
}

// PrimaryKeyValue get the primary key's value
func (scope *Scope) PrimaryKeyValue() interface{} {
	if field := scope.PrimaryField(); field != nil && field.Field.IsValid() {
		return field.Field.Interface()
	}
	return 0
}

// HasColumn to check if has column
func (scope *Scope) HasColumn(column string) bool {
	for _, field := range scope.GetStructFields() {
		if field.IsNormal && (field.Name == column || field.DBName == column) {
			return true
		}
	}
	return false
}

// SetColumn to set the column's value
func (scope *Scope) SetColumn(column interface{}, value interface{}) error {
	if field, ok := column.(*Field); ok {
		return field.Set(value)
	} else if name, ok := column.(string); ok {

		if field, ok := scope.Fields()[name]; ok {
			return field.Set(value)
		}

		dbName := ToDBName(name)
		if field, ok := scope.Fields()[dbName]; ok {
			return field.Set(value)
		}

		if field, ok := scope.FieldByName(name); ok {
			return field.Set(value)
		}
	}
	return errors.New("could not convert column to field")
}

func (scope *Scope) CallMethod(name string, checkError bool) {
	if scope.Value == nil || (checkError && scope.HasError()) {
		return
	}

	call := func(value interface{}) {
		if fm := reflect.ValueOf(value).MethodByName(name); fm.IsValid() {
			switch f := fm.Interface().(type) {
			case func():
				f()
			case func(s *Scope):
				f(scope)
			case func(s *DB):
				newDB := scope.NewDB()
				f(newDB)
				scope.Err(newDB.Error)
			case func() error:
				scope.Err(f())
			case func(s *Scope) error:
				scope.Err(f(scope))
			case func(s *DB) error:
				scope.Err(f(scope.NewDB()))
			default:
				scope.Err(fmt.Errorf("unsupported function %v", name))
			}
		}
	}

	if values := scope.IndirectValue(); values.Kind() == reflect.Slice {
		for i := 0; i < values.Len(); i++ {
			value := values.Index(i).Addr().Interface()
			if values.Index(i).Kind() == reflect.Ptr {
				value = values.Index(i).Interface()
			}
			call(value)
		}
	} else {
		if scope.IndirectValue().CanAddr() {
			call(scope.IndirectValue().Addr().Interface())
		} else {
			call(scope.IndirectValue().Interface())
		}
	}
}

func (scope *Scope) CallMethodWithErrorCheck(name string) {
	scope.CallMethod(name, true)
}

// AddToVars add value as sql's vars, gorm will escape them
func (scope *Scope) AddToVars(value interface{}) string {
	if expr, ok := value.(*expr); ok {
		exp := expr.expr
		for _, arg := range expr.args {
			exp = strings.Replace(exp, "?", scope.AddToVars(arg), 1)
		}
		return exp
	} else {
		scope.SqlVars = append(scope.SqlVars, value)
		return scope.Dialect().BinVar(len(scope.SqlVars))
	}
}

type tabler interface {
	TableName() string
}

type dbTabler interface {
	TableName(*DB) string
}

// TableName get table name
func (scope *Scope) TableName() string {
	if scope.Search != nil && len(scope.Search.tableName) > 0 {
		return scope.Search.tableName
	}

	if tabler, ok := scope.Value.(tabler); ok {
		return tabler.TableName()
	}

	if tabler, ok := scope.Value.(dbTabler); ok {
		return tabler.TableName(scope.db)
	}

	return scope.GetModelStruct().TableName(scope.db.Model(scope.Value))
}

func (scope *Scope) QuotedTableName() (name string) {
	if scope.Search != nil && len(scope.Search.tableName) > 0 {
		if strings.Index(scope.Search.tableName, " ") != -1 {
			return scope.Search.tableName
		}
		return scope.Quote(scope.Search.tableName)
	} else {
		return scope.Quote(scope.TableName())
	}
}

// CombinedConditionSql get combined condition sql
func (scope *Scope) CombinedConditionSql() string {
	return scope.joinsSql() + scope.whereSql() + scope.groupSql() +
		scope.havingSql() + scope.orderSql() + scope.limitSql() + scope.offsetSql()
}

func (scope *Scope) FieldByName(name string) (field *Field, ok bool) {
	for _, field := range scope.Fields() {
		if field.Name == name || field.DBName == name {
			return field, true
		}
	}
	return nil, false
}

// Raw set sql
func (scope *Scope) Raw(sql string) *Scope {
	scope.Sql = strings.Replace(sql, "$$", "?", -1)
	return scope
}

// Exec invoke sql
func (scope *Scope) Exec() *Scope {
	defer scope.Trace(NowFunc())

	if !scope.HasError() {
		if result, err := scope.SqlDB().Exec(scope.Sql, scope.SqlVars...); scope.Err(err) == nil {
			if count, err := result.RowsAffected(); scope.Err(err) == nil {
				scope.db.RowsAffected = count
			}
		}
	}
	return scope
}

// Set set value by name
func (scope *Scope) Set(name string, value interface{}) *Scope {
	scope.db.InstantSet(name, value)
	return scope
}

// Get get value by name
func (scope *Scope) Get(name string) (interface{}, bool) {
	return scope.db.Get(name)
}

// InstanceId get InstanceId for scope
func (scope *Scope) InstanceId() string {
	if scope.instanceId == "" {
		scope.instanceId = fmt.Sprintf("%v%v", &scope, &scope.db)
	}
	return scope.instanceId
}

func (scope *Scope) InstanceSet(name string, value interface{}) *Scope {
	return scope.Set(name+scope.InstanceId(), value)
}

func (scope *Scope) InstanceGet(name string) (interface{}, bool) {
	return scope.Get(name + scope.InstanceId())
}

// Trace print sql log
func (scope *Scope) Trace(t time.Time) {
	if len(scope.Sql) > 0 {
		scope.db.slog(scope.Sql, t, scope.SqlVars...)
	}
}

// Begin start a transaction
func (scope *Scope) Begin() *Scope {
	if db, ok := scope.SqlDB().(sqlDb); ok {
		if tx, err := db.Begin(); err == nil {
			scope.db.db = interface{}(tx).(sqlCommon)
			scope.InstanceSet("gorm:started_transaction", true)
		}
	}
	return scope
}

// CommitOrRollback commit current transaction if there is no error, otherwise rollback it
func (scope *Scope) CommitOrRollback() *Scope {
	if _, ok := scope.InstanceGet("gorm:started_transaction"); ok {
		if db, ok := scope.db.db.(sqlTx); ok {
			if scope.HasError() {
				db.Rollback()
			} else {
				db.Commit()
			}
			scope.db.db = scope.db.parent.db
		}
	}
	return scope
}

func (scope *Scope) SelectAttrs() []string {
	if scope.selectAttrs == nil {
		attrs := []string{}
		for _, value := range scope.Search.selects {
			if str, ok := value.(string); ok {
				attrs = append(attrs, str)
			} else if strs, ok := value.([]string); ok {
				attrs = append(attrs, strs...)
			} else if strs, ok := value.([]interface{}); ok {
				for _, str := range strs {
					attrs = append(attrs, fmt.Sprintf("%v", str))
				}
			}
		}
		scope.selectAttrs = &attrs
	}
	return *scope.selectAttrs
}

func (scope *Scope) OmitAttrs() []string {
	return scope.Search.omits
}

func (scope *Scope) changeableDBColumn(column string) bool {
	selectAttrs := scope.SelectAttrs()
	omitAttrs := scope.OmitAttrs()

	if len(selectAttrs) > 0 {
		for _, attr := range selectAttrs {
			if column == ToDBName(attr) {
				return true
			}
		}
		return false
	}

	for _, attr := range omitAttrs {
		if column == ToDBName(attr) {
			return false
		}
	}
	return true
}

func (scope *Scope) changeableField(field *Field) bool {
	selectAttrs := scope.SelectAttrs()
	omitAttrs := scope.OmitAttrs()

	if len(selectAttrs) > 0 {
		for _, attr := range selectAttrs {
			if field.Name == attr || field.DBName == attr {
				return true
			}
		}
		return false
	}

	for _, attr := range omitAttrs {
		if field.Name == attr || field.DBName == attr {
			return false
		}
	}

	return !field.IsIgnored
}

func (scope *Scope) shouldSaveAssociations() bool {
	saveAssociations, ok := scope.Get("gorm:save_associations")
	if ok && !saveAssociations.(bool) {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"sort"
	"strings"
	"unicode/utf8"
)

func indexRuneStarting(str string, r rune, start int) int {
	idx := strings.IndexRune(str[start:], r)
	if idx == -1 {
		return -1
	}
	return idx + start
}

func allIndexRune(str string, r rune) []int {
	var allIndexRune []int
	for i, c := range str {
		if c == r {
			allIndexRune = append(allIndexRune, i)
		}
	}
	return allIndexRune
}

func findMatch(candidate string, query string) (Match, error) {
	var runePositions Match
	start := 0
	for _, r := range query {
		start = indexRuneStarting(candidate, r, start)
		if start == -1 {
			return nil, errors.New("No Match Found")
		}
		runePositions = append(runePositions, start)
		start += utf8.RuneLen(r)
	}
	return runePositions, nil
}

type Match []int

func (m Match) Length() int {
	return m[len(m)-1] - m[0] + 1
}

type matchSlice []Match

func (ms matchSlice) Len() int           { return len(ms) }
func (ms matchSlice) Swap(i, j int)      { ms[i], ms[j] = ms[j], ms[i] }
func (ms matchSlice) Less(i, j int) bool { return ms[i].Length() < ms[j].Length() }

func bestMatch(ms []Match) Match {
	sort.Sort(matchSlice(ms))
	return ms[0]
}

func Score(candidate, query string) float64 {
	if len(query) == 0 {
		return 1.0
	}
	if len(candidate) < len(query) {
		return 0.0
	}

	first, _ := utf8.DecodeRuneInString(query)
	firstQueryRunePositions := allIndexRune(candidate, first)

	var matches []Match
	for _, start := range firstQueryRunePositions {
		match, err := findMatch(candidate[start:], query)
		if err != nil {
			continue
		}
		matches = append(matches, match)
	}

	if len(matches) == 0 {
		return 0.0
	}

	best := bestMatch(matches)

	score := float64(best.Length())
	score = float64(len(query)) / score
	score = score / float64(len(candidate))

	return score
}
<commit_msg>Minor renaming of local function<commit_after>package main

import (
	"errors"
	"sort"
	"strings"
	"unicode/utf8"
)

func indexRuneStarting(str string, r rune, start int) int {
	idx := strings.IndexRune(str[start:], r)
	if idx == -1 {
		return -1
	}
	return idx + start
}

func indexesRune(str string, r rune) []int {
	var indexes []int
	for i, c := range str {
		if c == r {
			indexes = append(indexes, i)
		}
	}
	return indexes
}

func findMatch(candidate string, query string) (Match, error) {
	var runePositions Match
	start := 0
	for _, r := range query {
		start = indexRuneStarting(candidate, r, start)
		if start == -1 {
			return nil, errors.New("No Match Found")
		}
		runePositions = append(runePositions, start)
		start += utf8.RuneLen(r)
	}
	return runePositions, nil
}

type Match []int

func (m Match) Length() int {
	return m[len(m)-1] - m[0] + 1
}

type matchSlice []Match

func (ms matchSlice) Len() int           { return len(ms) }
func (ms matchSlice) Swap(i, j int)      { ms[i], ms[j] = ms[j], ms[i] }
func (ms matchSlice) Less(i, j int) bool { return ms[i].Length() < ms[j].Length() }

func bestMatch(ms []Match) Match {
	sort.Sort(matchSlice(ms))
	return ms[0]
}

func Score(candidate, query string) float64 {
	if len(query) == 0 {
		return 1.0
	}
	if len(candidate) < len(query) {
		return 0.0
	}

	first, _ := utf8.DecodeRuneInString(query)
	firstQueryRunePositions := indexesRune(candidate, first)

	var matches []Match
	for _, start := range firstQueryRunePositions {
		match, err := findMatch(candidate[start:], query)
		if err != nil {
			continue
		}
		matches = append(matches, match)
	}

	if len(matches) == 0 {
		return 0.0
	}

	best := bestMatch(matches)

	score := float64(best.Length())
	score = float64(len(query)) / score
	score = score / float64(len(candidate))

	return score
}
<|endoftext|>


<commit_before>package bignum

import (
	"encoding/json"
	"testing"

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

func TestInt_MarshalJSON(t *testing.T) {
	var x = NewInt(0x7fffffffffffffff).Mul(NewInt(0x7fffffffffffffff))

	data, err := json.Marshal(x)

	assert.NoError(t, err)
	assert.Equal(t, "85070591730234615847396907784232501249", string(data))
}

func TestInt_UnmarshalJSON(t *testing.T) {
	data := []byte(`85070591730234615847396907784232501249`)

	var x Int
	err := json.Unmarshal(data, &x)

	assert.NoError(t, err)
	assert.Equal(t, "85070591730234615847396907784232501249", x.String())
}

func TestInt_IsZero(t *testing.T) {
	var x Int
	var y = NewInt(2).Sub(NewInt(2))
	var z = NewInt(0)

	assert.True(t, x.IsZero())
	assert.True(t, y.IsZero())
	assert.True(t, z.IsZero())
}

func TestInt_Equal(t *testing.T) {
	var x = NewInt(123)
	var y = NewInt(123)
	var z Int

	assert.True(t, x.Equal(x))
	assert.True(t, x.Equal(y))
	assert.True(t, y.Equal(x))
	assert.True(t, z.Equal(Int{}))
	assert.True(t, z.Equal(NewInt(0)))
	assert.True(t, x.Sub(y).Equal(z))
	assert.Equal(t, x, y)
	assert.Equal(t, y, x)
}

func TestInt_Neg(t *testing.T) {
	var x = NewInt(123)

	y := x.Neg()

	assert.Equal(t, NewInt(123), x)
	assert.Equal(t, NewInt(-123), y)
}

func TestInt_Sign(t *testing.T) {
	var x Int
	var y = NewInt(42)
	var z = NewInt(-42)

	assert.Equal(t, 0, x.Sign())
	assert.Equal(t, +1, y.Sign())
	assert.Equal(t, -1, z.Sign())
}

func TestInt_Add(t *testing.T) {
	var x = NewInt(2)
	var y = NewInt(3)

	z := x.Add(y)

	assert.Equal(t, NewInt(2), x)
	assert.Equal(t, NewInt(3), y)
	assert.Equal(t, NewInt(5), z)
}

func TestInt_Mul(t *testing.T) {
	var x = NewInt(2)
	var y = NewInt(-3)

	z := x.Mul(y)

	assert.Equal(t, NewInt(2), x)
	assert.Equal(t, NewInt(-3), y)
	assert.Equal(t, NewInt(-6), z)
}

func TestInt_BinWrite(t *testing.T) {
	var x Int
	var y = NewInt(123456)

	data0 := bin.Encode(x)
	data1 := bin.Encode(y)

	assert.Equal(t, []byte{0}, data0)
	assert.Equal(t, bin.Encode(123456), data1)
}

func TestInt_BinRead(t *testing.T) {
	data := bin.Encode(-0x7fffffffffffffff)

	var x Int
	err := bin.Decode(data, &x)

	assert.NoError(t, err)
	assert.EqualValues(t, -0x7fffffffffffffff, x.Int64())
}
<commit_msg>fix tests<commit_after>package bignum

import (
	"encoding/json"
	"testing"

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

func TestInt_MarshalJSON(t *testing.T) {
	var x = NewInt(0x7fffffffffffffff).Mul(NewInt(0x7fffffffffffffff))

	data, err := json.Marshal(x)

	assert.NoError(t, err)
	assert.Equal(t, "85070591730234615847396907784232501249", string(data))
}

func TestInt_UnmarshalJSON(t *testing.T) {
	data := []byte(`85070591730234615847396907784232501249`)

	var x Int
	err := json.Unmarshal(data, &x)

	assert.NoError(t, err)
	assert.Equal(t, "85070591730234615847396907784232501249", x.String())
}

func TestInt_IsZero(t *testing.T) {
	var x Int
	var y = NewInt(2).Sub(NewInt(2))
	var z = NewInt(0)

	assert.True(t, x.IsZero())
	assert.True(t, y.IsZero())
	assert.True(t, z.IsZero())
}

func TestInt_Equal(t *testing.T) {
	var x = NewInt(123)
	var y = NewInt(123)
	var z Int

	assert.True(t, x.Equal(x))
	assert.True(t, x.Equal(y))
	assert.True(t, y.Equal(x))
	assert.True(t, z.Equal(Int{}))
	assert.True(t, z.Equal(NewInt(0)))
	assert.True(t, x.Sub(y).Equal(z))
	assert.Equal(t, x, y)
	assert.Equal(t, y, x)
}

func TestInt_Neg(t *testing.T) {
	var x = NewInt(123)

	y := x.Neg()

	assert.Equal(t, NewInt(123), x)
	assert.Equal(t, NewInt(-123), y)
}

func TestInt_Sign(t *testing.T) {
	var x Int
	var y = NewInt(42)
	var z = NewInt(-42)

	assert.Equal(t, 0, x.Sign())
	assert.Equal(t, +1, y.Sign())
	assert.Equal(t, -1, z.Sign())
}

func TestInt_Add(t *testing.T) {
	var x = NewInt(2)
	var y = NewInt(3)

	z := x.Add(y)

	assert.Equal(t, NewInt(2), x)
	assert.Equal(t, NewInt(3), y)
	assert.Equal(t, NewInt(5), z)
}

func TestInt_Mul(t *testing.T) {
	var x = NewInt(2)
	var y = NewInt(-3)

	z := x.Mul(y)

	assert.Equal(t, NewInt(2), x)
	assert.Equal(t, NewInt(-3), y)
	assert.Equal(t, NewInt(-6), z)
}

func TestInt_BinaryEncode(t *testing.T) {
	var x Int
	var y = NewInt(123456)

	data0 := bin.Encode(x)
	data1 := bin.Encode(y)

	assert.Equal(t, []byte{0}, data0)
	assert.Equal(t, bin.Encode(123456), data1)
}

func TestInt_BinaryDecode(t *testing.T) {
	data := bin.Encode(-0x7fffffffffffffff)

	var x Int
	err := bin.Decode(data, &x)

	assert.NoError(t, err)
	assert.EqualValues(t, -0x7fffffffffffffff, x.Int64())
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"strconv"
	"strings"
	"sync"
	"time"

	"bufio"
	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/all"
	"github.com/kidoman/embd/sensor/bmp180"
	"github.com/tarm/serial"

	"../mpu6050"
	"os"
)

type SituationData struct {
	mu_GPS *sync.Mutex

	// From GPS.
	lastFixSinceMidnightUTC uint32
	lat                     float32
	lng                     float32
	quality                 uint8
	satellites              uint16
	accuracy                float32 // Meters.
	alt                     float32 // Feet.
	alt_accuracy            float32
	lastFixLocalTime        time.Time
	trueCourse              uint16
	groundSpeed             uint16
	lastGroundTrackTime     time.Time

	mu_Attitude *sync.Mutex

	// From BMP180 pressure sensor.
	temp              float64
	pressure_alt      float64
	lastTempPressTime time.Time

	// From MPU6050 accel/gyro.
	pitch            float64
	roll             float64
	gyro_heading     float64
	lastAttitudeTime time.Time
}

var serialConfig *serial.Config
var serialPort *serial.Port

func initGPSSerial() bool {
	var device string
	if _, err := os.Stat("/dev/ttyACM0"); err == nil {
		device = "/dev/ttyACM0"
	} else {
		device = "/dev/ttyAMA0"
	}
	log.Printf("Using %s for GPS\n", device)
	serialConfig = &serial.Config{Name: device, Baud: 9600}
	p, err := serial.OpenPort(serialConfig)
	if err != nil {
		log.Printf("serial port err: %s\n", err.Error())
		return false
	}
	serialPort = p
	return true
}

func processNMEALine(l string) bool {
	x := strings.Split(l, ",")
	if x[0] == "$GNVTG" { // Ground track information.
		mySituation.mu_GPS.Lock()
		defer mySituation.mu_GPS.Unlock()
		if len(x) < 10 {
			return false
		}
		trueCourse := uint16(0)
		if len(x[1]) > 0 {
			tc, err := strconv.ParseFloat(x[1], 32)
			if err != nil {
				return false
			}
			trueCourse = uint16(tc)
			//FIXME: Experimental. Set heading to true heading on the MPU6050 reader.
			if myMPU6050 != nil && globalStatus.RY835AI_connected && globalSettings.AHRS_Enabled {
				myMPU6050.ResetHeading(float64(tc))
			}
		} else {
			// No movement.
			mySituation.trueCourse = 0
			mySituation.groundSpeed = 0
			mySituation.lastGroundTrackTime = time.Time{}
			return true
		}
		groundSpeed, err := strconv.ParseFloat(x[5], 32) // Knots.
		if err != nil {
			return false
		}

		mySituation.trueCourse = uint16(trueCourse)
		mySituation.groundSpeed = uint16(groundSpeed)
		mySituation.lastGroundTrackTime = time.Now()

	} else if x[0] == "$GNGGA" { // GPS fix.
		if len(x) < 15 {
			return false
		}
		mySituation.mu_GPS.Lock()
		defer mySituation.mu_GPS.Unlock()
		// Timestamp.
		if len(x[1]) < 9 {
			return false
		}
		hr, err1 := strconv.Atoi(x[1][0:2])
		min, err2 := strconv.Atoi(x[1][2:4])
		sec, err3 := strconv.Atoi(x[1][4:6])
		if err1 != nil || err2 != nil || err3 != nil {
			return false
		}

		mySituation.lastFixSinceMidnightUTC = uint32((hr * 60 * 60) + (min * 60) + sec)

		// Latitude.
		if len(x[2]) < 10 {
			return false
		}
		hr, err1 = strconv.Atoi(x[2][0:2])
		minf, err2 := strconv.ParseFloat(x[2][2:10], 32)
		if err1 != nil || err2 != nil {
			return false
		}

		mySituation.lat = float32(hr) + float32(minf/60.0)
		if x[3] == "S" { // South = negative.
			mySituation.lat = -mySituation.lat
		}

		// Longitude.
		if len(x[4]) < 11 {
			return false
		}
		hr, err1 = strconv.Atoi(x[4][0:3])
		minf, err2 = strconv.ParseFloat(x[4][3:11], 32)
		if err1 != nil || err2 != nil {
			return false
		}

		mySituation.lng = float32(hr) + float32(minf/60.0)
		if x[5] == "W" { // West = negative.
			mySituation.lng = -mySituation.lng
		}

		// Quality indicator.
		q, err1 := strconv.Atoi(x[6])
		if err1 != nil {
			return false
		}
		mySituation.quality = uint8(q)

		// Satellites.
		sat, err1 := strconv.Atoi(x[7])
		if err1 != nil {
			return false
		}
		mySituation.satellites = uint16(sat)

		// Accuracy.
		hdop, err1 := strconv.ParseFloat(x[8], 32)
		if err1 != nil {
			return false
		}
		mySituation.accuracy = float32(hdop * 5.0) //FIXME: 5 meters ~ 1.0 HDOP?

		// Altitude.
		alt, err1 := strconv.ParseFloat(x[9], 32)
		if err1 != nil {
			return false
		}
		mySituation.alt = float32(alt * 3.28084) // Covnert to feet.

		//TODO: Altitude accuracy.
		mySituation.alt_accuracy = 0

		// Timestamp.
		mySituation.lastFixLocalTime = time.Now()

	}
	return true
}

func gpsSerialReader() {
	defer serialPort.Close()
	for globalSettings.GPS_Enabled && globalStatus.GPS_connected {

		scanner := bufio.NewScanner(serialPort)
		for scanner.Scan() {
			s := scanner.Text()
			// log.Printf("Output: %s\n", s)
			processNMEALine(s)
		}
		if err := scanner.Err(); err != nil {
			log.Printf("reading standard input: %s\n", err.Error())
		}
	}
	globalStatus.GPS_connected = false
}

var i2cbus embd.I2CBus
var myBMP180 *bmp180.BMP180
var myMPU6050 *mpu6050.MPU6050

func readBMP180() (float64, float64, error) { // ºCelsius, Meters
	temp, err := myBMP180.Temperature()
	if err != nil {
		return temp, 0.0, err
	}
	altitude, err := myBMP180.Altitude()
	altitude = float64(1/0.3048) * altitude // Convert meters to feet.
	if err != nil {
		return temp, altitude, err
	}
	return temp, altitude, nil
}

func readMPU6050() (float64, float64, error) { //TODO: error checking.
	pitch, roll := myMPU6050.PitchAndRoll()
	return pitch, roll, nil
}

func initBMP180() error {
	myBMP180 = bmp180.New(i2cbus) //TODO: error checking.
	return nil
}

func initMPU6050() error {
	myMPU6050 = mpu6050.New(i2cbus) //TODO: error checking.
	return nil
}

func initI2C() error {
	i2cbus = embd.NewI2CBus(1) //TODO: error checking.
	return nil
}

// Unused at the moment. 5 second update, since read functions in bmp180 are slow.
func tempAndPressureReader() {
	timer := time.NewTicker(5 * time.Second)
	for globalStatus.RY835AI_connected && globalSettings.AHRS_Enabled {
		<-timer.C
		// Read temperature and pressure altitude.
		temp, alt, err_bmp180 := readBMP180()
		// Process.
		if err_bmp180 != nil {
			log.Printf("readBMP180(): %s\n", err_bmp180.Error())
			globalStatus.RY835AI_connected = false
		} else {
			mySituation.temp = temp
			mySituation.pressure_alt = alt
			mySituation.lastTempPressTime = time.Now()
		}
	}
	globalStatus.RY835AI_connected = false
}

func makeFFAHRSSimReport() {
	s := fmt.Sprintf("XATTStratux,%f,%f,%f", mySituation.gyro_heading, mySituation.pitch, mySituation.roll)

	sendMsg([]byte(s), NETWORK_AHRS_FFSIM, false)
}

func makeAHRSGDL90Report() {
	msg := make([]byte, 16)
	msg[0] = 0x4c
	msg[1] = 0x45
	msg[2] = 0x01
	msg[3] = 0x00

	pitch := int16(float64(mySituation.pitch) * float64(10.0))
	roll := int16(float64(mySituation.roll) * float64(10.0))
	hdg := uint16(float64(mySituation.gyro_heading) * float64(10.0)) //TODO.
	slip_skid := int16(float64(0) * float64(10.0))                   //TODO.
	yaw_rate := int16(float64(0) * float64(10.0))                    //TODO.
	g := int16(float64(1.0) * float64(10.0))                         //TODO.

	// Roll.
	msg[4] = byte((roll >> 8) & 0xFF)
	msg[5] = byte(roll & 0xFF)

	// Pitch.
	msg[6] = byte((pitch >> 8) & 0xFF)
	msg[7] = byte(pitch & 0xFF)

	// Heading.
	msg[8] = byte((hdg >> 8) & 0xFF)
	msg[9] = byte(hdg & 0xFF)

	// Slip/skid.
	msg[10] = byte((slip_skid >> 8) & 0xFF)
	msg[11] = byte(slip_skid & 0xFF)

	// Yaw rate.
	msg[12] = byte((yaw_rate >> 8) & 0xFF)
	msg[13] = byte(yaw_rate & 0xFF)

	// "G".
	msg[14] = byte((g >> 8) & 0xFF)
	msg[15] = byte(g & 0xFF)

	sendMsg(prepareMessage(msg), NETWORK_AHRS_GDL90, false)
}

func attitudeReaderSender() {
	timer := time.NewTicker(100 * time.Millisecond) // ~10Hz update.
	for globalStatus.RY835AI_connected && globalSettings.AHRS_Enabled {
		<-timer.C
		// Read pitch and roll.
		pitch, roll, err_mpu6050 := readMPU6050()

		mySituation.mu_Attitude.Lock()

		if err_mpu6050 != nil {
			log.Printf("readMPU6050(): %s\n", err_mpu6050.Error())
			globalStatus.RY835AI_connected = false
			break
		} else {
			mySituation.pitch = pitch
			mySituation.roll = roll
			mySituation.gyro_heading = myMPU6050.Heading() //FIXME. Experimental.
			mySituation.lastAttitudeTime = time.Now()
		}

		// Send, if valid.
		//		if isGPSGroundTrackValid(), etc.

		makeFFAHRSSimReport()
		makeAHRSGDL90Report()

		mySituation.mu_Attitude.Unlock()
	}
	globalStatus.RY835AI_connected = false
}

func isGPSValid() bool {
	return time.Since(mySituation.lastFixLocalTime).Seconds() < 15
}

func isGPSGroundTrackValid() bool {
	return time.Since(mySituation.lastGroundTrackTime).Seconds() < 15
}

func isAHRSValid() bool {
	return time.Since(mySituation.lastAttitudeTime).Seconds() < 1 // If attitude information gets to be over 1 second old, declare invalid.
}

func isTempPressValid() bool {
	return time.Since(mySituation.lastTempPressTime).Seconds() < 15
}

func initAHRS() error {
	if err := initI2C(); err != nil { // I2C bus.
		return err
	}
	if err := initBMP180(); err != nil { // I2C temperature and pressure altitude.
		i2cbus.Close()
		return err
	}
	if err := initMPU6050(); err != nil { // I2C accel/gyro.
		i2cbus.Close()
		myBMP180.Close()
		return err
	}
	globalStatus.RY835AI_connected = true
	go attitudeReaderSender()
	go tempAndPressureReader()

	return nil
}

func pollRY835AI() {
	timer := time.NewTicker(10 * time.Second)
	for {
		<-timer.C
		// GPS enabled, was not connected previously?
		if globalSettings.GPS_Enabled && !globalStatus.GPS_connected {
			globalStatus.GPS_connected = initGPSSerial() // via USB for now.
			if globalStatus.GPS_connected {
				go gpsSerialReader()
			}
		}
		// RY835AI I2C enabled, was not connected previously?
		if globalSettings.AHRS_Enabled && !globalStatus.RY835AI_connected {
			err := initAHRS()
			if err != nil {
				log.Printf("initAHRS(): %s\ndisabling AHRS sensors.\n", err.Error())
				globalStatus.RY835AI_connected = false
			}
		}
	}
}

func initRY835AI() {
	mySituation.mu_GPS = &sync.Mutex{}
	mySituation.mu_Attitude = &sync.Mutex{}

	go pollRY835AI()
}
<commit_msg>GPS only RY835AI support.<commit_after>package main

import (
	"fmt"
	"log"
	"strconv"
	"strings"
	"sync"
	"time"

	"bufio"
	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/all"
	"github.com/kidoman/embd/sensor/bmp180"
	"github.com/tarm/serial"

	"../mpu6050"
	"os"
)

type SituationData struct {
	mu_GPS *sync.Mutex

	// From GPS.
	lastFixSinceMidnightUTC uint32
	lat                     float32
	lng                     float32
	quality                 uint8
	satellites              uint16
	accuracy                float32 // Meters.
	alt                     float32 // Feet.
	alt_accuracy            float32
	lastFixLocalTime        time.Time
	trueCourse              uint16
	groundSpeed             uint16
	lastGroundTrackTime     time.Time

	mu_Attitude *sync.Mutex

	// From BMP180 pressure sensor.
	temp              float64
	pressure_alt      float64
	lastTempPressTime time.Time

	// From MPU6050 accel/gyro.
	pitch            float64
	roll             float64
	gyro_heading     float64
	lastAttitudeTime time.Time
}

var serialConfig *serial.Config
var serialPort *serial.Port

func initGPSSerial() bool {
	var device string
	if _, err := os.Stat("/dev/ttyACM0"); err == nil {
		device = "/dev/ttyACM0"
	} else {
		device = "/dev/ttyAMA0"
	}
	log.Printf("Using %s for GPS\n", device)
	serialConfig = &serial.Config{Name: device, Baud: 9600}
	p, err := serial.OpenPort(serialConfig)
	if err != nil {
		log.Printf("serial port err: %s\n", err.Error())
		return false
	}
	serialPort = p
	return true
}

func processNMEALine(l string) bool {
	x := strings.Split(l, ",")
	if (x[0] == "$GNVTG") || (x[0] == "$GPVTG") { // Ground track information.
		mySituation.mu_GPS.Lock()
		defer mySituation.mu_GPS.Unlock()
		if len(x) < 10 {
			return false
		}
		trueCourse := uint16(0)
		if len(x[1]) > 0 {
			tc, err := strconv.ParseFloat(x[1], 32)
			if err != nil {
				return false
			}
			trueCourse = uint16(tc)
			//FIXME: Experimental. Set heading to true heading on the MPU6050 reader.
			if myMPU6050 != nil && globalStatus.RY835AI_connected && globalSettings.AHRS_Enabled {
				myMPU6050.ResetHeading(float64(tc))
			}
		} else {
			// No movement.
			mySituation.trueCourse = 0
			mySituation.groundSpeed = 0
			mySituation.lastGroundTrackTime = time.Time{}
			return true
		}
		groundSpeed, err := strconv.ParseFloat(x[5], 32) // Knots.
		if err != nil {
			return false
		}

		mySituation.trueCourse = uint16(trueCourse)
		mySituation.groundSpeed = uint16(groundSpeed)
		mySituation.lastGroundTrackTime = time.Now()

	} else if (x[0] == "$GNGGA") || (x[0] == "$GPGGA") { // GPS fix.
		if len(x) < 15 {
			return false
		}
		mySituation.mu_GPS.Lock()
		defer mySituation.mu_GPS.Unlock()
		// Timestamp.
		if len(x[1]) < 9 {
			return false
		}
		hr, err1 := strconv.Atoi(x[1][0:2])
		min, err2 := strconv.Atoi(x[1][2:4])
		sec, err3 := strconv.Atoi(x[1][4:6])
		if err1 != nil || err2 != nil || err3 != nil {
			return false
		}

		mySituation.lastFixSinceMidnightUTC = uint32((hr * 60 * 60) + (min * 60) + sec)

		// Latitude.
		if len(x[2]) < 10 {
			return false
		}

		hr, err1 = strconv.Atoi(x[2][0:2])
		minf, err2 := strconv.ParseFloat(x[2][2:10], 32)
		if err1 != nil || err2 != nil {
			return false
		}

		mySituation.lat = float32(hr) + float32(minf/60.0)
		if x[3] == "S" { // South = negative.
			mySituation.lat = -mySituation.lat
		}

		// Longitude.
		if len(x[4]) < 11 {
			return false
		}
		hr, err1 = strconv.Atoi(x[4][0:3])
		minf, err2 = strconv.ParseFloat(x[4][3:11], 32)
		if err1 != nil || err2 != nil {
			return false
		}

		mySituation.lng = float32(hr) + float32(minf/60.0)
		if x[5] == "W" { // West = negative.
			mySituation.lng = -mySituation.lng
		}

		// Quality indicator.
		q, err1 := strconv.Atoi(x[6])
		if err1 != nil {
			return false
		}
		mySituation.quality = uint8(q)

		// Satellites.
		sat, err1 := strconv.Atoi(x[7])
		if err1 != nil {
			return false
		}
		mySituation.satellites = uint16(sat)

		// Accuracy.
		hdop, err1 := strconv.ParseFloat(x[8], 32)
		if err1 != nil {
			return false
		}
		mySituation.accuracy = float32(hdop * 5.0) //FIXME: 5 meters ~ 1.0 HDOP?

		// Altitude.
		alt, err1 := strconv.ParseFloat(x[9], 32)
		if err1 != nil {
			return false
		}
		mySituation.alt = float32(alt * 3.28084) // Convert to feet.

		//TODO: Altitude accuracy.
		mySituation.alt_accuracy = 0

		// Timestamp.
		mySituation.lastFixLocalTime = time.Now()

	}
	return true
}

func gpsSerialReader() {
	defer serialPort.Close()
	for globalSettings.GPS_Enabled && globalStatus.GPS_connected {

		scanner := bufio.NewScanner(serialPort)
		for scanner.Scan() {
			s := scanner.Text()
			// log.Printf("Output: %s\n", s)
			processNMEALine(s)
		}
		if err := scanner.Err(); err != nil {
			log.Printf("reading standard input: %s\n", err.Error())
		}
	}
	globalStatus.GPS_connected = false
}

var i2cbus embd.I2CBus
var myBMP180 *bmp180.BMP180
var myMPU6050 *mpu6050.MPU6050

func readBMP180() (float64, float64, error) { // ºCelsius, Meters
	temp, err := myBMP180.Temperature()
	if err != nil {
		return temp, 0.0, err
	}
	altitude, err := myBMP180.Altitude()
	altitude = float64(1/0.3048) * altitude // Convert meters to feet.
	if err != nil {
		return temp, altitude, err
	}
	return temp, altitude, nil
}

func readMPU6050() (float64, float64, error) { //TODO: error checking.
	pitch, roll := myMPU6050.PitchAndRoll()
	return pitch, roll, nil
}

func initBMP180() error {
	myBMP180 = bmp180.New(i2cbus) //TODO: error checking.
	return nil
}

func initMPU6050() error {
	myMPU6050 = mpu6050.New(i2cbus) //TODO: error checking.
	return nil
}

func initI2C() error {
	i2cbus = embd.NewI2CBus(1) //TODO: error checking.
	return nil
}

// Unused at the moment. 5 second update, since read functions in bmp180 are slow.
func tempAndPressureReader() {
	timer := time.NewTicker(5 * time.Second)
	for globalStatus.RY835AI_connected && globalSettings.AHRS_Enabled {
		<-timer.C
		// Read temperature and pressure altitude.
		temp, alt, err_bmp180 := readBMP180()
		// Process.
		if err_bmp180 != nil {
			log.Printf("readBMP180(): %s\n", err_bmp180.Error())
			globalStatus.RY835AI_connected = false
		} else {
			mySituation.temp = temp
			mySituation.pressure_alt = alt
			mySituation.lastTempPressTime = time.Now()
		}
	}
	globalStatus.RY835AI_connected = false
}

func makeFFAHRSSimReport() {
	s := fmt.Sprintf("XATTStratux,%f,%f,%f", mySituation.gyro_heading, mySituation.pitch, mySituation.roll)

	sendMsg([]byte(s), NETWORK_AHRS_FFSIM, false)
}

func makeAHRSGDL90Report() {
	msg := make([]byte, 16)
	msg[0] = 0x4c
	msg[1] = 0x45
	msg[2] = 0x01
	msg[3] = 0x00

	pitch := int16(float64(mySituation.pitch) * float64(10.0))
	roll := int16(float64(mySituation.roll) * float64(10.0))
	hdg := uint16(float64(mySituation.gyro_heading) * float64(10.0)) //TODO.
	slip_skid := int16(float64(0) * float64(10.0))                   //TODO.
	yaw_rate := int16(float64(0) * float64(10.0))                    //TODO.
	g := int16(float64(1.0) * float64(10.0))                         //TODO.

	// Roll.
	msg[4] = byte((roll >> 8) & 0xFF)
	msg[5] = byte(roll & 0xFF)

	// Pitch.
	msg[6] = byte((pitch >> 8) & 0xFF)
	msg[7] = byte(pitch & 0xFF)

	// Heading.
	msg[8] = byte((hdg >> 8) & 0xFF)
	msg[9] = byte(hdg & 0xFF)

	// Slip/skid.
	msg[10] = byte((slip_skid >> 8) & 0xFF)
	msg[11] = byte(slip_skid & 0xFF)

	// Yaw rate.
	msg[12] = byte((yaw_rate >> 8) & 0xFF)
	msg[13] = byte(yaw_rate & 0xFF)

	// "G".
	msg[14] = byte((g >> 8) & 0xFF)
	msg[15] = byte(g & 0xFF)

	sendMsg(prepareMessage(msg), NETWORK_AHRS_GDL90, false)
}

func attitudeReaderSender() {
	timer := time.NewTicker(100 * time.Millisecond) // ~10Hz update.
	for globalStatus.RY835AI_connected && globalSettings.AHRS_Enabled {
		<-timer.C
		// Read pitch and roll.
		pitch, roll, err_mpu6050 := readMPU6050()

		mySituation.mu_Attitude.Lock()

		if err_mpu6050 != nil {
			log.Printf("readMPU6050(): %s\n", err_mpu6050.Error())
			globalStatus.RY835AI_connected = false
			break
		} else {
			mySituation.pitch = pitch
			mySituation.roll = roll
			mySituation.gyro_heading = myMPU6050.Heading() //FIXME. Experimental.
			mySituation.lastAttitudeTime = time.Now()
		}

		// Send, if valid.
		//		if isGPSGroundTrackValid(), etc.

		makeFFAHRSSimReport()
		makeAHRSGDL90Report()

		mySituation.mu_Attitude.Unlock()
	}
	globalStatus.RY835AI_connected = false
}

func isGPSValid() bool {
	return time.Since(mySituation.lastFixLocalTime).Seconds() < 15
}

func isGPSGroundTrackValid() bool {
	return time.Since(mySituation.lastGroundTrackTime).Seconds() < 15
}

func isAHRSValid() bool {
	return time.Since(mySituation.lastAttitudeTime).Seconds() < 1 // If attitude information gets to be over 1 second old, declare invalid.
}

func isTempPressValid() bool {
	return time.Since(mySituation.lastTempPressTime).Seconds() < 15
}

func initAHRS() error {
	if err := initI2C(); err != nil { // I2C bus.
		return err
	}
	if err := initBMP180(); err != nil { // I2C temperature and pressure altitude.
		i2cbus.Close()
		return err
	}
	if err := initMPU6050(); err != nil { // I2C accel/gyro.
		i2cbus.Close()
		myBMP180.Close()
		return err
	}
	globalStatus.RY835AI_connected = true
	go attitudeReaderSender()
	go tempAndPressureReader()

	return nil
}

func pollRY835AI() {
	timer := time.NewTicker(10 * time.Second)
	for {
		<-timer.C
		// GPS enabled, was not connected previously?
		if globalSettings.GPS_Enabled && !globalStatus.GPS_connected {
			globalStatus.GPS_connected = initGPSSerial() // via USB for now.
			if globalStatus.GPS_connected {
				go gpsSerialReader()
			}
		}
		// RY835AI I2C enabled, was not connected previously?
		if globalSettings.AHRS_Enabled && !globalStatus.RY835AI_connected {
			err := initAHRS()
			if err != nil {
				log.Printf("initAHRS(): %s\ndisabling AHRS sensors.\n", err.Error())
				globalStatus.RY835AI_connected = false
			}
		}
	}
}

func initRY835AI() {
	mySituation.mu_GPS = &sync.Mutex{}
	mySituation.mu_Attitude = &sync.Mutex{}

	go pollRY835AI()
}
<|endoftext|>


<commit_before>package xpra

import (
	"errors"
	"fmt"
	"github.com/subgraph/oz"
	"os"
	"os/exec"
	"os/user"
	"path"
	"strconv"
	"syscall"
)

type Xpra struct {
	// Server working directory where unix socket is created
	WorkDir string

	Config *oz.XServerConf

	// Running xpra process
	Process *exec.Cmd

	// Display number
	Display uint64

	// Arguments passed to xpra command
	xpraArgs []string
}

var xpraDefaultArgs = []string{
	"--no-daemon",
	"--mmap",
	"--no-sharing",
	"--bell",
	"--system-tray",
	"--xsettings",
	//"--no-xsettings",
	"--cursors",
	"--encoding=rgb",
	"--no-pulseaudio",
}

func getDefaultArgs(config *oz.XServerConf) []string {
	args := []string{}
	args = append(args, xpraDefaultArgs...)
	if config.DisableClipboard {
		args = append(args, "--no-clipboard")
	} else {
		args = append(args, "--clipboard")
	}

	switch config.AudioMode {
	case oz.PROFILE_AUDIO_NONE, "":
		args = append(args, "--no-microphone", "--no-speaker")
	case oz.PROFILE_AUDIO_SPEAKER:
		args = append(args, "--no-microphone", "--speaker")
	case oz.PROFILE_AUDIO_FULL:
		args = append(args, "--microphone", "--speaker")
	}

	if config.EnableNotifications {
		args = append(args, "--notifications")
	} else {
		args = append(args, "--no-notifications")

	return args
}

func (x *Xpra) Stop(cred *syscall.Credential) ([]byte, error) {
	cmd := exec.Command("/usr/bin/xpra",
		"--socket-dir="+x.WorkDir,
		"stop",
		fmt.Sprintf(":%d", x.Display),
	)
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Credential: cred,
	}
	cmd.Env = []string{"TMPDIR=" + x.WorkDir}
	return cmd.Output()
}

func GetPath(u *user.User, name string) string {
	return path.Join(u.HomeDir, ".Xoz", name)
}

func CreateDir(u *user.User, name string) (string, error) {
	uid, gid, err := userIds(u)
	if err != nil {
		return "", err
	}
	dir := GetPath(u, name)
	if err := createSubdirs(u.HomeDir, uid, gid, 0755, ".Xoz", name); err != nil {
		return "", fmt.Errorf("failed to create xpra directory (%s): %v", dir, err)
	}
	return dir, nil
}

func createSubdirs(base string, uid, gid int, mode os.FileMode, subdirs ...string) error {
	dir := base
	for _, sd := range subdirs {
		dir = path.Join(dir, sd)
		if err := os.Mkdir(dir, mode); err != nil && !os.IsExist(err) {
			return err
		}
		if err := os.Chown(dir, uid, gid); err != nil {
			return err
		}
	}
	return nil
}

func userIds(user *user.User) (int, int, error) {
	uid, err := strconv.Atoi(user.Uid)
	if err != nil {
		return -1, -1, errors.New("failed to parse uid from user struct: " + err.Error())
	}
	gid, err := strconv.Atoi(user.Gid)
	if err != nil {
		return -1, -1, errors.New("failed to parse gid from user struct: " + err.Error())
	}
	return uid, gid, nil
}
<commit_msg>Wooops<commit_after>package xpra

import (
	"errors"
	"fmt"
	"github.com/subgraph/oz"
	"os"
	"os/exec"
	"os/user"
	"path"
	"strconv"
	"syscall"
)

type Xpra struct {
	// Server working directory where unix socket is created
	WorkDir string

	Config *oz.XServerConf

	// Running xpra process
	Process *exec.Cmd

	// Display number
	Display uint64

	// Arguments passed to xpra command
	xpraArgs []string
}

var xpraDefaultArgs = []string{
	"--no-daemon",
	"--mmap",
	"--no-sharing",
	"--bell",
	"--system-tray",
	"--xsettings",
	//"--no-xsettings",
	"--cursors",
	"--encoding=rgb",
	"--no-pulseaudio",
}

func getDefaultArgs(config *oz.XServerConf) []string {
	args := []string{}
	args = append(args, xpraDefaultArgs...)
	if config.DisableClipboard {
		args = append(args, "--no-clipboard")
	} else {
		args = append(args, "--clipboard")
	}

	switch config.AudioMode {
	case oz.PROFILE_AUDIO_NONE, "":
		args = append(args, "--no-microphone", "--no-speaker")
	case oz.PROFILE_AUDIO_SPEAKER:
		args = append(args, "--no-microphone", "--speaker")
	case oz.PROFILE_AUDIO_FULL:
		args = append(args, "--microphone", "--speaker")
	}

	if config.EnableNotifications {
		args = append(args, "--notifications")
	} else {
		args = append(args, "--no-notifications")
	}

	return args
}

func (x *Xpra) Stop(cred *syscall.Credential) ([]byte, error) {
	cmd := exec.Command("/usr/bin/xpra",
		"--socket-dir="+x.WorkDir,
		"stop",
		fmt.Sprintf(":%d", x.Display),
	)
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Credential: cred,
	}
	cmd.Env = []string{"TMPDIR=" + x.WorkDir}
	return cmd.Output()
}

func GetPath(u *user.User, name string) string {
	return path.Join(u.HomeDir, ".Xoz", name)
}

func CreateDir(u *user.User, name string) (string, error) {
	uid, gid, err := userIds(u)
	if err != nil {
		return "", err
	}
	dir := GetPath(u, name)
	if err := createSubdirs(u.HomeDir, uid, gid, 0755, ".Xoz", name); err != nil {
		return "", fmt.Errorf("failed to create xpra directory (%s): %v", dir, err)
	}
	return dir, nil
}

func createSubdirs(base string, uid, gid int, mode os.FileMode, subdirs ...string) error {
	dir := base
	for _, sd := range subdirs {
		dir = path.Join(dir, sd)
		if err := os.Mkdir(dir, mode); err != nil && !os.IsExist(err) {
			return err
		}
		if err := os.Chown(dir, uid, gid); err != nil {
			return err
		}
	}
	return nil
}

func userIds(user *user.User) (int, int, error) {
	uid, err := strconv.Atoi(user.Uid)
	if err != nil {
		return -1, -1, errors.New("failed to parse uid from user struct: " + err.Error())
	}
	gid, err := strconv.Atoi(user.Gid)
	if err != nil {
		return -1, -1, errors.New("failed to parse gid from user struct: " + err.Error())
	}
	return uid, gid, nil
}
<|endoftext|>