<commit_before>package agent

import (
	"path"
	"sync"

	log "github.com/coreos/fleet/third_party/github.com/golang/glog"

	"github.com/coreos/fleet/job"
)

type AgentState struct {
	// used to lock the datastructure for multi-goroutine safety
	mutex	sync.Mutex

	// unresolved job offers
	offers	map[string]job.JobOffer

	// job names for which a bid has been submitted
	bids	[]string

	// reverse index of peers that would cause a reassesment of a JobOffer this
	// Agent could not have bid on previously
	// i.e. {"hello.service": ["howareyou.service", "goodbye.service"]}
	peers	map[string][]string

	// index of local payload conflicts to the job they belong to
	conflicts	map[string][]string
}

func NewState() *AgentState {
	return &AgentState{
		offers:		make(map[string]job.JobOffer),
		bids:		make([]string, 0),
		peers:		make(map[string][]string),
		conflicts:	make(map[string][]string, 0),
	}
}

func (self *AgentState) Lock() {
	log.V(2).Infof("Attempting to lock AgentState")
	self.mutex.Lock()
	log.V(2).Infof("AgentState locked")
}

func (self *AgentState) Unlock() {
	log.V(2).Infof("Attempting to unlock AgentState")
	self.mutex.Unlock()
	log.V(2).Infof("AgentState unlocked")
}

// Store a list of conflicts on behalf of a given Job
func (self *AgentState) TrackJobConflicts(jobName string, conflicts []string) {
	self.conflicts[jobName] = conflicts
}

// Determine whether there are any known conflicts with the given argument
func (self *AgentState) HasConflict(potentialJobName string, potentialConflicts []string) (bool, string) {
	// Iterate through each existing Job, asserting two things:
	for existingJobName, existingConflicts := range self.conflicts {

		// 1. Each tracked Job does not conflict with the potential conflicts
		for _, pc := range potentialConflicts {
			if globMatches(pc, existingJobName) {
				return true, existingJobName
			}
		}

		// 2. The new Job does not conflict with any of the tracked confclits
		for _, ec := range existingConflicts {
			if globMatches(ec, potentialJobName) {
				return true, existingJobName
			}
		}
	}

	return false, ""
}

// Purge all tracked conflicts for a given Job
func (self *AgentState) DropJobConflicts(jobName string) {
	delete(self.conflicts, jobName)
}

// Store a relation of 1 Job -> N Peers
func (self *AgentState) TrackJobPeers(jobName string, peers []string) {
	for _, peer := range peers {
		_, ok := self.peers[peer]
		if !ok {
			self.peers[peer] = make([]string, 0)
		}
		self.peers[peer] = append(self.peers[peer], jobName)
	}
}

// Retrieve all Jobs that share a given Peer
func (self *AgentState) GetJobsByPeer(peerName string) []string {
	peers, ok := self.peers[peerName]
	if ok {
		return peers
	} else {
		return make([]string, 0)
	}
}

// Remove all references to a given Job from all Peer indexes
func (self *AgentState) DropPeersJob(jobName string) {
	for peer, peerIndex := range self.peers {
		var idxs []int

		// Determine which item indexes must be removed from the Peer index
		for idx, record := range peerIndex {
			if jobName == record {
				idxs = append(idxs, idx)
			}
		}

		// Iterate through the item indexes, removing the corresponding Peers
		for i, idx := range idxs {
			self.peers[peer] = append(self.peers[peer][0:idx-i], self.peers[peer][idx-i:]...)
		}
	}
}

func (self *AgentState) TrackOffer(offer job.JobOffer) {
	self.offers[offer.Job.Name] = offer
}

func (self *AgentState) GetBadeOffers() []job.JobOffer {
	offers := make([]job.JobOffer, 0)
	for _, offer := range self.offers {
		if self.HasBid(offer.Job.Name) {
			offers = append(offers, offer)
		}
	}
	return offers
}

// GetOffersWithoutBids returns all tracked JobOffers that have
// no corresponding JobBid tracked in the same AgentState object.
func (self *AgentState) GetOffersWithoutBids() []job.JobOffer {
	offers := make([]job.JobOffer, 0)
	for _, offer := range self.offers {
		if !self.HasBid(offer.Job.Name) {
			offers = append(offers, offer)
		}
	}
	return offers
}

func (self *AgentState) GetOffer(name string) (job.JobOffer, bool) {
	offer, ok := self.offers[name]
	return offer, ok
}

func (self *AgentState) DropOffer(name string) {
	if _, ok := self.offers[name]; !ok {
		log.V(2).Infof("AgentState knows nothing of JobOffer(%s)", name)
		return
	}

	delete(self.offers, name)
}

func (self *AgentState) TrackBid(name string) {
	self.bids = append(self.bids, name)
}

func (self *AgentState) HasBid(name string) bool {
	for _, val := range self.bids {
		if val == name {
			return true
		}
	}
	return false
}

func (self *AgentState) DropBid(name string) {
	for idx, val := range self.bids {
		if val == name {
			self.bids = append(self.bids[0:idx], self.bids[idx+1:]...)
			return
		}
	}
}

func globMatches(pattern, target string) bool {
	matched, err := path.Match(pattern, target)
	if err != nil {
		log.V(2).Infof("Received error while matching pattern '%s': %v", pattern, err)
	}
	return matched
}
<commit_msg>refactor(AgentState): Drop unused method GetBadeOffers<commit_after>package agent

import (
	"path"
	"sync"

	log "github.com/coreos/fleet/third_party/github.com/golang/glog"

	"github.com/coreos/fleet/job"
)

type AgentState struct {
	// used to lock the datastructure for multi-goroutine safety
	mutex	sync.Mutex

	// unresolved job offers
	offers	map[string]job.JobOffer

	// job names for which a bid has been submitted
	bids	[]string

	// reverse index of peers that would cause a reassesment of a JobOffer this
	// Agent could not have bid on previously
	// i.e. {"hello.service": ["howareyou.service", "goodbye.service"]}
	peers	map[string][]string

	// index of local payload conflicts to the job they belong to
	conflicts	map[string][]string
}

func NewState() *AgentState {
	return &AgentState{
		offers:		make(map[string]job.JobOffer),
		bids:		make([]string, 0),
		peers:		make(map[string][]string),
		conflicts:	make(map[string][]string, 0),
	}
}

func (self *AgentState) Lock() {
	log.V(2).Infof("Attempting to lock AgentState")
	self.mutex.Lock()
	log.V(2).Infof("AgentState locked")
}

func (self *AgentState) Unlock() {
	log.V(2).Infof("Attempting to unlock AgentState")
	self.mutex.Unlock()
	log.V(2).Infof("AgentState unlocked")
}

// Store a list of conflicts on behalf of a given Job
func (self *AgentState) TrackJobConflicts(jobName string, conflicts []string) {
	self.conflicts[jobName] = conflicts
}

// Determine whether there are any known conflicts with the given argument
func (self *AgentState) HasConflict(potentialJobName string, potentialConflicts []string) (bool, string) {
	// Iterate through each existing Job, asserting two things:
	for existingJobName, existingConflicts := range self.conflicts {

		// 1. Each tracked Job does not conflict with the potential conflicts
		for _, pc := range potentialConflicts {
			if globMatches(pc, existingJobName) {
				return true, existingJobName
			}
		}

		// 2. The new Job does not conflict with any of the tracked confclits
		for _, ec := range existingConflicts {
			if globMatches(ec, potentialJobName) {
				return true, existingJobName
			}
		}
	}

	return false, ""
}

// Purge all tracked conflicts for a given Job
func (self *AgentState) DropJobConflicts(jobName string) {
	delete(self.conflicts, jobName)
}

// Store a relation of 1 Job -> N Peers
func (self *AgentState) TrackJobPeers(jobName string, peers []string) {
	for _, peer := range peers {
		_, ok := self.peers[peer]
		if !ok {
			self.peers[peer] = make([]string, 0)
		}
		self.peers[peer] = append(self.peers[peer], jobName)
	}
}

// Retrieve all Jobs that share a given Peer
func (self *AgentState) GetJobsByPeer(peerName string) []string {
	peers, ok := self.peers[peerName]
	if ok {
		return peers
	} else {
		return make([]string, 0)
	}
}

// Remove all references to a given Job from all Peer indexes
func (self *AgentState) DropPeersJob(jobName string) {
	for peer, peerIndex := range self.peers {
		var idxs []int

		// Determine which item indexes must be removed from the Peer index
		for idx, record := range peerIndex {
			if jobName == record {
				idxs = append(idxs, idx)
			}
		}

		// Iterate through the item indexes, removing the corresponding Peers
		for i, idx := range idxs {
			self.peers[peer] = append(self.peers[peer][0:idx-i], self.peers[peer][idx-i:]...)
		}
	}
}

func (self *AgentState) TrackOffer(offer job.JobOffer) {
	self.offers[offer.Job.Name] = offer
}

// GetOffersWithoutBids returns all tracked JobOffers that have
// no corresponding JobBid tracked in the same AgentState object.
func (self *AgentState) GetOffersWithoutBids() []job.JobOffer {
	offers := make([]job.JobOffer, 0)
	for _, offer := range self.offers {
		if !self.HasBid(offer.Job.Name) {
			offers = append(offers, offer)
		}
	}
	return offers
}

func (self *AgentState) GetOffer(name string) (job.JobOffer, bool) {
	offer, ok := self.offers[name]
	return offer, ok
}

func (self *AgentState) DropOffer(name string) {
	if _, ok := self.offers[name]; !ok {
		log.V(2).Infof("AgentState knows nothing of JobOffer(%s)", name)
		return
	}

	delete(self.offers, name)
}

func (self *AgentState) TrackBid(name string) {
	self.bids = append(self.bids, name)
}

func (self *AgentState) HasBid(name string) bool {
	for _, val := range self.bids {
		if val == name {
			return true
		}
	}
	return false
}

func (self *AgentState) DropBid(name string) {
	for idx, val := range self.bids {
		if val == name {
			self.bids = append(self.bids[0:idx], self.bids[idx+1:]...)
			return
		}
	}
}

func globMatches(pattern, target string) bool {
	matched, err := path.Match(pattern, target)
	if err != nil {
		log.V(2).Infof("Received error while matching pattern '%s': %v", pattern, err)
	}
	return matched
}
<|endoftext|>


<commit_before>package ai

import (
	"github.com/nelhage/taktician/bitboard"
	"github.com/nelhage/taktician/tak"
)

const (
	weightFlat       = 200
	weightCaptured   = 100
	weightControlled = 300
	weightCapstone   = -150
	weightGroup      = 4
	weightAdvantage  = 50
)

func (m *MinimaxAI) evaluate(p *tak.Position) int64 {
	if over, winner := p.GameOver(); over {
		switch winner {
		case tak.NoColor:
			return 0
		case p.ToMove():
			return maxEval - int64(p.MoveNumber())
		default:
			return minEval + int64(p.MoveNumber())
		}
	}
	mine, theirs := 0, 0
	me := p.ToMove()
	addw := func(c tak.Color, w int) {
		if c == me {
			mine += w
		} else {
			theirs += w
		}
	}
	analysis := p.Analysis()
	for x := 0; x < p.Size(); x++ {
		for y := 0; y < p.Size(); y++ {
			sq := p.At(x, y)
			if len(sq) == 0 {
				continue
			}
			if sq[0].Kind() != tak.Standing {
				addw(sq[0].Color(), weightControlled)
			}
			if sq[0].Kind() == tak.Capstone {
				addw(sq[0].Color(), weightCapstone)
			}

			for i, stone := range sq {
				if i > 0 && i < p.Size() {
					addw(sq[0].Color(), weightCaptured)
				}
				if stone.Kind() == tak.Flat {
					addw(stone.Color(), weightFlat)
				}
			}
		}
	}

	empty := ^(analysis.White | analysis.Black)
	addw(tak.White, m.scoreGroups(analysis.WhiteGroups, empty))
	addw(tak.Black, m.scoreGroups(analysis.BlackGroups, empty))

	for _, r := range m.regions {
		w := bitboard.Popcount(analysis.White & r)
		b := bitboard.Popcount(analysis.Black & r)
		if w > b {
			addw(tak.White, (w-b)*weightAdvantage)
		} else {
			addw(tak.Black, (b-w)*weightAdvantage)
		}
	}

	return int64(mine - theirs)
}

func (ai *MinimaxAI) scoreGroups(gs []uint64, empty uint64) int {
	sc := 0
	for _, g := range gs {
		w, h := bitboard.Dimensions(&ai.c, g)
		sz := bitboard.Popcount(g)
		libs := bitboard.Popcount(bitboard.Grow(&ai.c, g|empty, g) &^ g)

		sp := w
		if h > sp {
			sp = h
		}
		sc += (sp*sp + (2 * sz) + libs) * weightGroup
	}

	return sc
}
<commit_msg>vary positional weight with game stage<commit_after>package ai

import (
	"github.com/nelhage/taktician/bitboard"
	"github.com/nelhage/taktician/tak"
)

const (
	weightFlat       = 200
	weightCaptured   = 100
	weightControlled = 300
	weightCapstone   = -150
	weightGroup      = 4
)

func (m *MinimaxAI) evaluate(p *tak.Position) int64 {
	if over, winner := p.GameOver(); over {
		switch winner {
		case tak.NoColor:
			return 0
		case p.ToMove():
			return maxEval - int64(p.MoveNumber())
		default:
			return minEval + int64(p.MoveNumber())
		}
	}
	mine, theirs := 0, 0
	me := p.ToMove()
	addw := func(c tak.Color, w int) {
		if c == me {
			mine += w
		} else {
			theirs += w
		}
	}
	weightGroup := weightGroup
	maxStack := 0
	analysis := p.Analysis()
	for x := 0; x < p.Size(); x++ {
		for y := 0; y < p.Size(); y++ {
			sq := p.At(x, y)
			if len(sq) == 0 {
				continue
			}
			if len(sq) > maxStack {
				maxStack = len(sq)
			}
			if sq[0].Kind() != tak.Standing {
				addw(sq[0].Color(), weightControlled)
			}
			if sq[0].Kind() == tak.Capstone {
				addw(sq[0].Color(), weightCapstone)
			}

			for i, stone := range sq {
				if i > 0 && i < p.Size() {
					addw(sq[0].Color(), weightCaptured)
				}
				if stone.Kind() == tak.Flat {
					addw(stone.Color(), weightFlat)
				}
			}
		}
	}

	empty := ^(analysis.White | analysis.Black)
	if maxStack >= 3 {
		weightGroup--
	}
	if bitboard.Popcount(empty) < (p.Size()*p.Size())/2 {
		weightGroup--
	}
	addw(tak.White, m.scoreGroups(analysis.WhiteGroups, empty, weightGroup))
	addw(tak.Black, m.scoreGroups(analysis.BlackGroups, empty, weightGroup))

	return int64(mine - theirs)
}

func (ai *MinimaxAI) scoreGroups(gs []uint64, empty uint64, weight int) int {
	sc := 0
	for _, g := range gs {
		w, h := bitboard.Dimensions(&ai.c, g)
		sz := bitboard.Popcount(g)
		libs := bitboard.Popcount(bitboard.Grow(&ai.c, g|empty, g) &^ g)

		sp := w
		if h > sp {
			sp = h
		}
		sc += (sp*sp + (2 * sz) + libs) * weight
	}

	return sc
}
<|endoftext|>


<commit_before>// printer.go

package xingapi

import (
	"fmt"
	"github.com/str1ngs/ansi/color"
	"net/http"
)

type Printer struct{}

func PrintResponse(response *http.Response) {
	var colorCode string
	if response.StatusCode == 200 {
		colorCode = "g"
	} else {
		colorCode = "r"
	}
	color.Printf(colorCode, fmt.Sprintf("%s\n", response.Status))
}

func PrintCommand(command string) {
	color.Printf("c", fmt.Sprintf("%s", command))
}

func PrintError(err error) {
	color.Printf("r", fmt.Sprintf("%s", err.Error()))
}

func PrintMessageWithParam(message string, param string) {
	print(message)
	color.Print("m", fmt.Sprintf("%s%s", param, ""))
}

func PrintUser(user User) {
	color.Printf("", fmt.Sprintf("-----------------------------------\n%s <%s>:\n", user.DisplayName(), user.Id()))
	color.Printf("d", fmt.Sprintf("Email address:\t\t%s\nDate of birth:\t\t%s\n", user.ActiveEmail(), user.Birthdate()))
}

func PrintUserOneLine(user User) {
	color.Printf("m", fmt.Sprintf("%s <%s>\n", user.Birthdate().String(), user.Id()))
}
<commit_msg>Show display name when printing user in one line<commit_after>// printer.go

package xingapi

import (
	"fmt"
	"github.com/str1ngs/ansi/color"
	"net/http"
)

type Printer struct{}

func PrintResponse(response *http.Response) {
	var colorCode string
	if response.StatusCode == 200 {
		colorCode = "g"
	} else {
		colorCode = "r"
	}
	color.Printf(colorCode, fmt.Sprintf("%s\n", response.Status))
}

func PrintCommand(command string) {
	color.Printf("c", fmt.Sprintf("%s", command))
}

func PrintError(err error) {
	color.Printf("r", fmt.Sprintf("%s", err.Error()))
}

func PrintMessageWithParam(message string, param string) {
	print(message)
	color.Print("m", fmt.Sprintf("%s%s", param, ""))
}

func PrintUser(user User) {
	color.Printf("", fmt.Sprintf("-----------------------------------\n%s <%s>:\n", user.DisplayName(), user.Id()))
	color.Printf("d", fmt.Sprintf("Email address:\t\t%s\nDate of birth:\t\t%s\n", user.ActiveEmail(), user.Birthdate()))
}

func PrintUserOneLine(user User) {
	color.Printf("m", fmt.Sprintf("%s <%s>\n", user.DisplayName(), user.Id()))
}
<|endoftext|>


<commit_before>package ifrit

import "os"

type Process interface {
	Ready() <-chan struct{}
	Wait() <-chan error
	Signal(os.Signal)
}

func Invoke(r Runner) Process {
	p := newProcess(r)
	go p.run()

	select {
	case <-p.Ready():
	case <-p.Wait():
	}

	return p
}

func Envoke(r Runner) Process {
	return Invoke(r)
}

func Background(r Runner) Process {
	p := newProcess(r)
	go p.run()
	return p
}

type process struct {
	runner     Runner
	sig        chan os.Signal
	ready      chan struct{}
	exited     chan struct{}
	exitStatus error
}

func newProcess(runner Runner) *process {
	return &process{
		runner: runner,
		sig:    make(chan os.Signal),
		ready:  make(chan struct{}),
		exited: make(chan struct{}),
	}

}

func (p *process) run() {
	p.exitStatus = p.runner.Run(p.sig, p.ready)
	close(p.exited)
}

func (p *process) Ready() <-chan struct{} {
	return p.ready
}

func (p *process) Wait() <-chan error {
	exitChan := make(chan error, 1)

	go func() {
		<-p.exited
		exitChan <- p.exitStatus
	}()

	return exitChan
}

func (p *process) Signal(signal os.Signal) {
	go func() {
		select {
		case p.sig <- signal:
		case <-p.exited:
		}
	}()
}
<commit_msg>Invoke calls Background under the hood<commit_after>package ifrit

import "os"

type Process interface {
	Ready() <-chan struct{}
	Wait() <-chan error
	Signal(os.Signal)
}

func Invoke(r Runner) Process {
	p := Background(r)

	select {
	case <-p.Ready():
	case <-p.Wait():
	}

	return p
}

func Envoke(r Runner) Process {
	return Invoke(r)
}

func Background(r Runner) Process {
	p := newProcess(r)
	go p.run()
	return p
}

type process struct {
	runner     Runner
	sig        chan os.Signal
	ready      chan struct{}
	exited     chan struct{}
	exitStatus error
}

func newProcess(runner Runner) *process {
	return &process{
		runner: runner,
		sig:    make(chan os.Signal),
		ready:  make(chan struct{}),
		exited: make(chan struct{}),
	}

}

func (p *process) run() {
	p.exitStatus = p.runner.Run(p.sig, p.ready)
	close(p.exited)
}

func (p *process) Ready() <-chan struct{} {
	return p.ready
}

func (p *process) Wait() <-chan error {
	exitChan := make(chan error, 1)

	go func() {
		<-p.exited
		exitChan <- p.exitStatus
	}()

	return exitChan
}

func (p *process) Signal(signal os.Signal) {
	go func() {
		select {
		case p.sig <- signal:
		case <-p.exited:
		}
	}()
}
<|endoftext|>


<commit_before>package sprok

/*
 * Copyright 2014 Albert P. Tobey <atobey@datastax.com> @AlTobey
 *
 * 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.
 */

import (
	"fmt"
	"log"
	"os"
	"strings"
	"syscall"
)

type Process struct {
	Env    map[string]string `"env"`
	Argv   []string          `"argv"`
	Stdin  string            `"stdin"`
	Stdout string            `"stdout"`
	Stderr string            `"stderr"`
}

// NewProcess returns a Process struct with the env map and argv allocated
// and all stdio pointed at /dev/null.
func NewProcess() Process {
	return Process{
		Env:    map[string]string{},
		Argv:   make([]string, 1),
		Stdin:  "/dev/null",
		Stdout: "/dev/null",
		Stderr: "/dev/null",
	}
}

// Exec executes Argv with environment Env and file descriptors 1, 2, and 3 open on the
// files specified in Stdin, Stdout, and Stderr. They all default to /dev/null if left unspecified
// in the config or for empty string "".
func (p *Process) Exec() error {
	stdin := openFile(p.Stdin, os.O_RDONLY)
	stdout := openFile(p.Stdout, os.O_WRONLY|os.O_CREATE|os.O_APPEND)

	var stderr *os.File
	if p.Stdout == p.Stderr {
		stderr = stdout
	} else {
		stderr = openFile(p.Stderr, os.O_WRONLY|os.O_CREATE|os.O_APPEND)
	}

	err := syscall.Dup2(int(stdin.Fd()), int(os.Stdin.Fd()))
	if err != nil {
		log.Fatalf("Failed to redirect stdin: %s\n", err)
	}

	err = syscall.Dup2(int(stdout.Fd()), int(os.Stdout.Fd()))
	if err != nil {
		log.Fatalf("Failed to redirect stdout: %s\n", err)
	}

	err = syscall.Dup2(int(stderr.Fd()), int(os.Stderr.Fd()))
	if err != nil {
		log.Fatalf("Failed to redirect stderr: %s\n", err)
	}

	return syscall.Exec(p.Argv[0], p.Argv[1:], p.envPairs())
}

func (p *Process) String() string {
	env := strings.Join(p.envPairs(), " ")
	cmd := strings.Join(p.Argv, " ")
	// FOO=BAR cmd -arg1 -arg2 foo < /dev/null 1>/dev/null 2>/dev/null
	return fmt.Sprintf("%s %s <%s 1>%s 2>%s", env, cmd, p.Stdin, p.Stdout, p.Stderr)
}

func (p *Process) envPairs() []string {
	env := make([]string, len(p.Env))
	i := 0
	for key, value := range p.Env {
		env[i] = fmt.Sprintf("%s=%s", key, value)
		i++
	}
	return env
}

func openFile(name string, flags int) *os.File {
	if name == "/dev/null" {
		name = os.DevNull
	}

	f, err := os.OpenFile(name, flags, 0644)
	if err != nil {
		log.Fatalf("Could not open file '%s': %s\n", name, err)
	}

	return f
}
<commit_msg>Don't redirect stdio when it's unspecified.<commit_after>package sprok

/*
 * Copyright 2014 Albert P. Tobey <atobey@datastax.com> @AlTobey
 *
 * 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.
 */

import (
	"fmt"
	"log"
	"os"
	"strings"
	"syscall"
)

type Process struct {
	Env    map[string]string `"env"`
	Argv   []string          `"argv"`
	Stdin  string            `"stdin"`
	Stdout string            `"stdout"`
	Stderr string            `"stderr"`
}

// NewProcess returns a Process struct with the env map and argv allocated
// and all stdio pointed at /dev/null.
func NewProcess() Process {
	return Process{
		Env:    map[string]string{},
		Argv:   make([]string, 1),
		Stdin:  "/dev/null",
		Stdout: "/dev/null",
		Stderr: "/dev/null",
	}
}

// Exec executes Argv with environment Env and file descriptors
// 1, 2, and 3 open on the files specified in Stdin, Stdout,
// and Stderr. When output files are unspecified or an empty
// string, the file descriptors are left unmodified.
func (p *Process) Exec() error {
	var stdin, stdout, stderr *os.File

	if p.Stdin != "" {
		stdin = openFile(p.Stdin, os.O_RDONLY)

		err := syscall.Dup2(int(stdin.Fd()), int(os.Stdin.Fd()))
		if err != nil {
			log.Fatalf("Failed to redirect stdin: %s\n", err)
		}
	}

	if p.Stdout != "" {
		stdout = openFile(p.Stdout, os.O_WRONLY|os.O_CREATE|os.O_APPEND)

		err := syscall.Dup2(int(stdout.Fd()), int(os.Stdout.Fd()))
		if err != nil {
			log.Fatalf("Failed to redirect stdout: %s\n", err)
		}
	}

	dupStderr := false
	if p.Stderr != "" && p.Stderr == p.Stdout {
		stderr = stdout
		dupStderr = true
	} else if p.Stderr != "" {
		stderr = openFile(p.Stderr, os.O_WRONLY|os.O_CREATE|os.O_APPEND)
		dupStderr = true
	}

	if dupStderr {
		err := syscall.Dup2(int(stderr.Fd()), int(os.Stderr.Fd()))
		if err != nil {
			log.Fatalf("Failed to redirect stderr: %s\n", err)
		}
	}

	return syscall.Exec(p.Argv[0], p.Argv[1:], p.envPairs())
}

func (p *Process) String() string {
	env := strings.Join(p.envPairs(), " ")
	cmd := strings.Join(p.Argv, " ")
	// FOO=BAR cmd -arg1 -arg2 foo < /dev/null 1>/dev/null 2>/dev/null
	return fmt.Sprintf("%s %s <%s 1>%s 2>%s", env, cmd, p.Stdin, p.Stdout, p.Stderr)
}

func (p *Process) envPairs() []string {
	env := make([]string, len(p.Env))
	i := 0
	for key, value := range p.Env {
		env[i] = fmt.Sprintf("%s=%s", key, value)
		i++
	}
	return env
}

func openFile(name string, flags int) *os.File {
	if name == "/dev/null" {
		name = os.DevNull
	}

	f, err := os.OpenFile(name, flags, 0644)
	if err != nil {
		log.Fatalf("Could not open file '%s': %s\n", name, err)
	}

	return f
}
<|endoftext|>


<commit_before>// Package bamstats provides functions for computing several mapping statistics on a BAM file.
package bamstats

import (
	// "io"
	// "os"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/biogo/hts/bam"
	"github.com/guigolab/bamstats/annotation"
	"github.com/guigolab/bamstats/config"
	"github.com/guigolab/bamstats/sam"
	"github.com/guigolab/bamstats/stats"
	"github.com/guigolab/bamstats/utils"
)

func init() {
	log.SetLevel(log.WarnLevel)
}

var wg sync.WaitGroup

func worker(id int, in interface{}, out chan stats.StatsMap, index *annotation.RtreeMap, uniq bool) {
	defer wg.Done()
	logger := log.WithFields(log.Fields{
		"worker": id,
	})
	logger.Debug("Starting")

	sm := stats.NewStatsMap(true, (index != nil), uniq)

	switch in.(type) {
	case chan *sam.Record:
		c := in.(chan *sam.Record)
		for record := range c {
			for _, s := range sm {
				s.Collect(record, index)
			}
		}
	case chan *bam.Iterator:
		iterators := in.(chan *bam.Iterator)
		for it := range iterators {
			for it.Next() {
				for _, s := range sm {
					s.Collect(sam.NewRecord(it.Record()), index)
				}
			}
		}
	}
	logger.Debug("Done")

	out <- sm
}

func process(bamFile string, index *annotation.RtreeMap, cpu int, maxBuf int, reads int, uniq bool) (chan stats.StatsMap, error) {
	conf := config.NewConfig(cpu, maxBuf, reads, uniq)

	br, err := sam.NewReader(bamFile, conf)
	defer br.Close()
	if err != nil {
		return nil, err
	}
	st := make(chan stats.StatsMap, cpu)
	for i := 0; i < br.Workers; i++ {
		id := i + 1
		wg.Add(1)
		go worker(id, br.Channels[i], st, index, uniq)
	}

	br.Read()

	go waitProcess(st)

	return st, nil
}

func waitProcess(st chan stats.StatsMap) {
	wg.Wait()
	close(st)
}

// Process process the input BAM file and collect different mapping stats.
func Process(bamFile string, anno string, cpu int, maxBuf int, reads int, uniq bool) (stats.StatsMap, error) {
	var index *annotation.RtreeMap
	if anno != "" {
		log.Infof("Creating index for %s", anno)
		start := time.Now()
		index = annotation.CreateIndex(anno, cpu)
		log.Infof("Index done in %v", time.Since(start))
	}
	start := time.Now()
	log.Infof("Collecting stats for %s", bamFile)
	stats, err := process(bamFile, index, cpu, maxBuf, reads, uniq)
	if err != nil {
		return nil, err
	}
	st := <-stats
	st.Merge(stats)
	log.Infof("Stats done in %v", time.Since(start))
	return st, nil
}

func WriteOutput(output string, st stats.StatsMap) {
	out := utils.NewOutput(output)
	utils.OutputJSON(out, st)
}
<commit_msg>Update bam processing with new sam.Iterator<commit_after>// Package bamstats provides functions for computing several mapping statistics on a BAM file.
package bamstats

import (
	// "io"
	// "os"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/guigolab/bamstats/annotation"
	"github.com/guigolab/bamstats/config"
	"github.com/guigolab/bamstats/sam"
	"github.com/guigolab/bamstats/stats"
	"github.com/guigolab/bamstats/utils"
)

func init() {
	log.SetLevel(log.WarnLevel)
}

// var wg sync.WaitGroup

func worker(id int, in interface{}, out chan stats.StatsMap, index *annotation.RtreeMap, cfg *config.Config, wg *sync.WaitGroup) {
	defer wg.Done()
	logger := log.WithFields(log.Fields{
		"worker": id,
	})
	logger.Debug("Starting")

	sm := stats.NewStatsMap(true, (index != nil), cfg.Uniq)

	switch in.(type) {
	case chan *sam.Record:
		c := in.(chan *sam.Record)
		for record := range c {
			for _, s := range sm {
				s.Collect(record, index)
			}
		}
	case chan *sam.Iterator:
		iterators := in.(chan *sam.Iterator)
		for it := range iterators {
			for it.Next() {
				for _, s := range sm {
					s.Collect(it.Record(), index)
				}
			}
		}
	}
	logger.Debug("Done")

	out <- sm
}

func process(bamFile string, index *annotation.RtreeMap, cpu int, maxBuf int, reads int, uniq bool) (chan stats.StatsMap, error) {

	var wg sync.WaitGroup

	conf := config.NewConfig(cpu, maxBuf, reads, uniq)

	br, err := sam.NewReader(bamFile, conf)
	defer br.Close()
	if err != nil {
		return nil, err
	}
	st := make(chan stats.StatsMap, cpu)
	for i := 0; i < br.Workers; i++ {
		id := i + 1
		wg.Add(1)
		go worker(id, br.Channels[i], st, index, conf, &wg)
	}

	br.Read()

	go waitProcess(st, &wg)

	return st, nil
}

func waitProcess(st chan stats.StatsMap, wg *sync.WaitGroup) {
	wg.Wait()
	close(st)
}

// Process process the input BAM file and collect different mapping stats.
func Process(bamFile string, anno string, cpu int, maxBuf int, reads int, uniq bool) (stats.StatsMap, error) {
	var index *annotation.RtreeMap
	if anno != "" {
		log.Infof("Creating index for %s", anno)
		start := time.Now()
		index = annotation.CreateIndex(anno, cpu)
		log.Infof("Index done in %v", time.Since(start))
	}
	start := time.Now()
	log.Infof("Collecting stats for %s", bamFile)
	stats, err := process(bamFile, index, cpu, maxBuf, reads, uniq)
	if err != nil {
		return nil, err
	}
	st := <-stats
	st.Merge(stats)
	log.Infof("Stats done in %v", time.Since(start))
	return st, nil
}

func WriteOutput(output string, st stats.StatsMap) {
	out := utils.NewOutput(output)
	utils.OutputJSON(out, st)
}
<|endoftext|>


<commit_before>package temple

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

const defaultRootTemplateName = "_entry"

// Temple represents a map of Templates with their dot notation
// names.
type Temple map[string]*Template

// Process processes the root temple folder.
func Process(root string) (Temple, error) {
	temple := make(Temple)
	err := filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() {
			return nil // skip-non directories
		}
		if root == p {
			return nil // skip root
		}
		rel, err := filepath.Rel(root, p)
		if err != nil {
			return err
		}
		name := strings.Replace(rel, "/", ".", -1)
		// process the template
		tpl, err := parse(root, p)
		if err != nil {
			return err
		}
		temple[name] = tpl
		return nil
	})
	if err != nil {
		return nil, err
	}
	return temple, nil
}

// Template represents a single temple Template.
type Template struct {
	*template.Template
	foundlist map[string]struct{}
	// RootTemplateName is the name of the template that will be
	// rendered when Execute is called.
	RootTemplateName string
}

func parse(root, path string) (*Template, error) {
	tpl := &Template{}
	if err := tpl.parse(root, path); err != nil {
		return nil, err
	}
	return tpl, nil
}

// Execute applies a parsed template to the specified data object, writing the output to wr.
// It calls ExecuteTemplate on the underlying Template with the appropriate
// RootTemplateName.
func (c *Template) Execute(wr io.Writer, data interface{}) error {
	return c.Template.ExecuteTemplate(wr, c.RootTemplateName, data)
}

func (c *Template) parse(root, path string) error {
	if c.Template == nil {
		c.Template = template.New(defaultRootTemplateName)
	}
	if c.foundlist == nil {
		c.foundlist = make(map[string]struct{})
	}
	items, err := ioutil.ReadDir(path)
	if err != nil {
		return err
	}
	for _, item := range items {
		if item.IsDir() {
			continue
		}
		if isTempleFile(item.Name()) {
			name := templateName(item.Name())
			// skip it if we already have it
			if _, present := c.foundlist[name]; present {
				continue
			}
			// base always becomes the entry template
			if len(c.RootTemplateName) == 0 || name == "base" {
				c.RootTemplateName = name
			}
			filepath := filepath.Join(path, item.Name())
			b, err := ioutil.ReadFile(filepath)
			if err != nil {
				return err
			}
			s := string(b)
			s = "{{define \"" + name + "\"}}" + s + "{{end}}"
			_, err = c.Parse(s)
			if err != nil {
				return err
			}
			c.foundlist[name] = struct{}{}
		}
	}
	relpath, err := filepath.Rel(root, path)
	if err != nil {
		return err
	}
	if relpath != "." {
		// we haven't reached root - keep climbing
		up := filepath.Dir(path)
		if err := c.parse(root, up); err != nil {
			return err
		}
	}
	return nil
}

func isTempleFile(p string) bool {
	return strings.Contains(p, ".temple")
}

func templateName(p string) string {
	p = filepath.Base(p)
	i := strings.Index(p, ".temple")
	p = strings.ToLower(p[0:i])
	return p
}
<commit_msg>updated description<commit_after>package temple

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

const defaultRootTemplateName = "_entry"

// Temple represents a map of Templates with their dot notation
// names.
type Temple map[string]*Template

// Process walks directories starting at root and generates a Temple
// object containing all compiled templates.
func Process(root string) (Temple, error) {
	temple := make(Temple)
	err := filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() {
			return nil // skip-non directories
		}
		if root == p {
			return nil // skip root
		}
		rel, err := filepath.Rel(root, p)
		if err != nil {
			return err
		}
		name := strings.Replace(rel, "/", ".", -1)
		// process the template
		tpl, err := parse(root, p)
		if err != nil {
			return err
		}
		temple[name] = tpl
		return nil
	})
	if err != nil {
		return nil, err
	}
	return temple, nil
}

// Template represents a single temple Template.
type Template struct {
	*template.Template
	foundlist map[string]struct{}
	// RootTemplateName is the name of the template that will be
	// rendered when Execute is called.
	RootTemplateName string
}

func parse(root, path string) (*Template, error) {
	tpl := &Template{}
	if err := tpl.parse(root, path); err != nil {
		return nil, err
	}
	return tpl, nil
}

// Execute applies a parsed template to the specified data object, writing the output to wr.
// It calls ExecuteTemplate on the underlying Template with the appropriate
// RootTemplateName.
func (c *Template) Execute(wr io.Writer, data interface{}) error {
	return c.Template.ExecuteTemplate(wr, c.RootTemplateName, data)
}

func (c *Template) parse(root, path string) error {
	if c.Template == nil {
		c.Template = template.New(defaultRootTemplateName)
	}
	if c.foundlist == nil {
		c.foundlist = make(map[string]struct{})
	}
	items, err := ioutil.ReadDir(path)
	if err != nil {
		return err
	}
	for _, item := range items {
		if item.IsDir() {
			continue
		}
		if isTempleFile(item.Name()) {
			name := templateName(item.Name())
			// skip it if we already have it
			if _, present := c.foundlist[name]; present {
				continue
			}
			// base always becomes the entry template
			if len(c.RootTemplateName) == 0 || name == "base" {
				c.RootTemplateName = name
			}
			filepath := filepath.Join(path, item.Name())
			b, err := ioutil.ReadFile(filepath)
			if err != nil {
				return err
			}
			s := string(b)
			s = "{{define \"" + name + "\"}}" + s + "{{end}}"
			_, err = c.Parse(s)
			if err != nil {
				return err
			}
			c.foundlist[name] = struct{}{}
		}
	}
	relpath, err := filepath.Rel(root, path)
	if err != nil {
		return err
	}
	if relpath != "." {
		// we haven't reached root - keep climbing
		up := filepath.Dir(path)
		if err := c.parse(root, up); err != nil {
			return err
		}
	}
	return nil
}

func isTempleFile(p string) bool {
	return strings.Contains(p, ".temple")
}

func templateName(p string) string {
	p = filepath.Base(p)
	i := strings.Index(p, ".temple")
	p = strings.ToLower(p[0:i])
	return p
}
<|endoftext|>


<commit_before>// This file is paired up with nomain_in.go and only exists to make 'blaze test' of this directory work.
package main

func main() {
}
<commit_msg>Delete testdata/nomain_main.go<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/events"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/go-zigbee"
	"github.com/ninjasphere/go-zigbee/gateway"
	"github.com/ninjasphere/go-zigbee/nwkmgr"
)

const (
	ClusterIDBasic    uint32 = 0x00
	ClusterIDOnOff    uint32 = 0x06
	ClusterIDTemp     uint32 = 0x402
	ClusterIDHumidity uint32 = 0x405
	ClusterIDPower    uint32 = 0x702
)

type ZStackConfig struct {
	Hostname       string
	OtasrvrPort    int
	GatewayPort    int
	NwkmgrPort     int
	StableFlagFile string
}

type DriverConfig struct {
}

type Driver struct {
	conn      *ninja.Connection
	userAgent *ninja.ServiceClient
	sendEvent func(event string, payload interface{}) error

	devices map[uint64]*Device

	NetworkReady chan bool

	nwkmgrConn  *zigbee.ZStackNwkMgr
	gatewayConn *zigbee.ZStackGateway
	otaConn     *zigbee.ZStackOta
	config      *DriverConfig
}

func NewDriver() *Driver {
	return &Driver{
		NetworkReady: make(chan bool),
	}
}

type Device struct {
	info       *model.Device
	driver     *Driver
	deviceInfo *nwkmgr.NwkDeviceInfoT
	channels   []Channel
	sendEvent  func(event string, payload interface{}) error
}

type Channel struct {
	device   *Device
	endpoint *nwkmgr.NwkSimpleDescriptorT
}

func (d *Driver) GetModuleInfo() *model.Module {
	return info
}

func (d *Driver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}

func (d *Driver) Reset(hard bool) error {
	return d.nwkmgrConn.Reset(hard)
}

func (d *Driver) Start(config *DriverConfig) error {
	d.config = config
	return d.sendEvent("config", config)
}

func (d *Driver) Stop() error {
	return fmt.Errorf("This driver does not support being stopped. YOU HAVE NO POWER HERE.")
}

func (d *Driver) StartPairing(period uint32) (*uint32, error) {
	err := d.PermitJoin(uint32(period))
	if err != nil {
		err = fmt.Errorf("permit Join failed: %v", err)
		log.Errorf("%s", err)
	}
	return &period, err
}

func (d *Driver) OnPairingRequest(req *events.PairingRequest, topicKeys map[string]string) bool {
	log.Debugf("Pairing request of %d seconds received from %s", req.Duration, topicKeys["deviceId"])
	d.PermitJoin(uint32(req.Duration))
	return true
}

func (d *Driver) PermitJoin(period uint32) error {

	log.Infof("Join window will open for %d seconds.", period)

	//joinTime := uint32(30)
	permitJoinRequest := &nwkmgr.NwkSetPermitJoinReq{
		PermitJoinTime: &period,
		PermitJoin:     nwkmgr.NwkPermitJoinTypeT_PERMIT_ALL.Enum(),
	}

	permitJoinResponse := &nwkmgr.NwkZigbeeGenericCnf{}

	go func() {
		// logging the close of the join window is helpful when debugging
		// join behaviour.
		time.Sleep(time.Duration(period) * time.Second)
		log.Infof("Join window has closed after %d seconds.", period)
	}()
	err := d.nwkmgrConn.SendCommand(permitJoinRequest, permitJoinResponse)
	if err != nil {
		return fmt.Errorf("Failed to enable joining: %s", err)
	}
	if permitJoinResponse.Status.String() != "STATUS_SUCCESS" {
		return fmt.Errorf("Failed to enable joining: %s", permitJoinResponse.Status)
	}
	//log.Println("Permit join response: ")
	//outJSON(permitJoinResponse)

	return nil
}

func (d *Driver) Connect(cfg *ZStackConfig, networkReady chan bool) error {

	waitUntilZStackReady(config.StableFlagFile)

	d.devices = make(map[uint64]*Device)

	conn, err := ninja.Connect("com.ninjablocks.zigbee")
	if err != nil {
		return fmt.Errorf("Could not connect to MQTT: %s", err)
	}

	d.userAgent = conn.GetServiceClient("$device/:deviceId/channel/user-agent")
	err = d.userAgent.OnEvent("pairing-requested", d.OnPairingRequest)
	if err != nil {
		return fmt.Errorf("Failed register user-agent service client: %s", err)
	}

	err = conn.ExportDriver(d)
	if err != nil {
		return fmt.Errorf("Could not export driver: %s", err)
	}

	d.nwkmgrConn, err = zigbee.ConnectToNwkMgrServer(cfg.Hostname, cfg.NwkmgrPort)
	if err != nil {
		return fmt.Errorf("Error connecting to nwkmgr %s", err)
	}
	d.nwkmgrConn.OnDeviceFound = func(deviceInfo *nwkmgr.NwkDeviceInfoT) {
		d.onDeviceFound(deviceInfo)
	}

	done := false
	d.nwkmgrConn.OnNetworkReady = func() {
		if !done {
			done = true
			networkReady <- true
		}
	}

	d.otaConn, err = zigbee.ConnectToOtaServer(cfg.Hostname, cfg.OtasrvrPort)
	if err != nil {
		return fmt.Errorf("Error connecting to ota server %s", err)
	}

	d.gatewayConn, err = zigbee.ConnectToGatewayServer(cfg.Hostname, cfg.GatewayPort)
	if err != nil {
		return fmt.Errorf("Error connecting to gateway %s", err)
	}

	/*keyResponse := &nwkmgr.NwkZigbeeGenericCnf{}

	keyRequest := &nwkmgr.NwkChangeNwkKeyReq{
		NewKey: []byte{0x5a, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6c, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x30, 0x39},
	}

	err = d.nwkmgrConn.SendCommand(keyRequest, keyResponse)
	if err != nil {
		return fmt.Errorf("Failed setting network key: %s", err)
	}

	spew.Dump(keyResponse)
	log.Println("Sleeping for 10 seconds after setting network key")

	time.Sleep(10 * time.Second)*/

	networkInfo := &nwkmgr.NwkZigbeeNwkInfoCnf{}

	err = d.nwkmgrConn.SendCommand(&nwkmgr.NwkZigbeeNwkInfoReq{}, networkInfo)
	if err != nil {
		return fmt.Errorf("Failed getting network info: %s", err)
	}

	if *networkInfo.Status == nwkmgr.NwkNetworkStatusT_NWK_DOWN {
		return fmt.Errorf("The ZigBee network is down")
	}

	localDevice := &nwkmgr.NwkGetLocalDeviceInfoCnf{}

	err = d.nwkmgrConn.SendCommand(&nwkmgr.NwkGetLocalDeviceInfoReq{}, localDevice)
	if err != nil {
		return fmt.Errorf("Failed getting local device info: %s", err)
	}

	spew.Dump("device info", localDevice.String())

	networkKey := &nwkmgr.NwkGetNwkKeyCnf{}

	err = d.nwkmgrConn.SendCommand(&nwkmgr.NwkGetNwkKeyReq{}, networkKey)
	if err != nil {
		return fmt.Errorf("Failed getting network key: %s", err)
	}

	spew.Dump(networkKey)

	log.Infof("Started coordinator. Channel:%d Pan ID:0x%X Key:% X", *networkInfo.NwkChannel, *networkInfo.PanId, networkKey.NewKey)

	return nil
}

func (d *Driver) FetchDevices() error {

	return d.nwkmgrConn.FetchDeviceList()

}

func (d *Device) GetDriver() ninja.Driver {
	return d.driver
}

func (d *Device) GetDeviceInfo() *model.Device {
	return d.info
}

func (d *Device) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}

func (d *Device) getBasicInfo() error {

	log.Debugf("Getting basic information from %X", *d.deviceInfo.IeeeAddress)

	cluster := ClusterIDBasic
	ManufacturerNameAttribute := uint32(0x004)
	ModelIdentifierAttribute := uint32(0x005)

	request := &gateway.GwReadDeviceAttributeReq{
		DstAddress: &gateway.GwAddressStructT{
			AddressType: gateway.GwAddressTypeT_UNICAST.Enum(),
			IeeeAddr:    d.deviceInfo.IeeeAddress,
		},
		ClusterId:     &cluster,
		AttributeList: []uint32{ManufacturerNameAttribute, ModelIdentifierAttribute},
	}

	response := &gateway.GwReadDeviceAttributeRspInd{}
	err := d.driver.gatewayConn.SendAsyncCommand(request, response, 10*time.Second)
	if err != nil {
		return fmt.Errorf("Error getting basic device information state : %s", err)
	}
	if response.Status.String() != "STATUS_SUCCESS" {
		return fmt.Errorf("Failed to get basic device information. status: %s", response.Status.String())
	}

	sigs := make(map[string]string)

	manufacturerName := ""
	modelIdentifier := ""

	for _, attribute := range response.AttributeRecordList {

		switch *attribute.AttributeId {
		case ManufacturerNameAttribute:
			manufacturerName = string(attribute.AttributeValue)
		case ModelIdentifierAttribute:
			modelIdentifier = string(attribute.AttributeValue)
		default:
			log.Debugf("Unknown attribute returned when finding basic info %s", *attribute.AttributeId)
		}
	}

	sigs["zigbee:ManufacturerName"] = manufacturerName
	sigs["zigbee:ModelIdentifier"] = modelIdentifier

	name := fmt.Sprintf("%s by %s", modelIdentifier, manufacturerName)
	id := fmt.Sprintf("%X", *d.deviceInfo.IeeeAddress)

	d.info.Name = &name

	d.info.Signatures = &sigs
	d.info.NaturalIDType = "zigbee"
	d.info.NaturalID = id
	d.info.Name = &name

	return nil
}

func (d *Driver) onDeviceFound(deviceInfo *nwkmgr.NwkDeviceInfoT) {

	log.Debugf("\n\n")
	log.Debugf("---- Found Device IEEE:%X ----\f", *deviceInfo.IeeeAddress)

	if d.devices[*deviceInfo.IeeeAddress] != nil {
		log.Debugf("We've already seen this device")
	}

	/*sigs, _ := simplejson.NewJson([]byte(`{
	    "ninja:manufacturer": "Phillips",
	    "ninja:productName": "Hue",
	    "manufacturer:productModelId": "",
	    "ninja:productType": "Light",
	    "ninja:thingType": "light"
	}`))*/

	device := &Device{
		info:       &model.Device{},
		driver:     d,
		deviceInfo: deviceInfo,
	}

	err := device.getBasicInfo()
	if err != nil {
		log.Debugf("Failed to get basic info: %s", err)
		return
	}

	if d.Log.IsDebugEnabled() {
		spew.Dump(deviceInfo)
	}

	err = d.conn.ExportDevice(device)

	log.Debugf("Got device : %d", *deviceInfo.IeeeAddress)

	for _, endpoint := range deviceInfo.SimpleDescList {
		log.Debugf("Got endpoint : %d", *endpoint.EndpointId)

		if containsUInt32(endpoint.InputClusters, ClusterIDOnOff) {
			log.Debugf("This endpoint has on/off cluster")

			onOff := &OnOffChannel{
				Channel{
					device:   device,
					endpoint: endpoint,
				},
				nil,
			}

			err := onOff.init()
			if err != nil {
				log.Errorf("Failed initialising on/off channel: %s", err)
			}

		}

		if containsUInt32(endpoint.InputClusters, ClusterIDPower) {
			log.Debugf("This endpoint has power cluster")

			power := &PowerChannel{
				Channel{
					device:   device,
					endpoint: endpoint,
				},
				nil,
			}

			err := power.init()
			if err != nil {
				log.Errorf("Failed initialising power channel: %s", err)
			}

		}

		if containsUInt32(endpoint.InputClusters, ClusterIDTemp) {
			log.Debugf("This endpoint has temperature cluster")

			temp := &TempChannel{
				Channel{
					device:   device,
					endpoint: endpoint,
				},
				nil,
			}

			err := temp.init()
			if err != nil {
				log.Errorf("Failed initialising temp channel: %s", err)
			}

		}

		if containsUInt32(endpoint.InputClusters, ClusterIDHumidity) {
			log.Debugf("This endpoint has humidity cluster")

			humidity := &HumidityChannel{
				Channel{
					device:   device,
					endpoint: endpoint,
				},
				nil,
			}

			err := humidity.init()
			if err != nil {
				log.Errorf("Failed initialising humidity channel: %s", err)
			}

		}

	}

	d.devices[*deviceInfo.IeeeAddress] = device

	log.Debugf("---- Finished Device IEEE:%X ----\n", *deviceInfo.IeeeAddress)

}

func getCurDir() string {
	pwd, _ := os.Getwd()
	return pwd + "/"
}

func containsUInt32(hackstack []uint32, needle uint32) bool {
	for _, cluster := range hackstack {
		if cluster == needle {
			return true
		}
	}
	return false
}

func waitUntilZStackReady(checkFile string) {
	if checkFile == "" {
		return
	}

	// cooperate with zigbeeHAgw so that we don't start the zigbee driver
	// until we look somewhat stable.
	log.Debugf("waiting until zigbeeHAgw writes %s", checkFile)
	for {
		if _, err := os.Stat(checkFile); err == nil {
			break
		} else {
			time.Sleep(time.Second)
		}
	}
	log.Debugf("%s detected. start up continues...", checkFile)
}
<commit_msg>Remove member of Driver struct that was not required.<commit_after>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/events"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/go-zigbee"
	"github.com/ninjasphere/go-zigbee/gateway"
	"github.com/ninjasphere/go-zigbee/nwkmgr"
)

const (
	ClusterIDBasic    uint32 = 0x00
	ClusterIDOnOff    uint32 = 0x06
	ClusterIDTemp     uint32 = 0x402
	ClusterIDHumidity uint32 = 0x405
	ClusterIDPower    uint32 = 0x702
)

type ZStackConfig struct {
	Hostname       string
	OtasrvrPort    int
	GatewayPort    int
	NwkmgrPort     int
	StableFlagFile string
}

type DriverConfig struct {
}

type Driver struct {
	conn      *ninja.Connection
	sendEvent func(event string, payload interface{}) error

	devices map[uint64]*Device

	NetworkReady chan bool

	nwkmgrConn  *zigbee.ZStackNwkMgr
	gatewayConn *zigbee.ZStackGateway
	otaConn     *zigbee.ZStackOta
	config      *DriverConfig
}

func NewDriver() *Driver {
	return &Driver{
		NetworkReady: make(chan bool),
	}
}

type Device struct {
	info       *model.Device
	driver     *Driver
	deviceInfo *nwkmgr.NwkDeviceInfoT
	channels   []Channel
	sendEvent  func(event string, payload interface{}) error
}

type Channel struct {
	device   *Device
	endpoint *nwkmgr.NwkSimpleDescriptorT
}

func (d *Driver) GetModuleInfo() *model.Module {
	return info
}

func (d *Driver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}

func (d *Driver) Reset(hard bool) error {
	return d.nwkmgrConn.Reset(hard)
}

func (d *Driver) Start(config *DriverConfig) error {
	d.config = config
	return d.sendEvent("config", config)
}

func (d *Driver) Stop() error {
	return fmt.Errorf("This driver does not support being stopped. YOU HAVE NO POWER HERE.")
}

func (d *Driver) StartPairing(period uint32) (*uint32, error) {
	err := d.PermitJoin(uint32(period))
	if err != nil {
		err = fmt.Errorf("permit Join failed: %v", err)
		log.Errorf("%s", err)
	}
	return &period, err
}

func (d *Driver) OnPairingRequest(req *events.PairingRequest, topicKeys map[string]string) bool {
	log.Debugf("Pairing request of %d seconds received from %s", req.Duration, topicKeys["deviceId"])
	d.PermitJoin(uint32(req.Duration))
	return true
}

func (d *Driver) PermitJoin(period uint32) error {

	log.Infof("Join window will open for %d seconds.", period)

	//joinTime := uint32(30)
	permitJoinRequest := &nwkmgr.NwkSetPermitJoinReq{
		PermitJoinTime: &period,
		PermitJoin:     nwkmgr.NwkPermitJoinTypeT_PERMIT_ALL.Enum(),
	}

	permitJoinResponse := &nwkmgr.NwkZigbeeGenericCnf{}

	go func() {
		// logging the close of the join window is helpful when debugging
		// join behaviour.
		time.Sleep(time.Duration(period) * time.Second)
		log.Infof("Join window has closed after %d seconds.", period)
	}()
	err := d.nwkmgrConn.SendCommand(permitJoinRequest, permitJoinResponse)
	if err != nil {
		return fmt.Errorf("Failed to enable joining: %s", err)
	}
	if permitJoinResponse.Status.String() != "STATUS_SUCCESS" {
		return fmt.Errorf("Failed to enable joining: %s", permitJoinResponse.Status)
	}
	//log.Println("Permit join response: ")
	//outJSON(permitJoinResponse)

	return nil
}

func (d *Driver) Connect(cfg *ZStackConfig, networkReady chan bool) error {

	waitUntilZStackReady(config.StableFlagFile)

	d.devices = make(map[uint64]*Device)

	conn, err := ninja.Connect("com.ninjablocks.zigbee")
	if err != nil {
		return fmt.Errorf("Could not connect to MQTT: %s", err)
	}

	userAgent := conn.GetServiceClient("$device/:deviceId/channel/user-agent")
	err = userAgent.OnEvent("pairing-requested", d.OnPairingRequest)
	if err != nil {
		return fmt.Errorf("Failed register user-agent service client: %s", err)
	}

	err = conn.ExportDriver(d)
	if err != nil {
		return fmt.Errorf("Could not export driver: %s", err)
	}

	d.nwkmgrConn, err = zigbee.ConnectToNwkMgrServer(cfg.Hostname, cfg.NwkmgrPort)
	if err != nil {
		return fmt.Errorf("Error connecting to nwkmgr %s", err)
	}
	d.nwkmgrConn.OnDeviceFound = func(deviceInfo *nwkmgr.NwkDeviceInfoT) {
		d.onDeviceFound(deviceInfo)
	}

	done := false
	d.nwkmgrConn.OnNetworkReady = func() {
		if !done {
			done = true
			networkReady <- true
		}
	}

	d.otaConn, err = zigbee.ConnectToOtaServer(cfg.Hostname, cfg.OtasrvrPort)
	if err != nil {
		return fmt.Errorf("Error connecting to ota server %s", err)
	}

	d.gatewayConn, err = zigbee.ConnectToGatewayServer(cfg.Hostname, cfg.GatewayPort)
	if err != nil {
		return fmt.Errorf("Error connecting to gateway %s", err)
	}

	/*keyResponse := &nwkmgr.NwkZigbeeGenericCnf{}

	keyRequest := &nwkmgr.NwkChangeNwkKeyReq{
		NewKey: []byte{0x5a, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6c, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x30, 0x39},
	}

	err = d.nwkmgrConn.SendCommand(keyRequest, keyResponse)
	if err != nil {
		return fmt.Errorf("Failed setting network key: %s", err)
	}

	spew.Dump(keyResponse)
	log.Println("Sleeping for 10 seconds after setting network key")

	time.Sleep(10 * time.Second)*/

	networkInfo := &nwkmgr.NwkZigbeeNwkInfoCnf{}

	err = d.nwkmgrConn.SendCommand(&nwkmgr.NwkZigbeeNwkInfoReq{}, networkInfo)
	if err != nil {
		return fmt.Errorf("Failed getting network info: %s", err)
	}

	if *networkInfo.Status == nwkmgr.NwkNetworkStatusT_NWK_DOWN {
		return fmt.Errorf("The ZigBee network is down")
	}

	localDevice := &nwkmgr.NwkGetLocalDeviceInfoCnf{}

	err = d.nwkmgrConn.SendCommand(&nwkmgr.NwkGetLocalDeviceInfoReq{}, localDevice)
	if err != nil {
		return fmt.Errorf("Failed getting local device info: %s", err)
	}

	spew.Dump("device info", localDevice.String())

	networkKey := &nwkmgr.NwkGetNwkKeyCnf{}

	err = d.nwkmgrConn.SendCommand(&nwkmgr.NwkGetNwkKeyReq{}, networkKey)
	if err != nil {
		return fmt.Errorf("Failed getting network key: %s", err)
	}

	spew.Dump(networkKey)

	log.Infof("Started coordinator. Channel:%d Pan ID:0x%X Key:% X", *networkInfo.NwkChannel, *networkInfo.PanId, networkKey.NewKey)

	return nil
}

func (d *Driver) FetchDevices() error {

	return d.nwkmgrConn.FetchDeviceList()

}

func (d *Device) GetDriver() ninja.Driver {
	return d.driver
}

func (d *Device) GetDeviceInfo() *model.Device {
	return d.info
}

func (d *Device) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}

func (d *Device) getBasicInfo() error {

	log.Debugf("Getting basic information from %X", *d.deviceInfo.IeeeAddress)

	cluster := ClusterIDBasic
	ManufacturerNameAttribute := uint32(0x004)
	ModelIdentifierAttribute := uint32(0x005)

	request := &gateway.GwReadDeviceAttributeReq{
		DstAddress: &gateway.GwAddressStructT{
			AddressType: gateway.GwAddressTypeT_UNICAST.Enum(),
			IeeeAddr:    d.deviceInfo.IeeeAddress,
		},
		ClusterId:     &cluster,
		AttributeList: []uint32{ManufacturerNameAttribute, ModelIdentifierAttribute},
	}

	response := &gateway.GwReadDeviceAttributeRspInd{}
	err := d.driver.gatewayConn.SendAsyncCommand(request, response, 10*time.Second)
	if err != nil {
		return fmt.Errorf("Error getting basic device information state : %s", err)
	}
	if response.Status.String() != "STATUS_SUCCESS" {
		return fmt.Errorf("Failed to get basic device information. status: %s", response.Status.String())
	}

	sigs := make(map[string]string)

	manufacturerName := ""
	modelIdentifier := ""

	for _, attribute := range response.AttributeRecordList {

		switch *attribute.AttributeId {
		case ManufacturerNameAttribute:
			manufacturerName = string(attribute.AttributeValue)
		case ModelIdentifierAttribute:
			modelIdentifier = string(attribute.AttributeValue)
		default:
			log.Debugf("Unknown attribute returned when finding basic info %s", *attribute.AttributeId)
		}
	}

	sigs["zigbee:ManufacturerName"] = manufacturerName
	sigs["zigbee:ModelIdentifier"] = modelIdentifier

	name := fmt.Sprintf("%s by %s", modelIdentifier, manufacturerName)
	id := fmt.Sprintf("%X", *d.deviceInfo.IeeeAddress)

	d.info.Name = &name

	d.info.Signatures = &sigs
	d.info.NaturalIDType = "zigbee"
	d.info.NaturalID = id
	d.info.Name = &name

	return nil
}

func (d *Driver) onDeviceFound(deviceInfo *nwkmgr.NwkDeviceInfoT) {

	log.Debugf("\n\n")
	log.Debugf("---- Found Device IEEE:%X ----\f", *deviceInfo.IeeeAddress)

	if d.devices[*deviceInfo.IeeeAddress] != nil {
		log.Debugf("We've already seen this device")
	}

	/*sigs, _ := simplejson.NewJson([]byte(`{
	    "ninja:manufacturer": "Phillips",
	    "ninja:productName": "Hue",
	    "manufacturer:productModelId": "",
	    "ninja:productType": "Light",
	    "ninja:thingType": "light"
	}`))*/

	device := &Device{
		info:       &model.Device{},
		driver:     d,
		deviceInfo: deviceInfo,
	}

	err := device.getBasicInfo()
	if err != nil {
		log.Debugf("Failed to get basic info: %s", err)
		return
	}

	if d.Log.IsDebugEnabled() {
		spew.Dump(deviceInfo)
	}

	err = d.conn.ExportDevice(device)

	log.Debugf("Got device : %d", *deviceInfo.IeeeAddress)

	for _, endpoint := range deviceInfo.SimpleDescList {
		log.Debugf("Got endpoint : %d", *endpoint.EndpointId)

		if containsUInt32(endpoint.InputClusters, ClusterIDOnOff) {
			log.Debugf("This endpoint has on/off cluster")

			onOff := &OnOffChannel{
				Channel{
					device:   device,
					endpoint: endpoint,
				},
				nil,
			}

			err := onOff.init()
			if err != nil {
				log.Errorf("Failed initialising on/off channel: %s", err)
			}

		}

		if containsUInt32(endpoint.InputClusters, ClusterIDPower) {
			log.Debugf("This endpoint has power cluster")

			power := &PowerChannel{
				Channel{
					device:   device,
					endpoint: endpoint,
				},
				nil,
			}

			err := power.init()
			if err != nil {
				log.Errorf("Failed initialising power channel: %s", err)
			}

		}

		if containsUInt32(endpoint.InputClusters, ClusterIDTemp) {
			log.Debugf("This endpoint has temperature cluster")

			temp := &TempChannel{
				Channel{
					device:   device,
					endpoint: endpoint,
				},
				nil,
			}

			err := temp.init()
			if err != nil {
				log.Errorf("Failed initialising temp channel: %s", err)
			}

		}

		if containsUInt32(endpoint.InputClusters, ClusterIDHumidity) {
			log.Debugf("This endpoint has humidity cluster")

			humidity := &HumidityChannel{
				Channel{
					device:   device,
					endpoint: endpoint,
				},
				nil,
			}

			err := humidity.init()
			if err != nil {
				log.Errorf("Failed initialising humidity channel: %s", err)
			}

		}

	}

	d.devices[*deviceInfo.IeeeAddress] = device

	log.Debugf("---- Finished Device IEEE:%X ----\n", *deviceInfo.IeeeAddress)

}

func getCurDir() string {
	pwd, _ := os.Getwd()
	return pwd + "/"
}

func containsUInt32(hackstack []uint32, needle uint32) bool {
	for _, cluster := range hackstack {
		if cluster == needle {
			return true
		}
	}
	return false
}

func waitUntilZStackReady(checkFile string) {
	if checkFile == "" {
		return
	}

	// cooperate with zigbeeHAgw so that we don't start the zigbee driver
	// until we look somewhat stable.
	log.Debugf("waiting until zigbeeHAgw writes %s", checkFile)
	for {
		if _, err := os.Stat(checkFile); err == nil {
			break
		} else {
			time.Sleep(time.Second)
		}
	}
	log.Debugf("%s detected. start up continues...", checkFile)
}
<|endoftext|>


<commit_before>package gossip

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/weaveworks/weave/common"
	"github.com/weaveworks/weave/router"
)

// Router to convey gossip from one gossiper to another, for testing
type unicastMessage struct {
	sender router.PeerName
	buf    []byte
}
type broadcastMessage struct {
	sender router.PeerName
	data   router.GossipData
}
type exitMessage struct {
	exitChan chan struct{}
}
type flushMessage struct {
	flushChan chan struct{}
}

type TestRouter struct {
	gossipChans map[router.PeerName]chan interface{}
	loss        float32 // 0.0 means no loss
}

func NewTestRouter(loss float32) *TestRouter {
	return &TestRouter{make(map[router.PeerName]chan interface{}, 100), loss}
}

func (grouter *TestRouter) Stop() {
	for peer := range grouter.gossipChans {
		grouter.RemovePeer(peer)
	}
}

func (grouter *TestRouter) gossipBroadcast(sender router.PeerName, update router.GossipData) error {
	for _, gossipChan := range grouter.gossipChans {
		select {
		case gossipChan <- broadcastMessage{sender: sender, data: update}:
		default: // drop the message if we cannot send it
			common.Log.Errorf("Dropping message")
		}
	}
	return nil
}

func (grouter *TestRouter) Flush() {
	for _, gossipChan := range grouter.gossipChans {
		flushChan := make(chan struct{})
		gossipChan <- flushMessage{flushChan: flushChan}
		<-flushChan
	}
}

func (grouter *TestRouter) RemovePeer(peer router.PeerName) {
	gossipChan := grouter.gossipChans[peer]
	resultChan := make(chan struct{})
	gossipChan <- exitMessage{exitChan: resultChan}
	<-resultChan
	delete(grouter.gossipChans, peer)
}

type TestRouterClient struct {
	router *TestRouter
	sender router.PeerName
}

func (grouter *TestRouter) run(sender router.PeerName, gossiper router.Gossiper, gossipChan chan interface{}) {
	gossipTimer := time.Tick(10 * time.Second)
	for {
		select {
		case gossip := <-gossipChan:
			switch message := gossip.(type) {
			case exitMessage:
				close(message.exitChan)
				return

			case flushMessage:
				close(message.flushChan)

			case unicastMessage:
				if rand.Float32() > (1.0 - grouter.loss) {
					continue
				}
				if err := gossiper.OnGossipUnicast(message.sender, message.buf); err != nil {
					panic(fmt.Sprintf("Error doing gossip unicast to %s: %s", message.sender, err))
				}

			case broadcastMessage:
				if rand.Float32() > (1.0 - grouter.loss) {
					continue
				}
				for _, msg := range message.data.Encode() {
					// TODO: this should call OnGossipBroadcast, and we should implement
					// 'trickle' gossip correctly in this mock.  But no one depends on this
					// difference for testing right now, so we abuse the interface here.
					diff, err := gossiper.OnGossip(msg)
					if err != nil {
						panic(fmt.Sprintf("Error doing gossip broadcast: %s", err))
					}
					if diff == nil {
						continue
					}
					// Sanity check - reconsuming the diff should yield nil
					for _, diffMsg := range diff.Encode() {
						if nextDiff, err := gossiper.OnGossip(diffMsg); err != nil {
							panic(fmt.Sprintf("Error doing gossip broadcast: %s", err))
						} else if nextDiff != nil {
							panic(fmt.Sprintf("Breach of gossip interface: %v != nil", nextDiff))
						}
					}
				}
			}
		case <-gossipTimer:
			grouter.gossipBroadcast(sender, gossiper.Gossip())
		}
	}
}

func (grouter *TestRouter) Connect(sender router.PeerName, gossiper router.Gossiper) router.Gossip {
	gossipChan := make(chan interface{}, 100)

	go grouter.run(sender, gossiper, gossipChan)

	grouter.gossipChans[sender] = gossipChan
	return TestRouterClient{grouter, sender}
}

func (client TestRouterClient) GossipUnicast(dstPeerName router.PeerName, buf []byte) error {
	select {
	case client.router.gossipChans[dstPeerName] <- unicastMessage{sender: client.sender, buf: buf}:
	default: // drop the message if we cannot send it
		common.Log.Errorf("Dropping message")
	}
	return nil
}

func (client TestRouterClient) GossipBroadcast(update router.GossipData) error {
	return client.router.gossipBroadcast(client.sender, update)
}
<commit_msg>do proper mock periodic gossip<commit_after>package gossip

import (
	"fmt"
	"math"
	"math/rand"
	"time"

	"github.com/weaveworks/weave/common"
	"github.com/weaveworks/weave/router"
)

// Router to convey gossip from one gossiper to another, for testing
type unicastMessage struct {
	sender router.PeerName
	buf    []byte
}
type broadcastMessage struct {
	sender router.PeerName
	data   router.GossipData
}
type gossipMessage struct {
	sender router.PeerName
	data   router.GossipData
}
type exitMessage struct {
	exitChan chan struct{}
}
type flushMessage struct {
	flushChan chan struct{}
}

type TestRouter struct {
	gossipChans map[router.PeerName]chan interface{}
	loss        float32 // 0.0 means no loss
}

func NewTestRouter(loss float32) *TestRouter {
	return &TestRouter{make(map[router.PeerName]chan interface{}, 100), loss}
}

func (grouter *TestRouter) Stop() {
	for peer := range grouter.gossipChans {
		grouter.RemovePeer(peer)
	}
}

func (grouter *TestRouter) gossipBroadcast(sender router.PeerName, update router.GossipData) error {
	for _, gossipChan := range grouter.gossipChans {
		select {
		case gossipChan <- broadcastMessage{sender: sender, data: update}:
		default: // drop the message if we cannot send it
			common.Log.Errorf("Dropping message")
		}
	}
	return nil
}

func (grouter *TestRouter) gossip(sender router.PeerName, update router.GossipData) error {
	count := int(math.Log2(float64(len(grouter.gossipChans))))
	for dest, gossipChan := range grouter.gossipChans {
		if dest == sender {
			continue
		}
		select {
		case gossipChan <- gossipMessage{sender: sender, data: update}:
		default: // drop the message if we cannot send it
			common.Log.Errorf("Dropping message")
		}
		count--
		if count <= 0 {
			break
		}
	}
	return nil
}

func (grouter *TestRouter) Flush() {
	for _, gossipChan := range grouter.gossipChans {
		flushChan := make(chan struct{})
		gossipChan <- flushMessage{flushChan: flushChan}
		<-flushChan
	}
}

func (grouter *TestRouter) RemovePeer(peer router.PeerName) {
	gossipChan := grouter.gossipChans[peer]
	resultChan := make(chan struct{})
	gossipChan <- exitMessage{exitChan: resultChan}
	<-resultChan
	delete(grouter.gossipChans, peer)
}

type TestRouterClient struct {
	router *TestRouter
	sender router.PeerName
}

func (grouter *TestRouter) run(sender router.PeerName, gossiper router.Gossiper, gossipChan chan interface{}) {
	gossipTimer := time.Tick(10 * time.Second)
	for {
		select {
		case gossip := <-gossipChan:
			switch message := gossip.(type) {
			case exitMessage:
				close(message.exitChan)
				return

			case flushMessage:
				close(message.flushChan)

			case unicastMessage:
				if rand.Float32() > (1.0 - grouter.loss) {
					continue
				}
				if err := gossiper.OnGossipUnicast(message.sender, message.buf); err != nil {
					panic(fmt.Sprintf("Error doing gossip unicast to %s: %s", message.sender, err))
				}

			case broadcastMessage:
				if rand.Float32() > (1.0 - grouter.loss) {
					continue
				}
				for _, msg := range message.data.Encode() {
					if _, err := gossiper.OnGossipBroadcast(message.sender, msg); err != nil {
						panic(fmt.Sprintf("Error doing gossip broadcast: %s", err))
					}
				}
			case gossipMessage:
				if rand.Float32() > (1.0 - grouter.loss) {
					continue
				}
				for _, msg := range message.data.Encode() {
					diff, err := gossiper.OnGossip(msg)
					if err != nil {
						panic(fmt.Sprintf("Error doing gossip: %s", err))
					}
					if diff == nil {
						continue
					}
					// Sanity check - reconsuming the diff should yield nil
					for _, diffMsg := range diff.Encode() {
						if nextDiff, err := gossiper.OnGossip(diffMsg); err != nil {
							panic(fmt.Sprintf("Error doing gossip: %s", err))
						} else if nextDiff != nil {
							panic(fmt.Sprintf("Breach of gossip interface: %v != nil", nextDiff))
						}
					}
					grouter.gossip(message.sender, diff)
				}
			}
		case <-gossipTimer:
			grouter.gossip(sender, gossiper.Gossip())
		}
	}
}

func (grouter *TestRouter) Connect(sender router.PeerName, gossiper router.Gossiper) router.Gossip {
	gossipChan := make(chan interface{}, 100)

	go grouter.run(sender, gossiper, gossipChan)

	grouter.gossipChans[sender] = gossipChan
	return TestRouterClient{grouter, sender}
}

func (client TestRouterClient) GossipUnicast(dstPeerName router.PeerName, buf []byte) error {
	select {
	case client.router.gossipChans[dstPeerName] <- unicastMessage{sender: client.sender, buf: buf}:
	default: // drop the message if we cannot send it
		common.Log.Errorf("Dropping message")
	}
	return nil
}

func (client TestRouterClient) GossipBroadcast(update router.GossipData) error {
	return client.router.gossipBroadcast(client.sender, update)
}
<|endoftext|>


<commit_before>// Package profile provides a simple way to manage runtime/pprof
// profiling of your Go application.
package profile

import (
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
)

// memProfileRate holds the rate for the memory profile.
var memProfileRate = 4096

const (
	cpuMode = iota
	memMode
	blockMode
)

type profile struct {
	// quiet suppresses informational messages during profiling.
	quiet bool

	// noShutdownHook controls whether the profiling package should
	// hook SIGINT to write profiles cleanly.
	noShutdownHook bool

	// mode holds the type of profiling that will be made
	mode int

	// path holds the base path where various profiling files are  written.
	// If blank, the base path will be generated by ioutil.TempDir.
	path string

	// closers holds the cleanup functions that run after each profile
	closers []func()
}

// NoShutdownHook controls whether the profiling package should
// hook SIGINT to write profiles cleanly.
// Programs with more sophisticated signal handling should set
// this to true and ensure the Stop() function returned from Start()
// is called during shutdown.
func NoShutdownHook(p *profile) { p.noShutdownHook = true }

// Quiet suppresses informational messages during profiling.
func Quiet(p *profile) { p.quiet = true }

// CPUProfile controls if cpu profiling will be enabled. It disables any previous profiling settings.
func CPUProfile(p *profile) { p.mode = cpuMode }

// MemProfile controls if memory profiling will be enabled. It disables any previous profiling settings.
func MemProfile(p *profile) { p.mode = memMode }

// MemProfileRate controls if memory profiling will be enabled. Additionally, it takes a parameter which
// allows the setting of the memory profile rate.
func MemProfileRate(rate int) func(*profile) {
	return func(p *profile) {
		memProfileRate = rate
		p.mode = memMode
	}
}

// BlockProfile controls if block (contention) profiling will be enabled. It disables any previous profiling settings.
func BlockProfile(p *profile) { p.mode = blockMode }

// ProfilePath controls the base path where various profiling
// files are written. If blank, the base path will be generated
// by ioutil.TempDir.
func ProfilePath(path string) func(*profile) {
	return func(p *profile) {
		p.path = path
	}
}

// Stop stops the profile and flushes any unwritten data.
func (p *profile) Stop() {
	for _, c := range p.closers {
		c()
	}
}

// Start starts a new profiling session.
// The caller should call the Stop method on the value returned
// to cleanly stop profiling.
func Start(options ...func(*profile)) interface {
	Stop()
} {
	var prof profile
	for _, option := range options {
		option(&prof)
	}

	path, err := func() (string, error) {
		if p := prof.path; p != "" {
			return p, os.MkdirAll(p, 0777)
		}
		return ioutil.TempDir("", "profile")
	}()

	if err != nil {
		log.Fatalf("profile: could not create initial output directory: %v", err)
	}

	switch prof.mode {
	case cpuMode:
		fn := filepath.Join(path, "cpu.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
		}
		if !prof.quiet {
			log.Printf("profile: cpu profiling enabled, %s", fn)
		}
		pprof.StartCPUProfile(f)
		prof.closers = append(prof.closers, func() {
			pprof.StopCPUProfile()
			f.Close()
		})

	case memMode:
		fn := filepath.Join(path, "mem.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
		}
		old := runtime.MemProfileRate
		runtime.MemProfileRate = memProfileRate
		if !prof.quiet {
			log.Printf("profile: memory profiling enabled (rate %d), %s", memProfileRate, fn)
		}
		prof.closers = append(prof.closers, func() {
			pprof.Lookup("heap").WriteTo(f, 0)
			f.Close()
			runtime.MemProfileRate = old
		})

	case blockMode:
		fn := filepath.Join(path, "block.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create block profile %q: %v", fn, err)
		}
		runtime.SetBlockProfileRate(1)
		if !prof.quiet {
			log.Printf("profile: block profiling enabled, %s", fn)
		}
		prof.closers = append(prof.closers, func() {
			pprof.Lookup("block").WriteTo(f, 0)
			f.Close()
			runtime.SetBlockProfileRate(0)
		})
	}

	if !prof.noShutdownHook {
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, os.Interrupt)
			<-c

			log.Println("profile: caught interrupt, stopping profiles")
			prof.Stop()

			os.Exit(0)
		}()
	}

	return &prof
}
<commit_msg>Added command line flags, locking mechanism and noOverride flag<commit_after>// Package profile provides a simple way to manage runtime/pprof
// profiling of your Go application.
package profile

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"sync/atomic"
)

// memProfileRate holds the rate for the memory profile.
var memProfileRate = 4096

// started signifies whether profiling is running (1 being 'Yes' and 0 being 'No')
var started uint32 = 0

var (
	cpuFlag    = flag.Bool("profile.cpu", false, "enables CPU profiling")
	memFlag    = flag.Bool("profile.mem", false, "enables memory profiling")
	blockFlag  = flag.Bool("profile.block", false, "enables block profiling")
	pathFlag   = flag.String("profile.path", "", "allows setting of the output directory")
	quietFlag  = flag.Bool("profile.quiet", false, "disables logging during profiling")
	noHookFlag = flag.Bool("profile.nohook", false, "enables hook on OS interrupt signals")
)

const (
	cpuMode = iota
	memMode
	blockMode
)

type profile struct {
	// quiet suppresses informational messages during profiling.
	quiet bool

	// noShutdownHook controls whether the profiling package should
	// hook SIGINT to write profiles cleanly.
	noShutdownHook bool

	// noOverride controls whether command line flags can override
	// the profile's settings or not.
	noOverride bool

	// mode holds the type of profiling that will be made
	mode int

	// path holds the base path where various profiling files are  written.
	// If blank, the base path will be generated by ioutil.TempDir.
	path string

	// closers holds the cleanup functions that run after each profile
	closers []func()
}

// NoShutdownHook controls whether the profiling package should
// hook SIGINT to write profiles cleanly.
// Programs with more sophisticated signal handling should set
// this to true and ensure the Stop() function returned from Start()
// is called during shutdown.
func NoShutdownHook(p *profile) { p.noShutdownHook = true }

// Quiet suppresses informational messages during profiling.
func Quiet(p *profile) { p.quiet = true }

// NoOverride protects this profile's settings from being overriden by command line flags.
func NoOverride(p *profile) { p.noOverride = true }

// CPUProfile controls if cpu profiling will be enabled. It disables any previous profiling settings.
func CPUProfile(p *profile) { p.mode = cpuMode }

// MemProfile controls if memory profiling will be enabled. It disables any previous profiling settings.
func MemProfile(p *profile) { p.mode = memMode }

// MemProfileRate controls if memory profiling will be enabled. Additionally, it takes a parameter which
// allows the setting of the memory profile rate.
func MemProfileRate(rate int) func(*profile) {
	return func(p *profile) {
		memProfileRate = rate
		p.mode = memMode
	}
}

// BlockProfile controls if block (contention) profiling will be enabled. It disables any previous profiling settings.
func BlockProfile(p *profile) { p.mode = blockMode }

// ProfilePath controls the base path where various profiling
// files are written. If blank, the base path will be generated
// by ioutil.TempDir.
func ProfilePath(path string) func(*profile) {
	return func(p *profile) {
		p.path = path
	}
}

// Stop stops the profile and flushes any unwritten data.
func (p *profile) Stop() {
	for _, c := range p.closers {
		c()
	}
}

// applyFlags overrides profile settings by applying command line flags.
func applyFlags(p *profile) {
	flag.Parse()

	switch {
	case *cpuFlag:
		p.mode = cpuMode
	case *memFlag:
		p.mode = memMode
	case *blockFlag:
		p.mode = blockMode
	}

	if *pathFlag != "" {
		p.path = *pathFlag
	}
	if *quietFlag {
		p.quiet = true
	}
	if *noHookFlag {
		p.noShutdownHook = true
	}
}

// Start starts a new profiling session.
// The caller should call the Stop method on the value returned
// to cleanly stop profiling.
func Start(options ...func(*profile)) interface {
	Stop()
} {
	var prof profile
	// disallow starting multiple profiles
	if !atomic.CompareAndSwapUint32(&started, 0, 1) {
		log.Println("profile: Start() ignored - can not run multiple profiles at the same time")
		return &prof
	}

	for _, option := range options {
		option(&prof)
	}

	if !prof.noOverride {
		applyFlags(&prof)
	}

	path, err := func() (string, error) {
		if p := prof.path; p != "" {
			return p, os.MkdirAll(p, 0777)
		}
		return ioutil.TempDir("", "profile")
	}()

	if err != nil {
		log.Fatalf("profile: could not create initial output directory: %v", err)
	}

	switch prof.mode {
	case cpuMode:
		fn := filepath.Join(path, "cpu.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
		}
		if !prof.quiet {
			log.Printf("profile: cpu profiling enabled, %s", fn)
		}
		pprof.StartCPUProfile(f)
		prof.closers = append(prof.closers, func() {
			pprof.StopCPUProfile()
			f.Close()
		})

	case memMode:
		fn := filepath.Join(path, "mem.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
		}
		old := runtime.MemProfileRate
		runtime.MemProfileRate = memProfileRate
		if !prof.quiet {
			log.Printf("profile: memory profiling enabled (rate %d), %s", memProfileRate, fn)
		}
		prof.closers = append(prof.closers, func() {
			pprof.Lookup("heap").WriteTo(f, 0)
			f.Close()
			runtime.MemProfileRate = old
		})

	case blockMode:
		fn := filepath.Join(path, "block.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create block profile %q: %v", fn, err)
		}
		runtime.SetBlockProfileRate(1)
		if !prof.quiet {
			log.Printf("profile: block profiling enabled, %s", fn)
		}
		prof.closers = append(prof.closers, func() {
			pprof.Lookup("block").WriteTo(f, 0)
			f.Close()
			runtime.SetBlockProfileRate(0)
		})
	}

	if !prof.noShutdownHook {
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, os.Interrupt)
			<-c

			log.Println("profile: caught interrupt, stopping profiles")
			prof.Stop()

			os.Exit(0)
		}()
	}

	prof.closers = append(prof.closers, func() {
		started = 0
	})

	return &prof
}
<|endoftext|>


<commit_before><commit_msg>Add jekyll-archives<commit_after><|endoftext|>


<commit_before>package ami

import (
	"errors"
	"fmt"
	"strings"
)

// Connect verify connect response.
func Connect(client Client) (bool, error) {
	if answer, err := client.Recv(); err != nil || !strings.Contains(answer, "Asterisk Call Manager") {
		return false, errors.New("manager: Invalid parameters")
	}
	return true, nil
}

// Login provides the login manager.
func Login(client Client, user, secret, events, actionID string) error {
	var login = struct {
		Username string `ami:"Username"`
		Secret   string `ami:"Secret"`
		Events   string `ami:"Events,omitempty"`
	}{Username: user, Secret: secret, Events: events}
	resp, err := send(client, "Login", actionID, login)
	if err != nil {
		return err
	}
	if ok := resp.Get("Response"); ok != "Success" {
		return fmt.Errorf("login failed: %v", resp.Get("Message"))
	}
	return nil
}

// Logoff logoff the current manager session.
func Logoff(client Client, actionID string) error {
	resp, err := send(client, "Logoff", actionID, nil)
	if err != nil {
		return err
	}
	if msg := resp.Get("Response"); msg != "Goodbye" {
		return fmt.Errorf("logout failed: %v", resp.Get("Message"))
	}
	return nil
}

// Ping action will ellicit a 'Pong' response.
// Used to keep the manager connection open.
func Ping(client Client, actionID string) error {
	resp, err := send(client, "Ping", actionID, nil)
	if err != nil {
		return err
	}
	if ok := resp.Get("Response"); ok != "Success" {
		return fmt.Errorf("ping failed: %v", resp.Get("Message"))
	}
	return nil
}

// Challenge generates a challenge for MD5 authentication.
func Challenge(client Client, actionID string) (Response, error) {
	return send(client, "Challenge", actionID, map[string]string{
		"AuthType": "MD5",
	})
}

// Command executes an Asterisk CLI Command.
func Command(client Client, actionID, cmd string) (Response, error) {
	return send(client, "Command", actionID, map[string]string{
		"Command": cmd,
	})
}

// CoreSettings shows PBX core settings (version etc).
func CoreSettings(client Client, actionID string) (Response, error) {
	return send(client, "CoreSettings", actionID, nil)
}

// CoreStatus shows PBX core status variables.
func CoreStatus(client Client, actionID string) (Response, error) {
	return send(client, "CoreStatus", actionID, nil)
}

// CreateConfig creates an empty file in the configuration directory.
// This action will create an empty file in the configuration directory.
// This action is intended to be used before an UpdateConfig action.
func CreateConfig(client Client, actionID, filename string) (Response, error) {
	return send(client, "CreateConfig", actionID, map[string]string{
		"Filename": filename,
	})
}

// DataGet retrieves the data api tree.
func DataGet(client Client, actionID, path, search, filter string) (Response, error) {
	return send(client, "DataGet", actionID, map[string]string{
		"Path":   path,
		"Search": search,
		"Filter": filter,
	})
}

// EventFlow control Event Flow.
// Enable/Disable sending of events to this manager client.
func EventFlow(client Client, actionID, eventMask string) (Response, error) {
	return send(client, "Events", actionID, map[string]string{
		"EventMask": eventMask,
	})
}

// GetConfig retrieves configuration.
// This action will dump the contents of a configuration file by category and contents or optionally by specified category only.
func GetConfig(client Client, actionID, filename, category string) (Response, error) {
	return send(client, "GetConfig", actionID, map[string]string{
		"Filename": filename,
		"Category": category,
	})
}

// GetConfigJSON retrieves configuration (JSON format).
// This action will dump the contents of a configuration file by category and contents in JSON format.
// This only makes sense to be used using rawman over the HTTP interface.
func GetConfigJSON(client Client, actionID, filename string) (Response, error) {
	return send(client, "GetConfigJSON", actionID, map[string]string{
		"Filename": filename,
	})
}

// JabberSend sends a message to a Jabber Client.
func JabberSend(client Client, actionID, jabber, jid, message string) (Response, error) {
	return send(client, "JabberSend", actionID, map[string]string{
		"Jabber":  jabber,
		"JID":     jid,
		"Message": message,
	})
}

// ListCommands lists available manager commands.
// Returns the action name and synopsis for every action that is available to the user
func ListCommands(client Client, actionID string) (Response, error) {
	return send(client, "ListCommands", actionID, nil)
}

// ListCategories lists categories in configuration file.
func ListCategories(client Client, actionID, filename string) (Response, error) {
	return send(client, "ListCategories", actionID, map[string]string{
		"Filename": filename,
	})
}

// ModuleCheck checks if module is loaded.
// Checks if Asterisk module is loaded. Will return Success/Failure. For success returns, the module revision number is included.
func ModuleCheck(client Client, actionID, module string) (Response, error) {
	return send(client, "ModuleCheck", actionID, map[string]string{
		"Module": module,
	})
}

// ModuleLoad module management.
// Loads, unloads or reloads an Asterisk module in a running system.
func ModuleLoad(client Client, actionID, module, loadType string) (Response, error) {
	return send(client, "ModuleLoad", actionID, map[string]string{
		"Module":   module,
		"LoadType": loadType,
	})
}

// Reload Sends a reload event.
func Reload(client Client, actionID, module string) (Response, error) {
	return send(client, "Reload", actionID, map[string]string{
		"Module": module,
	})
}

// ShowDialPlan shows dialplan contexts and extensions
// Be aware that showing the full dialplan may take a lot of capacity.
func ShowDialPlan(client Client, actionID, extension, context string) (Response, error) {
	return send(client, "ShowDialPlan", actionID, map[string]string{
		"Extension": extension,
		"Context":   context,
	})
}

// Events gets events from current client connection
// It is mandatory set 'events' of ami.Login with "system,call,all,user", to received events.
func Events(client Client) (Response, error) {
	return read(client)
}

// Filter dinamically add filters for the current manager session.
func Filter(client Client, actionID, operation, filter string) (Response, error) {
	return send(client, "ShowDialPlan", actionID, map[string]string{
		"Operation": operation,
		"Filter":    filter,
	})
}

// PRIShowSpans show status of PRI spans.
func PRIShowSpans(client Client, actionID, span string) (Response, error) {
	return send(client, "PRIShowSpans", actionID, map[string]string{
		"Span": span,
	})
}
<commit_msg>Fix action sent for Filter function.<commit_after>package ami

import (
	"errors"
	"fmt"
	"strings"
)

// Connect verify connect response.
func Connect(client Client) (bool, error) {
	if answer, err := client.Recv(); err != nil || !strings.Contains(answer, "Asterisk Call Manager") {
		return false, errors.New("manager: Invalid parameters")
	}
	return true, nil
}

// Login provides the login manager.
func Login(client Client, user, secret, events, actionID string) error {
	var login = struct {
		Username string `ami:"Username"`
		Secret   string `ami:"Secret"`
		Events   string `ami:"Events,omitempty"`
	}{Username: user, Secret: secret, Events: events}
	resp, err := send(client, "Login", actionID, login)
	if err != nil {
		return err
	}
	if ok := resp.Get("Response"); ok != "Success" {
		return fmt.Errorf("login failed: %v", resp.Get("Message"))
	}
	return nil
}

// Logoff logoff the current manager session.
func Logoff(client Client, actionID string) error {
	resp, err := send(client, "Logoff", actionID, nil)
	if err != nil {
		return err
	}
	if msg := resp.Get("Response"); msg != "Goodbye" {
		return fmt.Errorf("logout failed: %v", resp.Get("Message"))
	}
	return nil
}

// Ping action will ellicit a 'Pong' response.
// Used to keep the manager connection open.
func Ping(client Client, actionID string) error {
	resp, err := send(client, "Ping", actionID, nil)
	if err != nil {
		return err
	}
	if ok := resp.Get("Response"); ok != "Success" {
		return fmt.Errorf("ping failed: %v", resp.Get("Message"))
	}
	return nil
}

// Challenge generates a challenge for MD5 authentication.
func Challenge(client Client, actionID string) (Response, error) {
	return send(client, "Challenge", actionID, map[string]string{
		"AuthType": "MD5",
	})
}

// Command executes an Asterisk CLI Command.
func Command(client Client, actionID, cmd string) (Response, error) {
	return send(client, "Command", actionID, map[string]string{
		"Command": cmd,
	})
}

// CoreSettings shows PBX core settings (version etc).
func CoreSettings(client Client, actionID string) (Response, error) {
	return send(client, "CoreSettings", actionID, nil)
}

// CoreStatus shows PBX core status variables.
func CoreStatus(client Client, actionID string) (Response, error) {
	return send(client, "CoreStatus", actionID, nil)
}

// CreateConfig creates an empty file in the configuration directory.
// This action will create an empty file in the configuration directory.
// This action is intended to be used before an UpdateConfig action.
func CreateConfig(client Client, actionID, filename string) (Response, error) {
	return send(client, "CreateConfig", actionID, map[string]string{
		"Filename": filename,
	})
}

// DataGet retrieves the data api tree.
func DataGet(client Client, actionID, path, search, filter string) (Response, error) {
	return send(client, "DataGet", actionID, map[string]string{
		"Path":   path,
		"Search": search,
		"Filter": filter,
	})
}

// EventFlow control Event Flow.
// Enable/Disable sending of events to this manager client.
func EventFlow(client Client, actionID, eventMask string) (Response, error) {
	return send(client, "Events", actionID, map[string]string{
		"EventMask": eventMask,
	})
}

// GetConfig retrieves configuration.
// This action will dump the contents of a configuration file by category and contents or optionally by specified category only.
func GetConfig(client Client, actionID, filename, category string) (Response, error) {
	return send(client, "GetConfig", actionID, map[string]string{
		"Filename": filename,
		"Category": category,
	})
}

// GetConfigJSON retrieves configuration (JSON format).
// This action will dump the contents of a configuration file by category and contents in JSON format.
// This only makes sense to be used using rawman over the HTTP interface.
func GetConfigJSON(client Client, actionID, filename string) (Response, error) {
	return send(client, "GetConfigJSON", actionID, map[string]string{
		"Filename": filename,
	})
}

// JabberSend sends a message to a Jabber Client.
func JabberSend(client Client, actionID, jabber, jid, message string) (Response, error) {
	return send(client, "JabberSend", actionID, map[string]string{
		"Jabber":  jabber,
		"JID":     jid,
		"Message": message,
	})
}

// ListCommands lists available manager commands.
// Returns the action name and synopsis for every action that is available to the user
func ListCommands(client Client, actionID string) (Response, error) {
	return send(client, "ListCommands", actionID, nil)
}

// ListCategories lists categories in configuration file.
func ListCategories(client Client, actionID, filename string) (Response, error) {
	return send(client, "ListCategories", actionID, map[string]string{
		"Filename": filename,
	})
}

// ModuleCheck checks if module is loaded.
// Checks if Asterisk module is loaded. Will return Success/Failure. For success returns, the module revision number is included.
func ModuleCheck(client Client, actionID, module string) (Response, error) {
	return send(client, "ModuleCheck", actionID, map[string]string{
		"Module": module,
	})
}

// ModuleLoad module management.
// Loads, unloads or reloads an Asterisk module in a running system.
func ModuleLoad(client Client, actionID, module, loadType string) (Response, error) {
	return send(client, "ModuleLoad", actionID, map[string]string{
		"Module":   module,
		"LoadType": loadType,
	})
}

// Reload Sends a reload event.
func Reload(client Client, actionID, module string) (Response, error) {
	return send(client, "Reload", actionID, map[string]string{
		"Module": module,
	})
}

// ShowDialPlan shows dialplan contexts and extensions
// Be aware that showing the full dialplan may take a lot of capacity.
func ShowDialPlan(client Client, actionID, extension, context string) (Response, error) {
	return send(client, "ShowDialPlan", actionID, map[string]string{
		"Extension": extension,
		"Context":   context,
	})
}

// Events gets events from current client connection
// It is mandatory set 'events' of ami.Login with "system,call,all,user", to received events.
func Events(client Client) (Response, error) {
	return read(client)
}

// Filter dinamically add filters for the current manager session.
func Filter(client Client, actionID, operation, filter string) (Response, error) {
	return send(client, "Filter", actionID, map[string]string{
		"Operation": operation,
		"Filter":    filter,
	})
}

// PRIShowSpans show status of PRI spans.
func PRIShowSpans(client Client, actionID, span string) (Response, error) {
	return send(client, "PRIShowSpans", actionID, map[string]string{
		"Span": span,
	})
}
<|endoftext|>