<commit_before>package mount // import "github.com/docker/docker/pkg/mount"

import (
	"sort"
	"strings"

	"syscall"

	"github.com/sirupsen/logrus"
)

// FilterFunc is a type defining a callback function
// to filter out unwanted entries. It takes a pointer
// to an Info struct (not fully populated, currently
// only Mountpoint is filled in), and returns two booleans:
//  - skip: true if the entry should be skipped
//  - stop: true if parsing should be stopped after the entry
type FilterFunc func(*Info) (skip, stop bool)

// PrefixFilter discards all entries whose mount points
// do not start with a prefix specified
func PrefixFilter(prefix string) FilterFunc {
	return func(m *Info) (bool, bool) {
		skip := !strings.HasPrefix(m.Mountpoint, prefix)
		return skip, false
	}
}

// SingleEntryFilter looks for a specific entry
func SingleEntryFilter(mp string) FilterFunc {
	return func(m *Info) (bool, bool) {
		if m.Mountpoint == mp {
			return false, true // don't skip, stop now
		}
		return true, false // skip, keep going
	}
}

// ParentsFilter returns all entries whose mount points
// can be parents of a path specified, discarding others.
// For example, given `/var/lib/docker/something`, entries
// like `/var/lib/docker`, `/var` and `/` are returned.
func ParentsFilter(path string) FilterFunc {
	return func(m *Info) (bool, bool) {
		skip := !strings.HasPrefix(path, m.Mountpoint)
		return skip, false
	}
}

// GetMounts retrieves a list of mounts for the current running process,
// with an optional filter applied (use nil for no filter).
func GetMounts(f FilterFunc) ([]*Info, error) {
	return parseMountTable(f)
}

// Mounted determines if a specified mountpoint has been mounted.
// On Linux it looks at /proc/self/mountinfo.
func Mounted(mountpoint string) (bool, error) {
	entries, err := GetMounts(SingleEntryFilter(mountpoint))
	if err != nil {
		return false, err
	}

	return len(entries) > 0, nil
}

// Mount will mount filesystem according to the specified configuration, on the
// condition that the target path is *not* already mounted. Options must be
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
// flags.go for supported option flags.
func Mount(device, target, mType, options string) error {
	flag, _ := parseOptions(options)
	if flag&REMOUNT != REMOUNT {
		if mounted, err := Mounted(target); err != nil || mounted {
			return err
		}
	}
	return ForceMount(device, target, mType, options)
}

// ForceMount will mount a filesystem according to the specified configuration,
// *regardless* if the target path is not already mounted. Options must be
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
// flags.go for supported option flags.
func ForceMount(device, target, mType, options string) error {
	flag, data := parseOptions(options)
	return mount(device, target, mType, uintptr(flag), data)
}

// Unmount lazily unmounts a filesystem on supported platforms, otherwise
// does a normal unmount.
func Unmount(target string) error {
	if mounted, err := Mounted(target); err != nil || !mounted {
		return err
	}
	return unmount(target, mntDetach)
}

// RecursiveUnmount unmounts the target and all mounts underneath, starting with
// the deepsest mount first.
func RecursiveUnmount(target string) error {
	mounts, err := parseMountTable(PrefixFilter(target))
	if err != nil {
		return err
	}

	// Make the deepest mount be first
	sort.Slice(mounts, func(i, j int) bool {
		return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint)
	})

	for i, m := range mounts {
		logrus.Debugf("Trying to unmount %s", m.Mountpoint)
		err = unmount(m.Mountpoint, mntDetach)
		if err != nil {
			// If the error is EINVAL either this whole package is wrong (invalid flags passed to unmount(2)) or this is
			// not a mountpoint (which is ok in this case).
			// Meanwhile calling `Mounted()` is very expensive.
			//
			// We've purposefully used `syscall.EINVAL` here instead of `unix.EINVAL` to avoid platform branching
			// Since `EINVAL` is defined for both Windows and Linux in the `syscall` package (and other platforms),
			//   this is nicer than defining a custom value that we can refer to in each platform file.
			if err == syscall.EINVAL {
				continue
			}
			if i == len(mounts)-1 {
				if mounted, e := Mounted(m.Mountpoint); e != nil || mounted {
					return err
				}
				continue
			}
			// This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem
			logrus.WithError(err).Warnf("Failed to unmount submount %s", m.Mountpoint)
			continue
		}

		logrus.Debugf("Unmounted %s", m.Mountpoint)
	}
	return nil
}
<commit_msg>mount.Unmount(): don't look into /proc/self/mountinfo<commit_after>package mount // import "github.com/docker/docker/pkg/mount"

import (
	"sort"
	"strings"
	"syscall"

	"github.com/sirupsen/logrus"
)

// FilterFunc is a type defining a callback function
// to filter out unwanted entries. It takes a pointer
// to an Info struct (not fully populated, currently
// only Mountpoint is filled in), and returns two booleans:
//  - skip: true if the entry should be skipped
//  - stop: true if parsing should be stopped after the entry
type FilterFunc func(*Info) (skip, stop bool)

// PrefixFilter discards all entries whose mount points
// do not start with a prefix specified
func PrefixFilter(prefix string) FilterFunc {
	return func(m *Info) (bool, bool) {
		skip := !strings.HasPrefix(m.Mountpoint, prefix)
		return skip, false
	}
}

// SingleEntryFilter looks for a specific entry
func SingleEntryFilter(mp string) FilterFunc {
	return func(m *Info) (bool, bool) {
		if m.Mountpoint == mp {
			return false, true // don't skip, stop now
		}
		return true, false // skip, keep going
	}
}

// ParentsFilter returns all entries whose mount points
// can be parents of a path specified, discarding others.
// For example, given `/var/lib/docker/something`, entries
// like `/var/lib/docker`, `/var` and `/` are returned.
func ParentsFilter(path string) FilterFunc {
	return func(m *Info) (bool, bool) {
		skip := !strings.HasPrefix(path, m.Mountpoint)
		return skip, false
	}
}

// GetMounts retrieves a list of mounts for the current running process,
// with an optional filter applied (use nil for no filter).
func GetMounts(f FilterFunc) ([]*Info, error) {
	return parseMountTable(f)
}

// Mounted determines if a specified mountpoint has been mounted.
// On Linux it looks at /proc/self/mountinfo.
func Mounted(mountpoint string) (bool, error) {
	entries, err := GetMounts(SingleEntryFilter(mountpoint))
	if err != nil {
		return false, err
	}

	return len(entries) > 0, nil
}

// Mount will mount filesystem according to the specified configuration, on the
// condition that the target path is *not* already mounted. Options must be
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
// flags.go for supported option flags.
func Mount(device, target, mType, options string) error {
	flag, _ := parseOptions(options)
	if flag&REMOUNT != REMOUNT {
		if mounted, err := Mounted(target); err != nil || mounted {
			return err
		}
	}
	return ForceMount(device, target, mType, options)
}

// ForceMount will mount a filesystem according to the specified configuration,
// *regardless* if the target path is not already mounted. Options must be
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
// flags.go for supported option flags.
func ForceMount(device, target, mType, options string) error {
	flag, data := parseOptions(options)
	return mount(device, target, mType, uintptr(flag), data)
}

// Unmount lazily unmounts a filesystem on supported platforms, otherwise
// does a normal unmount.
func Unmount(target string) error {
	err := unmount(target, mntDetach)
	if err == syscall.EINVAL {
		// ignore "not mounted" error
		err = nil
	}
	return err
}

// RecursiveUnmount unmounts the target and all mounts underneath, starting with
// the deepsest mount first.
func RecursiveUnmount(target string) error {
	mounts, err := parseMountTable(PrefixFilter(target))
	if err != nil {
		return err
	}

	// Make the deepest mount be first
	sort.Slice(mounts, func(i, j int) bool {
		return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint)
	})

	for i, m := range mounts {
		logrus.Debugf("Trying to unmount %s", m.Mountpoint)
		err = unmount(m.Mountpoint, mntDetach)
		if err != nil {
			// If the error is EINVAL either this whole package is wrong (invalid flags passed to unmount(2)) or this is
			// not a mountpoint (which is ok in this case).
			// Meanwhile calling `Mounted()` is very expensive.
			//
			// We've purposefully used `syscall.EINVAL` here instead of `unix.EINVAL` to avoid platform branching
			// Since `EINVAL` is defined for both Windows and Linux in the `syscall` package (and other platforms),
			//   this is nicer than defining a custom value that we can refer to in each platform file.
			if err == syscall.EINVAL {
				continue
			}
			if i == len(mounts)-1 {
				if mounted, e := Mounted(m.Mountpoint); e != nil || mounted {
					return err
				}
				continue
			}
			// This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem
			logrus.WithError(err).Warnf("Failed to unmount submount %s", m.Mountpoint)
			continue
		}

		logrus.Debugf("Unmounted %s", m.Mountpoint)
	}
	return nil
}
<|endoftext|>


<commit_before>// Golang support for LLSN - Allyst's data interchange format.
// LLSN specification http://allyst.org/opensource/llsn/

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// copyright (C) 2015 Allyst Inc. http://allyst.com
// author Taras Halturin <halturin@allyst.com>

package llsn

import (
	"bytes"
	"errors"
	"fmt"
	"reflect"
	"sync"
)

// global variables
var threshold uint16
var dir string
var version uint8

////////////////////////////////////////////////////////////////////////////////
// ENCODE routines
////////////////////////////////////////////////////////////////////////////////

// Encode method allows calling
//
// Encode(value)
// Encode(value, threshold)
//
// return nil in this case. all encoded data writes to the channel
// Encode(value, channel)
// Encode(value, channel, threshold)
func Encode(v interface{}, a ...interface{}) *bytes.Buffer {
	var value reflect.Value = reflect.ValueOf(v)
	var args []interface{} = a
	var channel chan []byte
	var buffer *bytes.Buffer
	var mutex = &sync.Mutex{}
	var done = sync.NewCond(mutex)

	switch len(args) {
	case 0:
		channel = make(chan []byte)
		buffer = new(bytes.Buffer)

	case 1:
		switch reflect.ValueOf(args[0]).Kind() {
		case reflect.Int:
			threshold = uint16(args[0].(int))
			channel = make(chan []byte)
			buffer = new(bytes.Buffer)

		case reflect.Chan:
			channel = args[0].(chan []byte)

		default:
			panic("wrong second argument")
		}

	case 2:
		channel = args[0].(chan []byte)
		threshold = uint16(args[1].(int))

	default:
		panic("wrong arguments")
	}

	if value.Kind() != reflect.Ptr || value.Elem().Kind() != reflect.Struct {
		panic("Incorrect type of the source (expect '*struct')")
	}
	value = value.Elem()

	// create internal channel handler
	if buffer != nil {
		go func() {

			mutex.Lock()
			for {
				b, ok := <-channel
				if ok {
					buffer.Write(b)
				} else {
					break
				}
			}
			done.Signal()
		}()

	}

	// encode it
	encode_ext(value, channel, threshold)

	// we should wait channel's routines in case of using internal handler
	if buffer != nil {
		done.Wait()
	}

	return buffer
}

func Decode(source interface{}, destination interface{}) (err error) {
	var value reflect.Value = reflect.ValueOf(destination)
	var buffer decodeBuffer

	defer func() {
		if r := recover(); r != nil {
			err = errors.New(fmt.Sprintf("Malformed data. (%s)", r))
		}

		if buffer.channel != nil {
			close(buffer.channel)
		}
	}()

	if value.Kind() != reflect.Ptr || value.Elem().Kind() != reflect.Struct {
		return errors.New("Incorrect type of the destination (expect '*struct')")
	}

	value = value.Elem()

	switch v := source.(type) {
	case []byte:
		buffer.init_buffer(v)

	case chan []byte:
		buffer.init_chan(v)

	default:
		return errors.New("Incorrect type of the source (expect 'chan []byte' or '[]byte'")
	}

	decode_ext(&buffer, &value)
	return err
}

func init() {
	threshold = DEFAULT_THRESHOLD
	dir = DECODE_FOLDER
}

func SetOption(name string, v interface{}) {
	switch name {
	case "threshold":
		threshold = uint16(v.(int))
	case "dir":
		dir = v.(string)

	default:
		panic("unknown option")
	}
}
<commit_msg>Fix: do not close alien channel<commit_after>// Golang support for LLSN - Allyst's data interchange format.
// LLSN specification http://allyst.org/opensource/llsn/

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// copyright (C) 2015 Allyst Inc. http://allyst.com
// author Taras Halturin <halturin@allyst.com>

package llsn

import (
	"bytes"
	"errors"
	"fmt"
	"reflect"
	"sync"
)

// global variables
var threshold uint16
var dir string
var version uint8

////////////////////////////////////////////////////////////////////////////////
// ENCODE routines
////////////////////////////////////////////////////////////////////////////////

// Encode method allows calling
//
// Encode(value)
// Encode(value, threshold)
//
// return nil in this case. all encoded data writes to the channel
// Encode(value, channel)
// Encode(value, channel, threshold)
func Encode(v interface{}, a ...interface{}) *bytes.Buffer {
	var value reflect.Value = reflect.ValueOf(v)
	var args []interface{} = a
	var channel chan []byte
	var buffer *bytes.Buffer
	var mutex = &sync.Mutex{}
	var done = sync.NewCond(mutex)

	switch len(args) {
	case 0:
		channel = make(chan []byte)
		buffer = new(bytes.Buffer)

	case 1:
		switch reflect.ValueOf(args[0]).Kind() {
		case reflect.Int:
			threshold = uint16(args[0].(int))
			channel = make(chan []byte)
			buffer = new(bytes.Buffer)

		case reflect.Chan:
			channel = args[0].(chan []byte)

		default:
			panic("wrong second argument")
		}

	case 2:
		channel = args[0].(chan []byte)
		threshold = uint16(args[1].(int))

	default:
		panic("wrong arguments")
	}

	if value.Kind() != reflect.Ptr || value.Elem().Kind() != reflect.Struct {
		panic("Incorrect type of the source (expect '*struct')")
	}
	value = value.Elem()

	// create internal channel handler
	if buffer != nil {
		go func() {

			mutex.Lock()
			for {
				b, ok := <-channel
				if ok {
					buffer.Write(b)
				} else {
					break
				}
			}
			done.Signal()
		}()

	}

	// encode it
	encode_ext(value, channel, threshold)

	// we should wait channel's routines in case of using internal handler
	if buffer != nil {
		done.Wait()
	}

	return buffer
}

func Decode(source interface{}, destination interface{}) (err error) {
	var value reflect.Value = reflect.ValueOf(destination)
	var buffer decodeBuffer

	defer func() {
		if r := recover(); r != nil {
			err = errors.New(fmt.Sprintf("Malformed data. (%s)", r))
		}
	}()

	if value.Kind() != reflect.Ptr || value.Elem().Kind() != reflect.Struct {
		return errors.New("Incorrect type of the destination (expect '*struct')")
	}

	value = value.Elem()

	switch v := source.(type) {
	case []byte:
		buffer.init_buffer(v)

	case chan []byte:
		buffer.init_chan(v)

	default:
		return errors.New("Incorrect type of the source (expect 'chan []byte' or '[]byte'")
	}

	decode_ext(&buffer, &value)
	return err
}

func init() {
	threshold = DEFAULT_THRESHOLD
	dir = DECODE_FOLDER
}

func SetOption(name string, v interface{}) {
	switch name {
	case "threshold":
		threshold = uint16(v.(int))
	case "dir":
		dir = v.(string)

	default:
		panic("unknown option")
	}
}
<|endoftext|>


<commit_before>package edgesearch

import (
	"github.com/unixpickle/gocube"
)

// A PhaseOneHeuristic records the move count for every phase-one state.
// A phase-one state is determined by the edge orientation case and the
// permutation of the E slice edges.
type PhaseOneHeuristic struct {
	ChooseMap map[int]int
	Counts    [1013760]int8
}

// NewPhaseOneHeuristic creates a PhaseOneHeuristic with zeroes for every count
// and a generated ChooseMap.
func NewPhaseOneHeuristic() *PhaseOneHeuristic {
	res := PhaseOneHeuristic{ChooseMap: map[int]int{}}

	// Generate the map of all cases for (12 choose 4). Here are some examples,
	// just so you get the idea:
	// [w|x|y|z| | | | | | | | ], [w| |x|y| | | | |z| | | ], etc.
	chooseVal := 0
	for w := uint(0); w < 9; w++ {
		for x := w + 1; x < 10; x++ {
			for y := x + 1; y < 11; y++ {
				for z := y + 1; z < 12; z++ {
					// The sub-optimal but simple encoding for the choice.
					fromVal := (1 << w) | (1 << x) | (1 << y) | (1 << z)
					res.ChooseMap[fromVal] = chooseVal
					chooseVal++
				}
			}
		}
	}

	return &res
}

// Encode returns a hash number between 0 (inclusive) and 1013760 (exclusive)
// corresponding to the given edge configuration.
func (h *PhaseOneHeuristic) Encode(c gocube.CubieEdges) int {
	// Turn the edges into a bitmap with 1's where there are E slice edges.
	chooseFlags := 0
	for i, p := range c {
		if p.Piece == 1 || p.Piece == 3 || p.Piece == 7 || p.Piece == 9 {
			chooseFlags |= 1 << uint(i)
		}
	}

	// Generate the two numerical components of the hash.
	chooseVal := h.ChooseMap[chooseFlags]
	eoVal := encodeEO(c)

	return chooseVal*0x800 + eoVal
}

// An OrientHeuristic stores the number of moves required to solve every EO
// configuration.
type OrientHeuristic [0x800]int

// MakeOrientHeuristic uses breadth-first search to generate an OrientHeuristic.
// This should run pretty fast.
func MakeOrientHeuristic(moves []gocube.Move) *OrientHeuristic {
	var res OrientHeuristic

	for i := 0; i < 0x800; i++ {
		res[i] = -1
	}

	// Perform a very basic breadth-first search.
	nodes := []searchNode{searchNode{gocube.SolvedCubieEdges(), 0}}
	for len(nodes) > 0 {
		node := nodes[0]
		nodes = nodes[1:]
		idx := encodeEO(node.State)

		if res[idx] >= 0 {
			// Node was already visited
			continue
		}

		// Expand the node
		res[idx] = node.Depth
		for _, move := range moves {
			state := node.State
			state.Move(move)
			nodes = append(nodes, searchNode{state, node.Depth + 1})
		}
	}

	return &res
}

// MinMoves returns the number of moves required to orient all the edges.
func (o *OrientHeuristic) MinMoves(e gocube.CubieEdges) int {
	return o[encodeEO(e)]
}

type searchNode struct {
	State gocube.CubieEdges
	Depth int
}

func encodeEO(e gocube.CubieEdges) int {
	res := 0
	for i := 0; i < 11; i++ {
		if e[i].Flip {
			res |= (1 << uint(i))
		}
	}
	return res
}
<commit_msg>generated and use phase1 heuristic<commit_after>package edgesearch

import (
	"github.com/unixpickle/gocube"
)

// A PhaseOneHeuristic records the move count for every phase-one state.
// A phase-one state is determined by the edge orientation case and the
// permutation of the E slice edges.
type PhaseOneHeuristic struct {
	ChooseMap map[int]int
	Counts    [1013760]int8
}

// MakePhaseOneHeuristic uses a breadth-first search to generate a
// PhaseOneHeuristic.
func MakePhaseOneHeuristic(moves []gocube.Move) *PhaseOneHeuristic {
	res := NewPhaseOneHeuristic()

	// Set every move count to -1 so we know which one's we haven't visited.
	for i := 0; i < 1013760; i++ {
		res.Counts[i] = -1
	}

	// Perform a very basic breadth-first search.
	nodes := []searchNode{searchNode{gocube.SolvedCubieEdges(), 0}}
	for len(nodes) > 0 {
		node := nodes[0]
		nodes = nodes[1:]
		idx := res.Encode(node.State)

		if res.Counts[idx] >= 0 {
			// Node was already visited
			continue
		}

		// Expand the node
		res.Counts[idx] = int8(node.Depth)
		for _, move := range moves {
			state := node.State
			state.Move(move)
			nodes = append(nodes, searchNode{state, node.Depth + 1})
		}
	}

	return res
}

// NewPhaseOneHeuristic creates a PhaseOneHeuristic with zeroes for every count
// and a generated ChooseMap.
func NewPhaseOneHeuristic() *PhaseOneHeuristic {
	res := PhaseOneHeuristic{ChooseMap: map[int]int{}}

	// Generate the map of all cases for (12 choose 4). Here are some examples,
	// just so you get the idea:
	// [w|x|y|z| | | | | | | | ], [w| |x|y| | | | |z| | | ], etc.
	chooseVal := 0
	for w := uint(0); w < 9; w++ {
		for x := w + 1; x < 10; x++ {
			for y := x + 1; y < 11; y++ {
				for z := y + 1; z < 12; z++ {
					// The sub-optimal but simple encoding for the choice.
					fromVal := (1 << w) | (1 << x) | (1 << y) | (1 << z)
					res.ChooseMap[fromVal] = chooseVal
					chooseVal++
				}
			}
		}
	}

	return &res
}

// Encode returns a hash number between 0 (inclusive) and 1013760 (exclusive)
// corresponding to the given edge configuration.
func (h *PhaseOneHeuristic) Encode(c gocube.CubieEdges) int {
	// Turn the edges into a bitmap with 1's where there are E slice edges.
	chooseFlags := 0
	for i, p := range c {
		if p.Piece == 1 || p.Piece == 3 || p.Piece == 7 || p.Piece == 9 {
			chooseFlags |= 1 << uint(i)
		}
	}

	// Generate the two numerical components of the hash.
	chooseVal := h.ChooseMap[chooseFlags]
	eoVal := encodeEO(c)

	return chooseVal*0x800 + eoVal
}

// MinMoves returns the minimum number of moves needed to reach the solved
// phase one state for a given set of edges.
func (h *PhaseOneHeuristic) MinMoves(c gocube.CubieEdges) int {
	return int(h.Counts[h.Encode(c)])
}

// An OrientHeuristic stores the number of moves required to solve every EO
// configuration.
type OrientHeuristic [0x800]int

// MakeOrientHeuristic uses breadth-first search to generate an OrientHeuristic.
// This should run pretty fast.
func MakeOrientHeuristic(moves []gocube.Move) *OrientHeuristic {
	var res OrientHeuristic

	for i := 0; i < 0x800; i++ {
		res[i] = -1
	}

	// Perform a very basic breadth-first search.
	nodes := []searchNode{searchNode{gocube.SolvedCubieEdges(), 0}}
	for len(nodes) > 0 {
		node := nodes[0]
		nodes = nodes[1:]
		idx := encodeEO(node.State)

		if res[idx] >= 0 {
			// Node was already visited
			continue
		}

		// Expand the node
		res[idx] = node.Depth
		for _, move := range moves {
			state := node.State
			state.Move(move)
			nodes = append(nodes, searchNode{state, node.Depth + 1})
		}
	}

	return &res
}

// MinMoves returns the number of moves required to orient all the edges.
func (o *OrientHeuristic) MinMoves(e gocube.CubieEdges) int {
	return o[encodeEO(e)]
}

type searchNode struct {
	State gocube.CubieEdges
	Depth int
}

func encodeEO(e gocube.CubieEdges) int {
	res := 0
	for i := 0; i < 11; i++ {
		if e[i].Flip {
			res |= (1 << uint(i))
		}
	}
	return res
}
<|endoftext|>


<commit_before>package rtos

import (
	"syscall"
)

// Debug allows write debug information.
type Debug int

func (d Debug) Write(b []byte) (int, error) {
	return syscall.DebugOut(int(d), b)
}

func (d Debug) WriteString(s string) (int, error) {
	return syscall.DebugOutString(int(d), s)
}<commit_msg>rtos: New Debug.WriteByte method.<commit_after>package rtos

import (
	"syscall"
)

// Debug allows write debug information.
type Debug int

func (d Debug) Write(b []byte) (int, error) {
	return syscall.DebugOut(int(d), b)
}

func (d Debug) WriteByte(b byte) error {
	_, err := syscall.DebugOut(int(d), []byte{b})
	return err
}

func (d Debug) WriteString(s string) (int, error) {
	return syscall.DebugOutString(int(d), s)
}
<|endoftext|>


<commit_before>/**
 * @file pulse.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU GPLv3
 * @date September, 2015
 * @brief generate game events
 *
 * Routine that generates game events
 */

package pulse

import (
	"crypto/rsa"
	"database/sql"
	"log"
	"time"
)

func Wait(end time.Time, timeout time.Duration) (waited bool) {

	if time.Now().After(end) {
		return false
	}

	for time.Now().Before(end) {
		time.Sleep(timeout)
	}

	return true
}

func Pulse(db *sql.DB, priv *rsa.PrivateKey, start_time time.Time,
	half, lunch, round_len, check_timeout time.Duration) (err error) {

	log.Println("Launching pulse...")

	lunch_start_time := start_time.Add(half)
	lunch_end_time := lunch_start_time.Add(lunch)
	end_time := lunch_end_time.Add(half)

	log.Println("Pulse start time", time.Now())

	log.Println("Contest start time", start_time)

	game, err := NewGame(db, priv, round_len, check_timeout)

	defer game.Over()

	timeout := 100 * time.Millisecond

	log.Println("Wait start time...")
	if Wait(start_time, timeout) {
		err = game.Run(lunch_start_time)
		if err != nil {
			return
		}
	}

	Wait(lunch_start_time, timeout)

	log.Println("Lunch...")
	if Wait(lunch_end_time, timeout) {
		err = game.Run(end_time)
		if err != nil {
			return
		}
	}

	Wait(end_time, timeout)

	return
}
<commit_msg>Now continue game (new round) if run after start<commit_after>/**
 * @file pulse.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU GPLv3
 * @date September, 2015
 * @brief generate game events
 *
 * Routine that generates game events
 */

package pulse

import (
	"crypto/rsa"
	"database/sql"
	"log"
	"time"
)

func Wait(end time.Time, timeout time.Duration) (waited bool) {

	if time.Now().After(end) {
		return false
	}

	for time.Now().Before(end) {
		time.Sleep(timeout)
	}

	return true
}

func Pulse(db *sql.DB, priv *rsa.PrivateKey, start_time time.Time,
	half, lunch, round_len, check_timeout time.Duration) (err error) {

	log.Println("Launching pulse...")

	lunch_start_time := start_time.Add(half)
	lunch_end_time := lunch_start_time.Add(lunch)
	end_time := lunch_end_time.Add(half)

	log.Println("Pulse start time", time.Now())

	log.Println("Contest start time", start_time)

	game, err := NewGame(db, priv, round_len, check_timeout)

	defer game.Over()

	timeout := 100 * time.Millisecond

	log.Println("Wait start time...")
	if Wait(start_time, timeout) || time.Now().Before(lunch_start_time) {
		log.Println("game run")
		err = game.Run(lunch_start_time)
		if err != nil {
			return
		}
	}

	log.Println("Wait lunch time")
	Wait(lunch_start_time, timeout)

	log.Println("Lunch...")
	if Wait(lunch_end_time, timeout) || time.Now().Before(end_time) {
		err = game.Run(end_time)
		if err != nil {
			return
		}
	}

	log.Println("Wait end time")
	Wait(end_time, timeout)

	return
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "time"

func main() {
	board := Board{}

	w := 20
	h := 25
	err := board.Connect(w, h, 4, 5)
	defer board.Free()

	if err != nil {
		fmt.Print("Error: ")
		fmt.Println(err)
		return
	}
	xPix := 0
	yPix := 0
	for {
		xPix++
		if xPix > w {
			xPix = 0
			yPix++
		}
		if yPix > h {
			xPix = 0
			yPix = 0
		}

		for x := 0; x < w; x++ {
			for y := 0; y < h; y++ {
				if x == xPix && y == yPix {
					board.DrawPixel(x, y, 100, 100, 100)
				} else {
					board.DrawPixel(x, y, 0, 0, 0)
				}
			}
		}
		board.Save()
		time.Sleep(20 * time.Millisecond)
	}
}
<commit_msg> added pretty blue light color to sine wave<commit_after>package main

import "fmt"
import "time"
import "math"

func main() {
	board := Board{}

	w := 20
	h := 25
	err := board.Connect(w, h, 4, 5)
	defer board.Free()

	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	offset := 0.0
	for {
		offset -= 0.2
		for x := 0; x < w; x++ {
			for y := 0; y < h; y++ {
				dx := x - 10
				dy := y - 10
				dis := math.Sqrt(float64(dx*dx + dy*dy))
				amt := int(math.Sin(dis+offset)*125.0 + 125.0)
				board.DrawPixel(x, y, amt, 0, 125-amt/2)
			}
		}
		board.Save()
		time.Sleep(20 * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>package os

import (
	"bytes"
	linuxproc "github.com/c9s/goprocinfo/linux"
	"log"
	"os/exec"
	"strconv"
	"strings"
)

// GetPsAuxCount using linux command "ps aux | grep process_name | wc -l" to get a process count from system environment
// It returns the number of requested process.
func GetPsAuxCount(pn string) int {
	ps := exec.Command("ps", "aux")
	grep := exec.Command("grep", pn)
	wc := exec.Command("wc", "-l")
	var out bytes.Buffer
	grep.Stdin, _ = ps.StdoutPipe()
	wc.Stdin, _ = grep.StdoutPipe()
	wc.Stdout = &out

	if err := wc.Start(); err != nil {
		log.Fatal("wc start", err)
	}
	if err := grep.Start(); err != nil {
		log.Fatal("grep start", err)
	}
	if err := ps.Run(); err != nil {
		log.Fatal("ps run", err)
	}
	if err := grep.Wait(); err != nil {
		log.Fatal("grep wait:", err)
	}
	if err := wc.Wait(); err != nil {
		log.Fatal("wc wait", err)
	}

	result, err := strconv.Atoi(strings.TrimSpace(out.String()))
	if err != nil {
		log.Fatal(err)
	}

	// Since ```grep``` itself is also included in the results
	// And we need none nil value for pipe command ```grep``` and ```wc```
	// So we have to drop it (result -1) here
	return result - 1
}

// Pass the `pipe` as `cmd` input, and run it
// It returns the result of cmd
func ExecuteCmd(cmd *exec.Cmd, pipe string) string {
	var out bytes.Buffer

	if pipe != "" {
		cmd.Stdin = strings.NewReader(pipe)
	}
	cmd.Stdout = &out
	if err := cmd.Run(); err != nil {
		log.Println("ooops:", err.Error())
		return ""
	}

	return out.String()
}

//Check whether/proc/meminfo MemFree/MemTotal is less than $mb MB
func IsFreeMemoryLessThanMB(mb int) bool {
	if stat, err := linuxproc.ReadMemInfo("/proc/meminfo"); err != nil {
		log.Fatal("meminfo read fail")
		return false
	} else {
		mem := ByteSize(stat["MemFree"]) * KB
		return mem < (ByteSize(mb))
	}
}
<commit_msg>Refactor psAuxCount to save memory usage<commit_after>package os

import (
	"bytes"
	linuxproc "github.com/c9s/goprocinfo/linux"
	"log"
	"os/exec"
	"strconv"
	"strings"
)

// GetPsAuxCount using linux command "ps aux | grep process_name | wc -l" to get a process count from system environment
// It returns the number of requested process.
func GetPsAuxCount(pn string) int {
	ps := exec.Command("ps", "aux")
	grep := exec.Command("grep", pn)
	wc := exec.Command("wc", "-l")

	psRes := ExecuteCmd(ps, "")
	grepRes := ExecuteCmd(grep, psRes)
	if grepRes == "" {
		return 0
	}

	// pass the `grep` result to `wc` input, and run it
	wcRes := ExecuteCmd(wc, grepRes)

	result, err := strconv.Atoi(strings.TrimSpace(wcRes))
	if err != nil {
		log.Fatal("strconv.Atoi error: ", err)
	}

	// Since ```grep``` itself is also included in the results
	// And we need none nil value for pipe command ```grep``` and ```wc```
	// So we have to drop it (result -1) here
	return result - 1
}

// Pass the `pipe` as `cmd` input, and run it
// It returns the result of cmd
func ExecuteCmd(cmd *exec.Cmd, pipe string) string {
	var out bytes.Buffer

	if pipe != "" {
		cmd.Stdin = strings.NewReader(pipe)
	}
	cmd.Stdout = &out
	if err := cmd.Run(); err != nil {
		log.Println("ooops:", err.Error())
		return ""
	}

	return out.String()
}

//Check whether/proc/meminfo MemFree/MemTotal is less than $mb MB
func IsFreeMemoryLessThanMB(mb int) bool {
	if stat, err := linuxproc.ReadMemInfo("/proc/meminfo"); err != nil {
		log.Fatal("meminfo read fail")
		return false
	} else {
		mem := ByteSize(stat["MemFree"]) * KB
		return mem < (ByteSize(mb))
	}
}
<|endoftext|>


<commit_before>package command

import (
	"context"
	"fmt"

	"github.com/hashicorp/vault/command/server"
	"github.com/hashicorp/vault/vault"
	"github.com/pkg/errors"
)

var (
	onEnterprise = false
)

func adjustCoreForSealMigration(ctx context.Context, core *vault.Core, coreConfig *vault.CoreConfig, seal vault.Seal, config *server.Config) error {
	existBarrierSealConfig, existRecoverySealConfig, err := core.PhysicalSealConfigs(context.Background())
	if err != nil {
		return fmt.Errorf("Error checking for existing seal: %s", err)
	}
	var existSeal vault.Seal
	var newSeal vault.Seal
	if existBarrierSealConfig != nil &&
		(existBarrierSealConfig.Type != seal.BarrierType() ||
			config.Seal != nil && config.Seal.Disabled) {
		// If the existing seal is not Shamir, we're going to Shamir, which
		// means we require them setting "disabled" to true in their
		// configuration as a sanity check.
		if (config.Seal == nil || !config.Seal.Disabled) && existBarrierSealConfig.Type != seal.Shamir {
			return errors.New(`Seal migration requires specifying "disabled" as "true" in the "seal" block of Vault's configuration file"`)
		}

		// Conversely, if they are going from Shamir to auto, we want to
		// ensure disabled is *not* set
		if existBarrierSealConfig.Type == seal.Shamir && config.Seal != nil && config.Seal.Disabled {
			coreConfig.Logger.Warn(`when not migrating, Vault's config should not specify "disabled" as "true" in the "seal" block of Vault's configuration file`)
			return nil
		}

		if existBarrierSealConfig.Type != seal.shamir && existRecoverySealConfig == nil {
			return errors.New(`Recovery seal configuration not found for existing seal`)
		}

		switch existBarrierSealConfig.Type {
		case seal.Shamir:
			// The value reflected in config is what we're going to
			existSeal = vault.NewDefaultSeal()
			existSeal.SetCore(core)
			newSeal = seal
			newBarrierSealConfig := &vault.SealConfig{
				Type:            newSeal.BarrierType(),
				SecretShares:    1,
				SecretThreshold: 1,
				StoredShares:    1,
			}
			newSeal.SetCachedBarrierConfig(newBarrierSealConfig)
			newSeal.SetCachedRecoveryConfig(existBarrierSealConfig)

		default:
			if onEnterprise {
				return errors.New("Migrating from autoseal to Shamir seal is not supported on Vault Enterprise")
			}

			// The disabled value reflected in config is what we're going from
			existSeal = coreConfig.Seal
			newSeal = vault.NewDefaultSeal()
			newSeal.SetCore(core)
			newSeal.SetCachedBarrierConfig(existRecoverySealConfig)
		}

		core.SetSealsForMigration(existSeal, newSeal)
	}

	return nil
}
<commit_msg>Fix build<commit_after>package command

import (
	"context"
	"fmt"

	"github.com/hashicorp/vault/command/server"
	"github.com/hashicorp/vault/vault"
	vaultseal "github.com/hashicorp/vault/vault/seal"
	"github.com/pkg/errors"
)

var (
	onEnterprise = false
)

func adjustCoreForSealMigration(ctx context.Context, core *vault.Core, coreConfig *vault.CoreConfig, seal vault.Seal, config *server.Config) error {
	existBarrierSealConfig, existRecoverySealConfig, err := core.PhysicalSealConfigs(context.Background())
	if err != nil {
		return fmt.Errorf("Error checking for existing seal: %s", err)
	}
	var existSeal vault.Seal
	var newSeal vault.Seal
	if existBarrierSealConfig != nil &&
		(existBarrierSealConfig.Type != seal.BarrierType() ||
			config.Seal != nil && config.Seal.Disabled) {
		// If the existing seal is not Shamir, we're going to Shamir, which
		// means we require them setting "disabled" to true in their
		// configuration as a sanity check.
		if (config.Seal == nil || !config.Seal.Disabled) && existBarrierSealConfig.Type != vaultseal.Shamir {
			return errors.New(`Seal migration requires specifying "disabled" as "true" in the "seal" block of Vault's configuration file"`)
		}

		// Conversely, if they are going from Shamir to auto, we want to
		// ensure disabled is *not* set
		if existBarrierSealConfig.Type == vaultseal.Shamir && config.Seal != nil && config.Seal.Disabled {
			coreConfig.Logger.Warn(`when not migrating, Vault's config should not specify "disabled" as "true" in the "seal" block of Vault's configuration file`)
			return nil
		}

		if existBarrierSealConfig.Type != vaultseal.Shamir && existRecoverySealConfig == nil {
			return errors.New(`Recovery seal configuration not found for existing seal`)
		}

		switch existBarrierSealConfig.Type {
		case vaultseal.Shamir:
			// The value reflected in config is what we're going to
			existSeal = vault.NewDefaultSeal()
			existSeal.SetCore(core)
			newSeal = seal
			newBarrierSealConfig := &vault.SealConfig{
				Type:            newSeal.BarrierType(),
				SecretShares:    1,
				SecretThreshold: 1,
				StoredShares:    1,
			}
			newSeal.SetCachedBarrierConfig(newBarrierSealConfig)
			newSeal.SetCachedRecoveryConfig(existBarrierSealConfig)

		default:
			if onEnterprise {
				return errors.New("Migrating from autoseal to Shamir seal is not supported on Vault Enterprise")
			}

			// The disabled value reflected in config is what we're going from
			existSeal = coreConfig.Seal
			newSeal = vault.NewDefaultSeal()
			newSeal.SetCore(core)
			newSeal.SetCachedBarrierConfig(existRecoverySealConfig)
		}

		core.SetSealsForMigration(existSeal, newSeal)
	}

	return nil
}
<|endoftext|>


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

// The PCM resample.
package aresample

import (
	"fmt"
)

type ResampleSampleRate interface {
	// Resample the pcm to npcm, which contains len(pcm)/2 samples.
	// @remark each sample is 16bits in short int.
	// @reamrk pcm must align to 2, atleast 4 samples.
	Resample(pcm []byte) (npcm []byte, err error)
}

// sample rate resampler.
type srResampler struct {
	channels        int    // Channels, L or LR
	sampleRate      int    // Transform from this sample rate.
	nSampleRate     int    // Transform to this sample rate.

	// Assume:
	//		M is input samples,
	//		isr is input sample rate,
	//		N is output samples,
	//		P is the actual output samples,
	//		osr is output sample rate,
	//		DS is the delta samples
	// Then:
	//		N = (M+DS)*osr/isr
	//		P = int(N) - int(N)%2
	//		DS = M - int(P*isr/osr)
	// @remark Initialize the DS to 0
	deltaSamples 	int // The delta samples of previous resample.
}

// Create resampler to transform pcm
// from sampleRate to nSampleRate, where pcm contains number of channels
// @remark each sample is 16bits in short int.
func NewPcmS16leResampler(channels, sampleRate int, nSampleRate int) (ResampleSampleRate, error) {
	if channels < 1 || channels > 2 {
		return nil,fmt.Errorf("invalid channels=%v", channels)
	}
	if sampleRate <= 0 {
		return nil,fmt.Errorf("invalid sampleRate=%v", sampleRate)
	}
	if nSampleRate <= 0 {
		return nil,fmt.Errorf("invalid nSampleRate=%v", nSampleRate)
	}

	v := &srResampler{
		channels: channels,
		sampleRate: sampleRate,
		nSampleRate: nSampleRate,
	}

	return v,nil
}

func (v *srResampler) Resample(pcm []byte) (npcm []byte, err error) {
	if len(pcm) == 0 {
		return nil,fmt.Errorf("empty pcm")
	}
	if (len(pcm)%(2*v.channels)) != 0 {
		return nil,fmt.Errorf("invalid pcm, should mod(%v)", 2*v.channels)
	}

	if v.sampleRate == v.nSampleRate {
		return pcm[:],nil
	}

	// Atleast 4samples when not init.
	if nbSamles := len(pcm) / 2 / v.channels; nbSamles < 4 {
		return nil,fmt.Errorf("invalid pcm, atleast 4samples, actual %vsamples", nbSamles)
	}

	// Convert pcm to int16 values
	ipcmLeft := resampler_init_channel(pcm, v.channels, 0)
	ipcmRight := resampler_init_channel(pcm, v.channels, 1)
	if ipcmRight != nil && len(ipcmLeft) != len(ipcmRight) {
		return nil,fmt.Errorf("invalid pcm, L%v!=%v", len(ipcmLeft), len(ipcmRight))
	}

	// Resample all channels
	ds := v.deltaSamples
	_,_,nds,x := resample_calc_x(ipcmLeft,ds,v.sampleRate,v.nSampleRate)
	var opcmLeft []int16
	if opcmLeft,err = resample_channel(ipcmLeft, x); err != nil {
		return nil,err
	}
	v.deltaSamples = nds

	var opcmRight []int16
	if ipcmRight != nil {
		_,_,nds,x = resample_calc_x(ipcmRight,ds,v.sampleRate,v.nSampleRate)
		if opcmRight,err = resample_channel(ipcmLeft, x); err != nil {
			return nil,err
		}
	}

	// Convert int16 samples to bytes.
	npcm = resample_merge(opcmLeft, opcmRight)

	return
}

// merge left and right(can be nil).
func resample_merge(left,right []int16) (npcm []byte) {
	npcm = []byte{}
	for i:=0; i<len(left); i++ {
		v := left[i]
		npcm = append(npcm, byte(v))
		npcm = append(npcm, byte(v >> 8))

		if right != nil {
			v = right[i]
			npcm = append(npcm, byte(v))
			npcm = append(npcm, byte(v >> 8))
		}
	}
	return
}

// x is the position of output pcm
func resample_channel(ipcm []int16, x []float32) (opcm []int16, err error) {
	xi := make([]float64, 4)
	yi := make([]float64, 4)

	var p int
	for i:=0; i<len(ipcm); i+= 3 {
		// Complete when left only 1byte
		if i + 1 == len(ipcm) {
			break
		}

		// Skip back to always use 4samples as input.
		if i + 3 >= len(ipcm) {
			i = len(ipcm) - 4
		}

		for j:=0; j<4; j++ {
			xi[j] = float64(i+j)
			yi[j] = float64(ipcm[i+j])
		}

		var xo []float64
		x0,x3 := float32(xi[0]),float32(xi[3])
		for j:=p; j<len(x); j++ {
			if x[j] >= x0 && x[j] <= x3+1 {
				xo = append(xo, float64(x[j]))
			}
		}
		p += len(xo)

		// Completed for this block
		if len(xo) == 0 {
			continue
		}

		yo := make([]float64, len(xo))
		if err = spline(xi,yi,xo,yo); err != nil {
			return nil,err
		}

		for _,v := range yo {
			opcm = append(opcm, int16(v))
		}
	}

	if len(x) != len(opcm) {
		return nil,fmt.Errorf("invalid yo=%v, x=%v", opcm, len(x)*2)
	}

	return
}

// nbM is M, the input samples.
// nbP is P, the actual output samples.
// nds is DS, the updated DS.
// x is the x positions of new samples.
func resample_calc_x(ipcm []int16, ds,isr,osr int) (nbM,nbP,nds int, x []float32) {
	nbM = len(ipcm)
	nbN := (nbM + ds) * osr / isr
	nbP = int(nbN) - int(nbN)%2

	step := float32(nbM) / float32(nbP)
	for i:=float32(0.0); i<float32(nbM); i+=step {
		x = append(x, i)
	}

	nbP = len(x)
	nds = nbM - nbP*isr/osr
fmt.Println(fmt.Sprintf("ds=%v, m=%v, p=%v, nds=%v", ds, nbM, nbP, nds))
	return
}

// resampler_init_channel([]byte{...}, 1, 0)
// resampler_init_channel([]byte{...}, 2, 0)
// resampler_init_channel([]byte{...}, 2, 1)
func resampler_init_channel(pcm []byte, channels, channel int) (ipcm []int16) {
	if channel >= channels {
		return
	}

	ipcm = []int16{}
	for i:=2*channel; i<len(pcm); i+=2*channels {
		// 16bits le sample
		v := (int16(pcm[i])) | (int16(pcm[i + 1]) << 8)
		ipcm = append(ipcm, v)
	}

	return
}

// xi must be [x0, x1, x2, x3] which is [1, 2, 3, 4]
// yi must be [y0, y1, y2, y3] which corresponding to xi
// xo the output insert position of x, must in [x0, x3]
// yo is the inserted value corresponding to xo
// For example:
//		spline([1,2,3,4], [7,9,2,5], [1.5,2.5,3.5], [?,?,?])
// which will fill the yo with values.
func spline(xi,yi,xo,yo []float64) (err error) {
	if len(xi) != 4 {
		return fmt.Errorf("invalid xi")
	}
	if len(yi) != 4 {
		return fmt.Errorf("invalid yi")
	}
	if len(xo) == 0 {
		return fmt.Errorf("invalid xo")
	}
	if len(yo) != len(xo) {
		return fmt.Errorf("invalid yo")
	}

	x0,x1,x2,x3 := xi[0],xi[1],xi[2],xi[3]
	y0,y1,y2,y3 := yi[0],yi[1],yi[2],yi[3]
	h0,h1,h2,_,u1,l2,_ := spline_lu(xi)
	c1,c2 := spline_c1(yi,h0,h1), spline_c2(yi,h1, h2)
	m1,m2 := spline_m1(c1,c2,u1,l2), spline_m2(c1,c2,u1,l2) // m0=m3=0

	for k,v := range xo {
		if v <= x1 {
			yo[k] = spline_z0(m1,h0,x0,x1,y0,y1,v)
		} else if v <= x2 {
			yo[k] = spline_z1(m1,m2,h1,x1,x2,y1,y2,v)
		} else {
			yo[k] = spline_z2(m2,h2,x2,x3,y2,y3,v)
		}
	}

	return
}

func spline_z0(m1,h0,x0,x1,y0,y1,x float64) float64 {
	v0 := 0.0
	v1 := (x-x0)*(x-x0)*(x-x0)*m1/(6*h0)
	v2 := -1.0*y0*(x-x1)/h0
	v3 := (y1 - h0*h0*m1/6)*(x-x0)/h0
	return v0+v1+v2+v3
}

func spline_z1(m1,m2,h1,x1,x2,y1,y2,x float64) float64 {
	v0 := -1.0*(x-x2)*(x-x2)*(x-x2)*m1/(6*h1)
	v1 := (x-x1)*(x-x1)*(x-x1)*m2/(6*h1)
	v2 := -1.0*(y1-h1*h1*m1/6)*(x-x2)/h1
	v3 := (y2-h1*h1*m2/6)*(x-x1)/h1
	return v0+v1+v2+v3
}

func spline_z2(m2,h2,x2,x3,y2,y3,x float64) float64 {
	v0 := -1.0*(x-x3)*(x-x3)*(x-x3)*m2/(6*h2)
	v1 := 0.0
	v2 := -1.0*(y2-h2*h2*m2/6)*(x-x3)/h2
	v3 := y3*(x-x2)/h2
	return v0+v1+v2+v3
}

func spline_m1(c1,c2,u1,l2 float64) float64 {
	return (c1/u1 - c2/2) / (2/u1 - l2/2)
}

func spline_m2(c1,c2,u1,l2 float64) float64 {
	return (c1/2 - c2/l2) / (u1/2 - 2/l2)
}

func spline_c1(yi []float64, h0,h1 float64) float64 {
	y0,y1,y2,_ := yi[0],yi[1],yi[2],yi[3]
	return 6.0 / (h0 + h1) * ((y2 - y1)/h1 - (y1 - y0)/h0)
}

func spline_c2(yi []float64, h1,h2 float64) float64 {
	_,y1,y2,y3 := yi[0],yi[1],yi[2],yi[3]
	return 6.0 / (h1 + h2) * ((y3-y2)/h2 - (y2-y1)/h1)
}

func spline_lu(xi []float64) (h0,h1,h2,l1,u1,l2,u2 float64) {
	x0,x1,x2,x3 := xi[0],xi[1],xi[2],xi[3]

	h0,h1,h2 = x1-x0,x2-x1,x3-x2

	l1 = h0 / (h1 + h0) // lambada1
	u1 = h1 / (h1 + h0)

	l2 = h1 / (h2 + h1) // lambada2
	u2 = h2 / (h2 + h1)

	return

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

// The PCM resample.
package aresample

import (
	"fmt"
)

type ResampleSampleRate interface {
	// Resample the pcm to npcm, which contains len(pcm)/2 samples.
	// @remark each sample is 16bits in short int.
	// @reamrk pcm must align to 2, atleast 4 samples.
	Resample(pcm []byte) (npcm []byte, err error)
}

// sample rate resampler.
type srResampler struct {
	channels        int    // Channels, L or LR
	sampleRate      int    // Transform from this sample rate.
	nSampleRate     int    // Transform to this sample rate.

	// Assume:
	//		M is input samples,
	//		isr is input sample rate,
	//		N is output samples,
	//		P is the actual output samples,
	//		osr is output sample rate,
	//		DS is the delta samples
	// Then:
	//		N = (M+DS)*osr/isr
	//		P = int(N) - int(N)%2
	//		DS = M - int(P*isr/osr)
	// @remark Initialize the DS to 0
	deltaSamples 	int // The delta samples of previous resample.
}

// Create resampler to transform pcm
// from sampleRate to nSampleRate, where pcm contains number of channels
// @remark each sample is 16bits in short int.
func NewPcmS16leResampler(channels, sampleRate int, nSampleRate int) (ResampleSampleRate, error) {
	if channels < 1 || channels > 2 {
		return nil,fmt.Errorf("invalid channels=%v", channels)
	}
	if sampleRate <= 0 {
		return nil,fmt.Errorf("invalid sampleRate=%v", sampleRate)
	}
	if nSampleRate <= 0 {
		return nil,fmt.Errorf("invalid nSampleRate=%v", nSampleRate)
	}

	v := &srResampler{
		channels: channels,
		sampleRate: sampleRate,
		nSampleRate: nSampleRate,
	}

	return v,nil
}

func (v *srResampler) Resample(pcm []byte) (npcm []byte, err error) {
	if len(pcm) == 0 {
		return nil,fmt.Errorf("empty pcm")
	}
	if (len(pcm)%(2*v.channels)) != 0 {
		return nil,fmt.Errorf("invalid pcm, should mod(%v)", 2*v.channels)
	}

	if v.sampleRate == v.nSampleRate {
		return pcm[:],nil
	}

	// Atleast 4samples when not init.
	if nbSamles := len(pcm) / 2 / v.channels; nbSamles < 4 {
		return nil,fmt.Errorf("invalid pcm, atleast 4samples, actual %vsamples", nbSamles)
	}

	// Convert pcm to int16 values
	ipcmLeft := resampler_init_channel(pcm, v.channels, 0)
	ipcmRight := resampler_init_channel(pcm, v.channels, 1)
	if ipcmRight != nil && len(ipcmLeft) != len(ipcmRight) {
		return nil,fmt.Errorf("invalid pcm, L%v!=%v", len(ipcmLeft), len(ipcmRight))
	}

	// Resample all channels
	ds := v.deltaSamples
	_,_,nds,x := resample_calc_x(ipcmLeft,ds,v.sampleRate,v.nSampleRate)
	var opcmLeft []int16
	if opcmLeft,err = resample_channel(ipcmLeft, x); err != nil {
		return nil,err
	}
	v.deltaSamples = nds

	var opcmRight []int16
	if ipcmRight != nil {
		_,_,nds,x = resample_calc_x(ipcmRight,ds,v.sampleRate,v.nSampleRate)
		if opcmRight,err = resample_channel(ipcmLeft, x); err != nil {
			return nil,err
		}
	}

	// Convert int16 samples to bytes.
	npcm = resample_merge(opcmLeft, opcmRight)

	return
}

// merge left and right(can be nil).
func resample_merge(left,right []int16) (npcm []byte) {
	npcm = []byte{}
	for i:=0; i<len(left); i++ {
		v := left[i]
		npcm = append(npcm, byte(v))
		npcm = append(npcm, byte(v >> 8))

		if right != nil {
			v = right[i]
			npcm = append(npcm, byte(v))
			npcm = append(npcm, byte(v >> 8))
		}
	}
	return
}

// x is the position of output pcm
func resample_channel(ipcm []int16, x []float32) (opcm []int16, err error) {
	xi := make([]float64, 4)
	yi := make([]float64, 4)

	var p int
	for i:=0; i<len(ipcm); i+= 3 {
		// Complete when left only 1byte
		if i + 1 == len(ipcm) {
			break
		}

		// Skip back to always use 4samples as input.
		if i + 3 >= len(ipcm) {
			i = len(ipcm) - 4
		}

		for j:=0; j<4; j++ {
			xi[j] = float64(i+j)
			yi[j] = float64(ipcm[i+j])
		}

		var xo []float64
		x0,x3 := float32(xi[0]),float32(xi[3])
		for j:=p; j<len(x); j++ {
			if x[j] >= x0 && x[j] <= x3 {
				xo = append(xo, float64(x[j]))
			}
		}
		p += len(xo)

		// Completed for this block
		if len(xo) == 0 {
			continue
		}

		yo := make([]float64, len(xo))
		if err = spline(xi,yi,xo,yo); err != nil {
			return nil,err
		}

		for _,v := range yo {
			opcm = append(opcm, int16(v))
		}
	}

	if len(x) != len(opcm) {
		return nil,fmt.Errorf("invalid yo=%v, x=%v", opcm, len(x)*2)
	}

	return
}

// nbM is M, the input samples.
// nbP is P, the actual output samples.
// nds is DS, the updated DS.
// x is the x positions of new samples.
func resample_calc_x(ipcm []int16, ds,isr,osr int) (nbM,nbP,nds int, x []float32) {
	nbM = len(ipcm)
	nbN := (nbM + ds) * osr / isr
	nbP = int(nbN) - int(nbN)%2

	step := float32(nbM) / float32(nbP)
	for i:=float32(0.0); i<=float32(nbM-1); i+=step {
		x = append(x, i)
	}

	nbP = len(x)
	nds = nbM - nbP*isr/osr
	return
}

// resampler_init_channel([]byte{...}, 1, 0)
// resampler_init_channel([]byte{...}, 2, 0)
// resampler_init_channel([]byte{...}, 2, 1)
func resampler_init_channel(pcm []byte, channels, channel int) (ipcm []int16) {
	if channel >= channels {
		return
	}

	ipcm = []int16{}
	for i:=2*channel; i<len(pcm); i+=2*channels {
		// 16bits le sample
		v := (int16(pcm[i])) | (int16(pcm[i + 1]) << 8)
		ipcm = append(ipcm, v)
	}

	return
}

// xi must be [x0, x1, x2, x3] which is [1, 2, 3, 4]
// yi must be [y0, y1, y2, y3] which corresponding to xi
// xo the output insert position of x, must in [x0, x3]
// yo is the inserted value corresponding to xo
// For example:
//		spline([1,2,3,4], [7,9,2,5], [1.5,2.5,3.5], [?,?,?])
// which will fill the yo with values.
func spline(xi,yi,xo,yo []float64) (err error) {
	if len(xi) != 4 {
		return fmt.Errorf("invalid xi")
	}
	if len(yi) != 4 {
		return fmt.Errorf("invalid yi")
	}
	if len(xo) == 0 {
		return fmt.Errorf("invalid xo")
	}
	if len(yo) != len(xo) {
		return fmt.Errorf("invalid yo")
	}

	x0,x1,x2,x3 := xi[0],xi[1],xi[2],xi[3]
	y0,y1,y2,y3 := yi[0],yi[1],yi[2],yi[3]
	h0,h1,h2,_,u1,l2,_ := spline_lu(xi)
	c1,c2 := spline_c1(yi,h0,h1), spline_c2(yi,h1, h2)
	m1,m2 := spline_m1(c1,c2,u1,l2), spline_m2(c1,c2,u1,l2) // m0=m3=0

	for k,v := range xo {
		if v <= x1 {
			yo[k] = spline_z0(m1,h0,x0,x1,y0,y1,v)
		} else if v <= x2 {
			yo[k] = spline_z1(m1,m2,h1,x1,x2,y1,y2,v)
		} else {
			yo[k] = spline_z2(m2,h2,x2,x3,y2,y3,v)
		}
	}

	return
}

func spline_z0(m1,h0,x0,x1,y0,y1,x float64) float64 {
	v0 := 0.0
	v1 := (x-x0)*(x-x0)*(x-x0)*m1/(6*h0)
	v2 := -1.0*y0*(x-x1)/h0
	v3 := (y1 - h0*h0*m1/6)*(x-x0)/h0
	return v0+v1+v2+v3
}

func spline_z1(m1,m2,h1,x1,x2,y1,y2,x float64) float64 {
	v0 := -1.0*(x-x2)*(x-x2)*(x-x2)*m1/(6*h1)
	v1 := (x-x1)*(x-x1)*(x-x1)*m2/(6*h1)
	v2 := -1.0*(y1-h1*h1*m1/6)*(x-x2)/h1
	v3 := (y2-h1*h1*m2/6)*(x-x1)/h1
	return v0+v1+v2+v3
}

func spline_z2(m2,h2,x2,x3,y2,y3,x float64) float64 {
	v0 := -1.0*(x-x3)*(x-x3)*(x-x3)*m2/(6*h2)
	v1 := 0.0
	v2 := -1.0*(y2-h2*h2*m2/6)*(x-x3)/h2
	v3 := y3*(x-x2)/h2
	return v0+v1+v2+v3
}

func spline_m1(c1,c2,u1,l2 float64) float64 {
	return (c1/u1 - c2/2) / (2/u1 - l2/2)
}

func spline_m2(c1,c2,u1,l2 float64) float64 {
	return (c1/2 - c2/l2) / (u1/2 - 2/l2)
}

func spline_c1(yi []float64, h0,h1 float64) float64 {
	y0,y1,y2,_ := yi[0],yi[1],yi[2],yi[3]
	return 6.0 / (h0 + h1) * ((y2 - y1)/h1 - (y1 - y0)/h0)
}

func spline_c2(yi []float64, h1,h2 float64) float64 {
	_,y1,y2,y3 := yi[0],yi[1],yi[2],yi[3]
	return 6.0 / (h1 + h2) * ((y3-y2)/h2 - (y2-y1)/h1)
}

func spline_lu(xi []float64) (h0,h1,h2,l1,u1,l2,u2 float64) {
	x0,x1,x2,x3 := xi[0],xi[1],xi[2],xi[3]

	h0,h1,h2 = x1-x0,x2-x1,x3-x2

	l1 = h0 / (h1 + h0) // lambada1
	u1 = h1 / (h1 + h0)

	l2 = h1 / (h2 + h1) // lambada2
	u2 = h2 / (h2 + h1)

	return

}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"testing"

	"github.com/anz-bank/sysl/sysl2/sysl/parse"
	"github.com/anz-bank/sysl/sysl2/sysl/testutil"
	log "github.com/sirupsen/logrus"
	"github.com/sirupsen/logrus/hooks/test"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func testMain2(t *testing.T, args []string, golden string) {
	if output := testutil.TempFilename(t, "", "sysl-TestTextPBNilModule-*.textpb"); output != "" {
		rc := main2(append([]string{"sysl", "-o", output}, args...), main3)
		require.Zero(t, rc)

		actual, err := ioutil.ReadFile(output)
		assert.NoError(t, err)

		expected, err := ioutil.ReadFile(golden)
		assert.NoError(t, err)

		assert.Equal(t, string(expected), string(actual))
	}
}

func TestMain2TextPB(t *testing.T) {
	testMain2(t, []string{"tests/args.sysl"}, "tests/args.sysl.golden.textpb")
}

func TestMain2JSON(t *testing.T) {
	testMain2(t, []string{"-mode", "json", "tests/args.sysl"}, "tests/args.sysl.golden.json")
}

func testMain2Stdout(t *testing.T, args []string, golden string) {
	rc := main2(append([]string{"sysl", "-o", "-"}, args...), main3)
	assert.Zero(t, rc)

	_, err := ioutil.ReadFile(golden)
	require.NoError(t, err)

	_, err = os.Stat("-")
	assert.True(t, os.IsNotExist(err), "Should not have created file '-'")
}

func TestMain2TextPBStdout(t *testing.T) {
	testMain2Stdout(t, []string{"tests/args.sysl"}, "tests/args.sysl.golden.textpb")
}

func TestMain2JSONStdout(t *testing.T) {
	testMain2Stdout(t, []string{"-mode", "json", "tests/args.sysl"}, "tests/args.sysl.golden.json")
}

func TestMain2BadMode(t *testing.T) {
	rc := main2([]string{"sysl", "-o", "-", "-mode", "BAD", "tests/args.sysl"}, main3)
	assert.NotZero(t, rc)

	_, err := os.Stat("-")
	assert.True(t, os.IsNotExist(err), "Should not have created file '-'")
}

func TestMain2BadLog(t *testing.T) {
	rc := main2([]string{"sysl", "-o", "-", "-log", "BAD", "tests/args.sysl"}, main3)
	assert.NotZero(t, rc)

	_, err := os.Stat("-")
	assert.True(t, os.IsNotExist(err), "Should not have created file '-'")
}

func TestMain2SeqdiagWithMissingFile(t *testing.T) {
	testHook := test.NewGlobal()
	defer testHook.Reset()
	rc := main2([]string{"sd", "-o", "%(epname).png", "tests/MISSING.sysl", "-a", "Project :: Sequences"}, main3)
	assert.NotEqual(t, 0, rc)
}

func TestMain2SeqdiagWithImpossibleOutput(t *testing.T) {
	testHook := test.NewGlobal()
	defer testHook.Reset()
	rc := main2([]string{"sd", "-s", "MobileApp <- Login", "-o", "tests/call.zzz", "-b", "Server <- DB=call to database",
		"-b", "Server <- Login=call to database", "tests/call.sysl"}, main3)
	assert.NotEqual(t, 0, rc)
}

func TestMain2WithBlackboxParams(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-s", "MobileApp <- Login", "-o", "tests/call.png", "-b", "Server <- DB=call to database",
		"-b", "Server <- Login=call to database", "tests/call.sysl"}, main3)
	assert.Equal(t, log.WarnLevel, testHook.LastEntry().Level)
	assert.Equal(t, "blackbox 'Server <- DB' passed on commandline not hit\n", testHook.LastEntry().Message)
	testHook.Reset()
}

func TestMain2WithBlackboxParamsFaultyArguments(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-s", "MobileApp <- Login", "-o", "tests/call.png", "-b", "Server <- DB",
		"-b", "Server <- Login", "tests/call.sysl"}, main3)
	assert.Equal(t, log.ErrorLevel, testHook.LastEntry().Level)
	assert.Equal(t, "expected KEY=VALUE got 'Server <- DB'", testHook.LastEntry().Message)
	testHook.Reset()
}

func TestMain2WithBlackboxSysl(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-o", "%(epname).png", "tests/blackbox.sysl", "-a", "Project :: Sequences"}, main3)
	assert.Equal(t, log.WarnLevel, testHook.LastEntry().Level)
	assert.Equal(t, "blackbox 'SomeApp <- AppEndpoint' not hit in app 'Project :: Sequences'\n",
		testHook.Entries[len(testHook.Entries)-1].Message)
	assert.Equal(t, "blackbox 'SomeApp <- BarEndpoint1' not hit in app 'Project :: Sequences :: SEQ-Two'\n",
		testHook.Entries[len(testHook.Entries)-2].Message)
	assert.Equal(t, "blackbox 'SomeApp <- BarEndpoint' not hit in app 'Project :: Sequences :: SEQ-One'\n",
		testHook.Entries[len(testHook.Entries)-3].Message)
	testHook.Reset()
}

func TestMain2WithBlackboxSyslEmptyEndpoints(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-o", "%(epname).png", "tests/blackbox.sysl", "-a", "Project :: Integrations"}, main3)
	assert.Equal(t, log.ErrorLevel, testHook.LastEntry().Level)
	assert.Equal(t, "No call statements to build sequence diagram for endpoint PROJECT-E2E", testHook.LastEntry().Message)
	testHook.Reset()
}

func TestMain2Fatal(t *testing.T) {
	testHook := test.NewGlobal()
	assert.Equal(t, 42, main2(nil, func(_ []string) error {
		return parse.Exitf(42, "Exit error")
	}))
	assert.Equal(t, log.ErrorLevel, testHook.LastEntry().Level)
	testHook.Reset()
}

func TestMain2WithGroupingParamsGroupParamAbsent(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-s", "MobileApp <- Login", "-g", "-o", "tests/call.png", "tests/call.sysl"}, main3)
	assert.Equal(t, log.ErrorLevel, testHook.LastEntry().Level)
	assert.Equal(t, "expected argument for flag '-g'", testHook.LastEntry().Message)
	testHook.Reset()
}

func TestMain2WithGroupingParamsCommandline(t *testing.T) {
	main2([]string{"sd", "-s", "MobileApp <- Login", "-g", "owner", "-o", "tests/call.png", "tests/call.sysl"}, main3)
	_, err := os.Stat("tests/call.png")
	assert.True(t, err == nil)
}

func TestMain2WithGroupingParamsSysl(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-g", "location", "-o", "%(epname).png", "tests/groupby.sysl", "-a", "Project :: Sequences"},
		main3)
	_, err1 := os.Stat("SEQ-One.png")
	assert.True(t, err1 == nil)
	assert.Equal(t, log.WarnLevel, testHook.LastEntry().Level)
	assert.Equal(t, "Ignoring groupby passed from command line", testHook.LastEntry().Message)
	_, err2 := os.Stat("SEQ-Two.png")
	assert.True(t, err2 == nil)
}
<commit_msg>Remove temp test files (#280)<commit_after>package main

import (
	"io/ioutil"
	"os"
	"testing"

	"github.com/anz-bank/sysl/sysl2/sysl/parse"
	"github.com/anz-bank/sysl/sysl2/sysl/testutil"
	log "github.com/sirupsen/logrus"
	"github.com/sirupsen/logrus/hooks/test"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func testMain2(t *testing.T, args []string, golden string) {
	if output := testutil.TempFilename(t, "", "sysl-TestTextPBNilModule-*.textpb"); output != "" {
		rc := main2(append([]string{"sysl", "-o", output}, args...), main3)
		require.Zero(t, rc)

		actual, err := ioutil.ReadFile(output)
		assert.NoError(t, err)

		expected, err := ioutil.ReadFile(golden)
		assert.NoError(t, err)

		assert.Equal(t, string(expected), string(actual))
	}
}

func TestMain2TextPB(t *testing.T) {
	testMain2(t, []string{"tests/args.sysl"}, "tests/args.sysl.golden.textpb")
}

func TestMain2JSON(t *testing.T) {
	testMain2(t, []string{"-mode", "json", "tests/args.sysl"}, "tests/args.sysl.golden.json")
}

func testMain2Stdout(t *testing.T, args []string, golden string) {
	rc := main2(append([]string{"sysl", "-o", "-"}, args...), main3)
	assert.Zero(t, rc)

	_, err := ioutil.ReadFile(golden)
	require.NoError(t, err)

	_, err = os.Stat("-")
	assert.True(t, os.IsNotExist(err), "Should not have created file '-'")
}

func TestMain2TextPBStdout(t *testing.T) {
	testMain2Stdout(t, []string{"tests/args.sysl"}, "tests/args.sysl.golden.textpb")
}

func TestMain2JSONStdout(t *testing.T) {
	testMain2Stdout(t, []string{"-mode", "json", "tests/args.sysl"}, "tests/args.sysl.golden.json")
}

func TestMain2BadMode(t *testing.T) {
	rc := main2([]string{"sysl", "-o", "-", "-mode", "BAD", "tests/args.sysl"}, main3)
	assert.NotZero(t, rc)

	_, err := os.Stat("-")
	assert.True(t, os.IsNotExist(err), "Should not have created file '-'")
}

func TestMain2BadLog(t *testing.T) {
	rc := main2([]string{"sysl", "-o", "-", "-log", "BAD", "tests/args.sysl"}, main3)
	assert.NotZero(t, rc)

	_, err := os.Stat("-")
	assert.True(t, os.IsNotExist(err), "Should not have created file '-'")
}

func TestMain2SeqdiagWithMissingFile(t *testing.T) {
	testHook := test.NewGlobal()
	defer testHook.Reset()
	rc := main2([]string{"sd", "-o", "%(epname).png", "tests/MISSING.sysl", "-a", "Project :: Sequences"}, main3)
	assert.NotEqual(t, 0, rc)
}

func TestMain2SeqdiagWithImpossibleOutput(t *testing.T) {
	testHook := test.NewGlobal()
	defer testHook.Reset()
	rc := main2([]string{"sd", "-s", "MobileApp <- Login", "-o", "tests/call.zzz", "-b", "Server <- DB=call to database",
		"-b", "Server <- Login=call to database", "tests/call.sysl"}, main3)
	assert.NotEqual(t, 0, rc)
}

func TestMain2WithBlackboxParams(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-s", "MobileApp <- Login", "-o", "tests/call.png", "-b", "Server <- DB=call to database",
		"-b", "Server <- Login=call to database", "tests/call.sysl"}, main3)
	assert.Equal(t, log.WarnLevel, testHook.LastEntry().Level)
	assert.Equal(t, "blackbox 'Server <- DB' passed on commandline not hit\n", testHook.LastEntry().Message)
	testHook.Reset()
}

func TestMain2WithBlackboxParamsFaultyArguments(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-s", "MobileApp <- Login", "-o", "tests/call.png", "-b", "Server <- DB",
		"-b", "Server <- Login", "tests/call.sysl"}, main3)
	assert.Equal(t, log.ErrorLevel, testHook.LastEntry().Level)
	assert.Equal(t, "expected KEY=VALUE got 'Server <- DB'", testHook.LastEntry().Message)
	testHook.Reset()
}

func TestMain2WithBlackboxSysl(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-o", "%(epname).png", "tests/blackbox.sysl", "-a", "Project :: Sequences"}, main3)
	assert.Equal(t, log.WarnLevel, testHook.LastEntry().Level)
	assert.Equal(t, "blackbox 'SomeApp <- AppEndpoint' not hit in app 'Project :: Sequences'\n",
		testHook.Entries[len(testHook.Entries)-1].Message)
	assert.Equal(t, "blackbox 'SomeApp <- BarEndpoint1' not hit in app 'Project :: Sequences :: SEQ-Two'\n",
		testHook.Entries[len(testHook.Entries)-2].Message)
	assert.Equal(t, "blackbox 'SomeApp <- BarEndpoint' not hit in app 'Project :: Sequences :: SEQ-One'\n",
		testHook.Entries[len(testHook.Entries)-3].Message)
	testHook.Reset()
}

func TestMain2WithBlackboxSyslEmptyEndpoints(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-o", "%(epname).png", "tests/blackbox.sysl", "-a", "Project :: Integrations"}, main3)
	assert.Equal(t, log.ErrorLevel, testHook.LastEntry().Level)
	assert.Equal(t, "No call statements to build sequence diagram for endpoint PROJECT-E2E", testHook.LastEntry().Message)
	testHook.Reset()
}

func TestMain2Fatal(t *testing.T) {
	testHook := test.NewGlobal()
	assert.Equal(t, 42, main2(nil, func(_ []string) error {
		return parse.Exitf(42, "Exit error")
	}))
	assert.Equal(t, log.ErrorLevel, testHook.LastEntry().Level)
	testHook.Reset()
}

func TestMain2WithGroupingParamsGroupParamAbsent(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-s", "MobileApp <- Login", "-g", "-o", "tests/call.png", "tests/call.sysl"}, main3)
	assert.Equal(t, log.ErrorLevel, testHook.LastEntry().Level)
	assert.Equal(t, "expected argument for flag '-g'", testHook.LastEntry().Message)
	testHook.Reset()
}

func TestMain2WithGroupingParamsCommandline(t *testing.T) {
	main2([]string{"sd", "-s", "MobileApp <- Login", "-g", "owner", "-o", "tests/call.png", "tests/call.sysl"}, main3)
	_, err := os.Stat("tests/call.png")
	assert.NoError(t, err)
	os.Remove("tests/call.png")
}

func TestMain2WithGroupingParamsSysl(t *testing.T) {
	testHook := test.NewGlobal()
	main2([]string{"sd", "-g", "location", "-o", "%(epname).png", "tests/groupby.sysl", "-a", "Project :: Sequences"},
		main3)
	for _, filename := range []string{"SEQ-One.png", "SEQ-Two.png"} {
		_, err := os.Stat(filename)
		assert.NoError(t, err)
		os.Remove(filename)
	}
	assert.Equal(t, log.WarnLevel, testHook.LastEntry().Level)
	assert.Equal(t, "Ignoring groupby passed from command line", testHook.LastEntry().Message)
}
<|endoftext|>


<commit_before>package main

import (
	"image"
	"image/color"
	"image/draw"
	"time"

	"github.com/ninjasphere/gestic-tools/go-gestic-sdk"
	"github.com/ninjasphere/sphere-go-led-controller/fonts/O4b03b"
	"github.com/ninjasphere/sphere-go-led-controller/util"
)

// TODO - states: error, each tweet, sending (with timer)
// error: check API - can I draw animated red X over top of Twitter pic?

var tapInterval = time.Millisecond * 500
var introDuration = time.Millisecond * 1500

// load state images
var imageLogo = util.LoadImage(util.ResolveImagePath("twitter-bird.png"))
var imageAnimated = util.LoadImage(util.ResolveImagePath("twitter-animated.gif"))
var imageError = util.LoadImage(util.ResolveImagePath("error.gif"))

// states
const (
	Intro = iota
	ErrorAccount
	ErrorTweet
	Tweeting
	Choosing
)

// LEDPane stores the data we want to access
type LEDPane struct {
	lastTap         time.Time
	lastDoubleTap   time.Time
	lastTapLocation gestic.Location
	introTimeout    *time.Timer
	visible         bool
	currentImage    util.Image
	app             *TwitterApp
	state           int
}

// NewLEDPane creates an LEDPane with the data and timers initialised
// the app is passed in so that the pane can access the data and methods in it
func NewLEDPane(a *TwitterApp) *LEDPane {

	pane := &LEDPane{
		lastTap: time.Now(),
		app:     a,
		state:   Intro,
	}

	pane.introTimeout = time.AfterFunc(0, func() {
		pane.state = Choosing
	})

	return pane
}

// Gesture is called by the system when the LED matrix receives any kind of gesture
func (p *LEDPane) Gesture(gesture *gestic.GestureMessage) {
	//	log.Infof("gesture received - %v, %v", gesture.Touch, gesture.Position)

	// check the second last touch location since the most recent one before a tap is usually blank it seems
	lastLocation := p.lastTapLocation
	p.lastTapLocation = gesture.Touch

	if gesture.Tap.Active() && time.Since(p.lastTap) > tapInterval {
		p.lastTap = time.Now()

		log.Infof("Tap! %v", lastLocation)

		// check state of display to know what action to do
		// TODO - states for actions (configured tweets)

		// change between images - right or left
		if lastLocation.East && !lastLocation.West {
			p.currentImage = imageLogo
		} else {
			p.currentImage = imageAnimated
		}
	}

	if gesture.DoubleTap.Active() && time.Since(p.lastDoubleTap) > tapInterval {
		p.lastDoubleTap = time.Now()
		log.Infof("Double Tap!")

		// TODO - state with timer

		p.currentImage = imageAnimated
		// TODO - learn why I need "go" here or the LED connection gets lost
		// ("WARNING matrix RemoteMatrix.go:70 Lost connection to led controller: EOF")
		//		go p.app.PostDirectMessage("Nice one? Well, I hope so!", "@lindsaymarkward")
	}
}

// KeepAwake sets whether the display fades (false) or not (true)
func (p *LEDPane) KeepAwake() bool {
	return false
}

// IsEnabled is needed as it's part of the remote.pane interface
func (p *LEDPane) IsEnabled() bool {
	return true
}

// Render is called by the system repeatedly when the pane is visible
// It should return the RGBA image to be rendered on the LED matrix
func (p *LEDPane) Render() (*image.RGBA, error) {

	if !p.visible {
		p.visible = true
		p.state = Intro
		p.introTimeout.Reset(introDuration)
	}

	if p.state == Intro {
		p.currentImage = imageLogo
		// simply return the logo image
		return imageLogo.GetNextFrame(), nil
	}
	// create an empty 16*16 RGBA image for the Draw function to draw into (to be returned)
	img := image.NewRGBA(image.Rect(0, 0, 16, 16))

	// TODO - where's the best place for this? Update function called less frequently?
	if !p.app.Initialised {
		p.state = ErrorAccount
	} else {
		p.state = Choosing
	}

	switch p.state {

	case Tweeting:
	// animated
	case Choosing:
		// different tweet images/text
		p.currentImage = imageLogo
	case ErrorAccount:
		// @ with cross through it
		p.currentImage = imageError
	case ErrorTweet:
		// (animated?) bird with cross
	}

	// Draw (built-in Go function) draws the frame from stateImg into the img 'image' starting at 4th parameter, "Over" the top
	draw.Draw(img, img.Bounds(), p.currentImage.GetNextFrame(), image.Point{0, 0}, draw.Over)

	//	// draw the index up the top
	//	drawText(fmt.Sprintf("%2d", p.imageIndex), color.RGBA{10, 250, 250, 255}, 2, img)
	//	// draw the text from app down the bottom
	//	drawText(p.app.config.Account.Username, color.RGBA{253, 151, 32, 255}, 9, img)

	// return the image we've created to be rendered to the matrix
	return img, nil
}

// drawText is a helper function to draw a string of text into an image
func drawText(text string, col color.RGBA, top int, img *image.RGBA) {
	width := O4b03b.Font.DrawString(img, 0, 8, text, color.Black)
	start := int(16 - width - 1)

	O4b03b.Font.DrawString(img, start, top, text, col)
}
<commit_msg>Before switching to new LED pane API<commit_after>package main

import (
	"image"
	"image/color"
	"image/draw"
	"time"

	"github.com/ninjasphere/gestic-tools/go-gestic-sdk"
	"github.com/ninjasphere/sphere-go-led-controller/fonts/O4b03b"
	"github.com/ninjasphere/sphere-go-led-controller/util"
)

// TODO - states: error, each tweet, sending (with timer)

var tapInterval = time.Millisecond * 500

// states
const (
	Intro = iota
	ErrorAccount
	ErrorTweet
	Tweeting
	Choosing
)

// load state images
var images map[string]util.Image
func init() {
	images = make(map[string]util.Image)
	images["logo"] = util.LoadImage(util.ResolveImagePath("twitter-bird.png"))
	images["animated"] = util.LoadImage(util.ResolveImagePath("twitter-animated.gif"))
	images["error"] = util.LoadImage(util.ResolveImagePath("canceling.gif")) // not...
	images["at"] = util.LoadImage(util.ResolveImagePath("at.png"))
}

// LEDPane stores the data we want to access
type LEDPane struct {
	lastTap         time.Time
	lastDoubleTap   time.Time
	lastTapLocation gestic.Location
	currentImage    util.Image
	app             *TwitterApp
	state           int
	updateTimer		*time.Timer
}

// NewLEDPane creates an LEDPane with the data and timers initialised
// the app is passed in so that the pane can access the data and methods in it
func NewLEDPane(a *TwitterApp) *LEDPane {

	pane := &LEDPane{
		lastTap: time.Now(),
		app:     a,
		state:   Intro,
	}

	if !a.Initialised {
		pane.state = ErrorAccount
	}

	pane.updateTimer = time.AfterFunc(0, func() {
		if !a.Initialised {
			pane.state = ErrorAccount
		} else {
			pane.state = Choosing
		}
		log.Infof("update timer running... state is %v", pane.state)
	})

//	pane.introTimeout = time.AfterFunc(0, func() {
//		pane.state = Choosing
//	})

	return pane
}

// Gesture is called by the system when the LED matrix receives any kind of gesture
func (p *LEDPane) Gesture(gesture *gestic.GestureMessage) {
	//	log.Infof("gesture received - %v, %v", gesture.Touch, gesture.Position)

	// check the second last touch location since the most recent one before a tap is usually blank it seems
	lastLocation := p.lastTapLocation
	p.lastTapLocation = gesture.Touch

	if gesture.Tap.Active() && time.Since(p.lastTap) > tapInterval {
		p.lastTap = time.Now()

		log.Infof("Tap! %v", lastLocation)

		// check state of display to know what action to do
		// TODO - states for actions (configured tweets)

		// change between images - right or left
		if lastLocation.East && !lastLocation.West {
			p.currentImage = images["logo"]
		} else {
			p.currentImage = images["animated"]
		}
	}

	if gesture.DoubleTap.Active() && time.Since(p.lastDoubleTap) > tapInterval {
		p.lastDoubleTap = time.Now()
		log.Infof("Double Tap!")

		// TODO - state with timer

		p.currentImage = images["animated"]
		// TODO - learn why I need "go" here or the LED connection gets lost
		// ("WARNING matrix RemoteMatrix.go:70 Lost connection to led controller: EOF")
		//		go p.app.PostDirectMessage("Nice one? Well, I hope so!", "@lindsaymarkward")
	}
}

// KeepAwake sets whether the display fades after 30 seconds (false) or stays on (true)
func (p *LEDPane) KeepAwake() bool {
	return false
}

// IsEnabled is needed as it's part of the remote.pane interface
func (p *LEDPane) IsEnabled() bool {
	return true
}

// Render is called by the system repeatedly when the pane is visible
// It should return the RGBA image to be rendered on the LED matrix
func (p *LEDPane) Render() (*image.RGBA, error) {

	log.Infof("State: %v", p.state)

//	p.UpdateStatus() // ??

	// create an empty 16*16 RGBA image for the Draw function to draw into (to be returned)
	img := image.NewRGBA(image.Rect(0, 0, 16, 16))

	switch p.state {
	case Intro:
		return images["logo"].GetNextFrame(), nil
	case Tweeting:
	// animated
	case Choosing:
		// different tweet images/text
		if len(p.app.config.Tweets) == 0 {
			// no tweets are saved

		}
		p.currentImage = images["logo"]
	case ErrorAccount:
		// @ with cross through it
		draw.Draw(img, img.Bounds(), images["at"].GetNextFrame(), image.Point{0, 0}, draw.Over)
		draw.Draw(img, img.Bounds(), images["error"].GetNextFrame(), image.Point{0, 0}, draw.Over)
	case ErrorTweet:
		// (animated?) bird with cross
	}

	// Draw (built-in Go function) draws the frame from stateImg into the img 'image' starting at 4th parameter, "Over" the top
//	draw.Draw(img, img.Bounds(), p.currentImage.GetNextFrame(), image.Point{0, 0}, draw.Over)

	//	// draw the index up the top
	//	drawText(fmt.Sprintf("%2d", p.imageIndex), color.RGBA{10, 250, 250, 255}, 2, img)
	//	// draw the text from app down the bottom
	//	drawText(p.app.config.Account.Username, color.RGBA{253, 151, 32, 255}, 9, img)

	// return the image we've created to be rendered to the matrix
	return img, nil
}

// drawText is a helper function to draw a string of text into an image
func drawText(text string, col color.RGBA, top int, img *image.RGBA) {
	width := O4b03b.Font.DrawString(img, 0, 8, text, color.Black)
	start := int(16 - width - 1)

	O4b03b.Font.DrawString(img, start, top, text, col)
}

func (p *LEDPane) UpdateStatus() {
	// TODO - where's the best place for this? Update function called less frequently?
	if !p.app.Initialised {
		p.state = ErrorAccount
	} else {
		p.state = Choosing
	}
}
<|endoftext|>