<commit_before>package nx

import (
	"errors"
)

var (
	ErrNodeIndex   = errors.New("the node index provided does not exist / it exceeds the total number of nodes")
	ErrNodeParsed  = errors.New("this node has already been parsed")
	ErrNodeFile    = errors.New("this node has not been initialised properly with NewNode")
	ErrNodeNoChild = errors.New("this node does not have any children or it is not yet parsed")
)

type Children struct {
	Indexes map[string]uint
	Nodes   []*Node
	Total   uint
}

type Node struct {
	f       *File
	ID      uint
	Name    string
	ChildID uint32
	Count   uint16
	Type    uint16
	Data    interface{}
}

type DataNode interface {
	Value() interface{}
}

type EmptyNode struct {
}

type LongNode struct {
	d int64
}

type FloatNode struct {
	d float64
}

type StringNode struct {
	d uint32
}

type VectorNode struct {
	x, y int32
}

type BitmapNode struct {
	id uint32
	w  uint16
	h  uint16
}

type AudioNode struct {
	id     uint32
	length uint32
}

func NewNode(nxf *File, i uint) (*Node, error) {
	if i >= uint(nxf.header.NodeCount) {
		return nil, ErrNodeIndex
	}
	return &Node{f: nxf, ID: i}, nil
}

func (nd *Node) Parse() error {
	if nd.Name != "" {
		return ErrNodeParsed
	}

	if nd.f == nil {
		return ErrNodeFile
	}

	offset := nd.f.header.nodeOffset + uint64(nd.ID)*20

	sid := readU32(nd.f.raw[offset:])
	name, err := nd.f.GetString(uint(sid))
	if err != nil {
		return err
	}
	nd.Name = name
	offset += 4
	nd.ChildID = readU32(nd.f.raw[offset:])
	offset += 4
	nd.Count = readU16(nd.f.raw[offset:])
	offset += 2
	nd.Type = readU16(nd.f.raw[offset:])
	offset += 2
	nd.Data = nd.GetData(offset)

	return nil
}

func (nd *Node) GetData(offset uint64) interface{} {
	// TODO: Reader interface
	switch nd.Type {
	case 0:
		return EmptyNode{}
	case 1: // Int64
		return LongNode{read64(nd.f.raw[offset:])}
	case 2: // Double
		return FloatNode{readFloat64(nd.f.raw[offset:])}
	case 3: // NX_STRING (String Id)
		return StringNode{readU32(nd.f.raw[offset:])}
	case 4: // NX_VECTOR (X and Y)
		return VectorNode{
			read32(nd.f.raw[offset:]),
			read32(nd.f.raw[offset+4:]),
		}
	case 5: // NX_BITMAP (BitmapID, W, H)
		return BitmapNode{
			readU32(nd.f.raw[offset:]),
			readU16(nd.f.raw[offset+4:]), readU16(nd.f.raw[offset+6:]),
		}
	case 6: // NX_AUDIO
		return AudioNode{
			readU32(nd.f.raw[offset:]),
			readU32(nd.f.raw[offset+4:]),
		}
	}
	return nil
}

func (nd *Node) Children() (*Children, error) {
	totalNodes := uint(nd.Count)
	if totalNodes == 0 {
		return nil, ErrNodeNoChild
	}

	c := new(Children)
	c.Indexes = make(map[string]uint, totalNodes)
	c.Nodes = make([]*Node, totalNodes)
	c.Total = totalNodes

	for i := uint(0); i < totalNodes; i++ {
		cnd, err := NewNode(nd.f, uint(nd.ChildID)+i)
		if err != nil {
			return nil, err
		}
		err = cnd.Parse()
		if err != nil {
			return nil, err
		}
		c.Indexes[cnd.Name] = i
		c.Nodes[i] = cnd
	}
	return c, nil
}

func (c *Children) Get(n string) (*Node, error) {
	if i, ok := c.Indexes[n]; c.Nodes[i] != nil && ok {
		return c.Nodes[i], nil
	}
	return nil, ErrNodeIndex
}

func (c *Children) GetByID(i uint) (*Node, error) {
	if i >= c.Total {
		return nil, ErrNodeIndex
	}
	return c.Nodes[i], nil
}
<commit_msg>Embedding Children in Node via c field i.e. Re-added ability to parse node tree (no manual management)<commit_after>package nx

import (
	"errors"
)

var (
	ErrNodeIndex   = errors.New("the node index provided does not exist / it exceeds the total number of nodes")
	ErrNodeParsed  = errors.New("this node has already been parsed")
	ErrNodeFile    = errors.New("this node has not been initialised properly with NewNode")
	ErrNodeNoChild = errors.New("this node does not have any children or it is not yet parsed")
)

type Children struct {
	Indexes map[string]uint
	Nodes   []*Node
	Total   uint
}

type Node struct {
	f       *File
	c       *Children
	ID      uint
	Name    string
	ChildID uint32
	Count   uint16
	Type    uint16
	Data    interface{}
}

type DataNode interface {
	Value() interface{}
}

type EmptyNode struct {
}

type LongNode struct {
	d int64
}

type FloatNode struct {
	d float64
}

type StringNode struct {
	d uint32
}

type VectorNode struct {
	x, y int32
}

type BitmapNode struct {
	id uint32
	w  uint16
	h  uint16
}

type AudioNode struct {
	id     uint32
	length uint32
}

func NewNode(nxf *File, i uint) (*Node, error) {
	if i >= uint(nxf.header.NodeCount) {
		return nil, ErrNodeIndex
	}
	return &Node{f: nxf, ID: i}, nil
}

func (nd *Node) Parse() error {
	if nd.Name != "" {
		return ErrNodeParsed
	}

	if nd.f == nil {
		return ErrNodeFile
	}

	offset := nd.f.header.nodeOffset + uint64(nd.ID)*20

	sid := readU32(nd.f.raw[offset:])
	name, err := nd.f.GetString(uint(sid))
	if err != nil {
		return err
	}
	nd.Name = name
	offset += 4
	nd.ChildID = readU32(nd.f.raw[offset:])
	offset += 4
	nd.Count = readU16(nd.f.raw[offset:])
	offset += 2
	nd.Type = readU16(nd.f.raw[offset:])
	offset += 2
	nd.Data = nd.GetData(offset)

	return nil
}

func (nd *Node) GetData(offset uint64) interface{} {
	// TODO: Reader interface
	switch nd.Type {
	case 0:
		return EmptyNode{}
	case 1: // Int64
		return LongNode{read64(nd.f.raw[offset:])}
	case 2: // Double
		return FloatNode{readFloat64(nd.f.raw[offset:])}
	case 3: // NX_STRING (String Id)
		return StringNode{readU32(nd.f.raw[offset:])}
	case 4: // NX_VECTOR (X and Y)
		return VectorNode{
			read32(nd.f.raw[offset:]),
			read32(nd.f.raw[offset+4:]),
		}
	case 5: // NX_BITMAP (BitmapID, W, H)
		return BitmapNode{
			readU32(nd.f.raw[offset:]),
			readU16(nd.f.raw[offset+4:]), readU16(nd.f.raw[offset+6:]),
		}
	case 6: // NX_AUDIO
		return AudioNode{
			readU32(nd.f.raw[offset:]),
			readU32(nd.f.raw[offset+4:]),
		}
	}
	return nil
}

func (nd *Node) Children() (*Children, error) {
	totalNodes := uint(nd.Count)
	if totalNodes == 0 {
		return nil, ErrNodeNoChild
	}
	if nd.c != nil {
		return nd.c, nil
	}

	nd.c = new(Children)
	nd.c.Indexes = make(map[string]uint, totalNodes)
	nd.c.Nodes = make([]*Node, totalNodes)
	nd.c.Total = totalNodes

	for i := uint(0); i < totalNodes; i++ {
		cnd, err := NewNode(nd.f, uint(nd.ChildID)+i)
		if err != nil {
			return nil, err
		}
		err = cnd.Parse()
		if err != nil {
			return nil, err
		}
		nd.c.Indexes[cnd.Name] = i
		nd.c.Nodes[i] = cnd
	}
	return nd.c, nil
}

func (c *Children) Get(n string) (*Node, error) {
	if i, ok := c.Indexes[n]; c.Nodes[i] != nil && ok {
		return c.Nodes[i], nil
	}
	return nil, ErrNodeIndex
}

func (c *Children) GetByID(i uint) (*Node, error) {
	if i >= c.Total {
		return nil, ErrNodeIndex
	}
	return c.Nodes[i], nil
}
<|endoftext|>


<commit_before>package mediasort

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"

	"github.com/agnivade/levenshtein"
	"github.com/fatih/color"
	"github.com/jpillora/media-sort/search"
)

type fileSorter struct {
	name, path string
	info       os.FileInfo
	err        error

	s               *Sorter
	ext             string
	mtype           string
	season, episode string
	episodeDate     string //weekly series
	year            string
}

func newFileSorter(s *Sorter, path string, info os.FileInfo) (*fileSorter, error) {
	//attempt to rule out file
	if !info.Mode().IsRegular() {
		return nil, nil
	}

	name := info.Name()
	ext := filepath.Ext(name)
	if _, exists := s.exts[ext]; !exists {
		return nil, nil
	}
	name = strings.TrimSuffix(name, ext)

	//setup
	return &fileSorter{
		s:       s,
		name:    name,
		path:    path,
		info:    info,
		ext:     ext,
		season:  "1",
		episode: "",
	}, nil
}

//always in a goroutine
func (f *fileSorter) goRun(wg *sync.WaitGroup) {
	f.err = f.run()
	wg.Done()
}

func (f *fileSorter) run() error {

	//normalize name
	query := normalize(f.name)

	//extract episode date (weekly show)
	if f.mtype == "" {
		m := epidate.FindStringSubmatch(query)
		if len(m) > 0 {
			query = m[1] //trim name
			f.mtype = "series"
			f.episodeDate = strings.Replace(m[2], " ", "-", 2)
		}
	}

	//extract episde season numbers
	if f.mtype == "" {
		m := episeason.FindStringSubmatch(query)
		if len(m) > 0 {
			query = m[1] //trim name
			f.mtype = "series"
			f.season = m[3]
			f.episode = m[6]
		}
	}

	//extract *joined* episde season numbers
	if f.mtype == "" {
		m := joinedepiseason.FindStringSubmatch(query)
		if len(m) > 0 {
			query = m[1] //trim name
			f.mtype = "series"
			f.season = m[2]
			f.episode = m[3]
		}
	}

	//extract release year
	m := year.FindStringSubmatch(query)
	if len(m) > 0 {
		query = m[1] //trim name
		if f.mtype == "" {
			f.mtype = "movie" //set type to "movie", if not already set
		}
		f.year = m[2]
	}

	//if the above fails, extract "Part 1/2/3..."
	if f.mtype == "" {
		m := partnum.FindStringSubmatch(query)
		if len(m) > 0 {
			query = m[1] //trim name
			f.mtype = "series"
			f.episode = m[2]
		}
	}

	//trim spaces
	query = strings.TrimSpace(query)

	//search for normalized name
	r, err := search.Do(query, f.year, f.mtype)
	if err != nil {
		return err //search failed
	}

	// normalize so the title is query-like
	title := normalize(r.Title)

	ldiff := abs(len(query) - len(title))

	dist, _ := levenshtein.ComputeDistance(query, title)

	// log.Printf("search found: '%s' -> '%s' %s => %d (#%d)", query, title, r.Type, dist, ldiff)

	// incorrect by more than the query!
	if dist-ldiff > 5 {
		return fmt.Errorf("Best match for '%s' was '%s'", f.name, r.Title)
	}

	//calculate destination path
	dest := ""
	if r.Type == "series" && f.episodeDate != "" {
		filename := fmt.Sprintf("%s %s%s", r.Title, f.episodeDate, f.ext)
		dest = filepath.Join(f.s.c.TVDir, r.Title, filename)
	} else if r.Type == "series" && f.episode != "" {
		s, _ := strconv.Atoi(f.season)
		e, _ := strconv.Atoi(f.episode)
		filename := fmt.Sprintf("%s S%02dE%02d%s", r.Title, s, e, f.ext)
		dest = filepath.Join(f.s.c.TVDir, r.Title, filename)
	} else if r.Type == "movie" {
		filename := fmt.Sprintf("%s (%s)%s", r.Title, r.Year, f.ext)
		dest = filepath.Join(f.s.c.MovieDir, filename)
	} else {
		return fmt.Errorf("TV Series with no episode found '%s'", query)
	}

	//DEBUG
	// log.Printf("SUCCESS = D%d #%d\n  %s\n  %s", r.Distance, len(query), query, r.Title)
	log.Printf("Moving\n  '%s'\n  └─> '%s'", f.path, color.GreenString(dest))

	if f.s.c.DryRun {
		return nil
	}

	//check already exists
	if _, err := os.Stat(dest); err == nil {
		return fmt.Errorf("File already exists '%s'", dest)
	}

	//mkdir -p
	err = os.MkdirAll(filepath.Dir(dest), 0755)
	if err != nil {
		return err //failed to mkdir
	}

	//mv
	err = os.Rename(f.path, dest)
	if err != nil {
		return err //failed to move
	}
	return nil
}

var yearstr = `(19\d\d|20[0,1]\d)`

var encodings = regexp.MustCompile(`\b(720p|1080p|hdtv|x264|dts|bluray)\b.*`) //strip all junk
var nonalpha = regexp.MustCompile(`[^A-Za-z0-9]`)
var spaces = regexp.MustCompile(`\s+`)
var episeason = regexp.MustCompile(`^(.+?)\bs?(eason)?(\d{1,2})(e|\ |\ e|x|xe)(pisode)?(\d{1,2})\b`)
var epidate = regexp.MustCompile(`^(.+?\b)(` + yearstr + ` \d{2} \d{2}|\d{2} \d{2} ` + yearstr + `)\b`)
var year = regexp.MustCompile(`^(.+?\b)` + yearstr + `\b`)
var joinedepiseason = regexp.MustCompile(`^(.+?\b)(\d)(\d{2})\b`)
var partnum = regexp.MustCompile(`^(.+?\b)(\d{1,2})\b`)

//TODO var romannumerals...

func normalize(s string) string {
	s = strings.ToLower(s)
	s = nonalpha.ReplaceAllString(s, " ")
	s = encodings.ReplaceAllString(s, "")
	s = spaces.ReplaceAllString(s, " ")
	s = strings.TrimSpace(s)
	return s
}

func abs(n int) int {
	if n < 0 {
		return n * -1
	}
	return n
}
<commit_msg>exclude sample files<commit_after>package mediasort

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"

	"github.com/agnivade/levenshtein"
	"github.com/fatih/color"
	"github.com/jpillora/media-sort/search"
)

type fileSorter struct {
	name, path string
	info       os.FileInfo
	err        error

	s               *Sorter
	ext             string
	mtype           string
	season, episode string
	episodeDate     string //weekly series
	year            string
}

var sample = regexp.MustCompile(`\bsample\b`)

func newFileSorter(s *Sorter, path string, info os.FileInfo) (*fileSorter, error) {
	//attempt to rule out file
	if !info.Mode().IsRegular() {
		return nil, nil
	}
	if sample.MatchString(strings.ToLower(path)) {
		return nil, nil
	}

	name := info.Name()
	ext := filepath.Ext(name)
	if _, exists := s.exts[ext]; !exists {
		return nil, nil
	}
	name = strings.TrimSuffix(name, ext)

	//setup
	return &fileSorter{
		s:       s,
		name:    name,
		path:    path,
		info:    info,
		ext:     ext,
		season:  "1",
		episode: "",
	}, nil
}

//always in a goroutine
func (f *fileSorter) goRun(wg *sync.WaitGroup) {
	f.err = f.run()
	wg.Done()
}

func (f *fileSorter) run() error {

	//normalize name
	query := normalize(f.name)

	//extract episode date (weekly show)
	if f.mtype == "" {
		m := epidate.FindStringSubmatch(query)
		if len(m) > 0 {
			query = m[1] //trim name
			f.mtype = "series"
			f.episodeDate = strings.Replace(m[2], " ", "-", 2)
		}
	}

	//extract episde season numbers
	if f.mtype == "" {
		m := episeason.FindStringSubmatch(query)
		if len(m) > 0 {
			query = m[1] //trim name
			f.mtype = "series"
			f.season = m[3]
			f.episode = m[6]
		}
	}

	//extract *joined* episde season numbers
	if f.mtype == "" {
		m := joinedepiseason.FindStringSubmatch(query)
		if len(m) > 0 {
			query = m[1] //trim name
			f.mtype = "series"
			f.season = m[2]
			f.episode = m[3]
		}
	}

	//extract release year
	m := year.FindStringSubmatch(query)
	if len(m) > 0 {
		query = m[1] //trim name
		if f.mtype == "" {
			f.mtype = "movie" //set type to "movie", if not already set
		}
		f.year = m[2]
	}

	//if the above fails, extract "Part 1/2/3..."
	if f.mtype == "" {
		m := partnum.FindStringSubmatch(query)
		if len(m) > 0 {
			query = m[1] //trim name
			f.mtype = "series"
			f.episode = m[2]
		}
	}

	//trim spaces
	query = strings.TrimSpace(query)

	//search for normalized name
	r, err := search.Do(query, f.year, f.mtype)
	if err != nil {
		return err //search failed
	}

	// normalize so the title is query-like
	title := normalize(r.Title)

	ldiff := abs(len(query) - len(title))

	dist, _ := levenshtein.ComputeDistance(query, title)

	// log.Printf("search found: '%s' -> '%s' %s => %d (#%d)", query, title, r.Type, dist, ldiff)

	// incorrect by more than the query!
	if dist-ldiff > 5 {
		return fmt.Errorf("Best match for '%s' was '%s'", f.name, r.Title)
	}

	//calculate destination path
	dest := ""
	if r.Type == "series" && f.episodeDate != "" {
		filename := fmt.Sprintf("%s %s%s", r.Title, f.episodeDate, f.ext)
		dest = filepath.Join(f.s.c.TVDir, r.Title, filename)
	} else if r.Type == "series" && f.episode != "" {
		s, _ := strconv.Atoi(f.season)
		e, _ := strconv.Atoi(f.episode)
		filename := fmt.Sprintf("%s S%02dE%02d%s", r.Title, s, e, f.ext)
		dest = filepath.Join(f.s.c.TVDir, r.Title, filename)
	} else if r.Type == "movie" {
		filename := fmt.Sprintf("%s (%s)%s", r.Title, r.Year, f.ext)
		dest = filepath.Join(f.s.c.MovieDir, filename)
	} else {
		return fmt.Errorf("TV Series with no episode found '%s'", query)
	}

	//DEBUG
	// log.Printf("SUCCESS = D%d #%d\n  %s\n  %s", r.Distance, len(query), query, r.Title)
	log.Printf("Moving\n  '%s'\n  └─> '%s'", f.path, color.GreenString(dest))

	if f.s.c.DryRun {
		return nil
	}

	//check already exists
	if _, err := os.Stat(dest); err == nil {
		return fmt.Errorf("File already exists '%s'", dest)
	}

	//mkdir -p
	err = os.MkdirAll(filepath.Dir(dest), 0755)
	if err != nil {
		return err //failed to mkdir
	}

	//mv
	err = os.Rename(f.path, dest)
	if err != nil {
		return err //failed to move
	}
	return nil
}

var yearstr = `(19\d\d|20[0,1]\d)`

var encodings = regexp.MustCompile(`\b(720p|1080p|hdtv|x264|dts|bluray)\b.*`) //strip all junk
var nonalpha = regexp.MustCompile(`[^A-Za-z0-9]`)
var spaces = regexp.MustCompile(`\s+`)
var episeason = regexp.MustCompile(`^(.+?)\bs?(eason)?(\d{1,2})(e|\ |\ e|x|xe)(pisode)?(\d{1,2})\b`)
var epidate = regexp.MustCompile(`^(.+?\b)(` + yearstr + ` \d{2} \d{2}|\d{2} \d{2} ` + yearstr + `)\b`)
var year = regexp.MustCompile(`^(.+?\b)` + yearstr + `\b`)
var joinedepiseason = regexp.MustCompile(`^(.+?\b)(\d)(\d{2})\b`)
var partnum = regexp.MustCompile(`^(.+?\b)(\d{1,2})\b`)

//TODO var romannumerals...

func normalize(s string) string {
	s = strings.ToLower(s)
	s = nonalpha.ReplaceAllString(s, " ")
	s = encodings.ReplaceAllString(s, "")
	s = spaces.ReplaceAllString(s, " ")
	s = strings.TrimSpace(s)
	return s
}

func abs(n int) int {
	if n < 0 {
		return n * -1
	}
	return n
}
<|endoftext|>


<commit_before>package hu

import (
	"fmt"
	"bytes"
	"big"
)

type Term interface {
	String() string
}

type Evaluable interface {
	Evaluate(*Environment) Term
}

type Rune int

func (rune Rune) String() string {
	return string(rune)
}

type Boolean bool

func (b Boolean) String() (result string) {
	if b {
		result  = "true"
	} else {
		result  = "false"
	}
	return
}

type Number struct {
	value *big.Int
}

func (n *Number) String() string {
	return n.value.String()
}

type Symbol string

func (s Symbol) String() string {
	return string(s)
}

func (s Symbol) Evaluate(environment *Environment) Term {
	return environment.Get(s)
}

type String string

func (s String) String() string {
	var out bytes.Buffer
	for _, rune := range s {
		switch rune {
		case '\n':
			out.WriteString("\\n")
			break
		case '\\':
			out.WriteString("\\\\")
			break
		case '"':
			out.WriteString("\\\"")
			break
		default:
			out.WriteRune(rune)
		}
	}
	return out.String()
}

type Pair struct {
	car, cdr Term
}

func (pair *Pair) String() string {
	return fmt.Sprintf("(%v %v)", pair.car, pair.cdr)
}

type Operator interface {
	apply(*Environment, Term) Term
}

type PrimitiveFunction func(*Environment, Term) Term

func (pf PrimitiveFunction) apply(environment *Environment, term Term) Term {
	return pf(environment, term)
}

func (pf PrimitiveFunction) String() string {
	return fmt.Sprintf("#<primitive-function> %p", pf)
}

type Primitive func(*Environment) Term

func (p Primitive) String() string {
	return fmt.Sprintf("#<primitive> %p", p)
}

func (p Primitive) Evaluate(environment *Environment) Term {
	return p(environment)
}

type Application struct {
	term Term
}

func (application Application) String() string {
	return fmt.Sprintf("{%v}", application.term)
}

func (application Application) Evaluate(environment *Environment) Term {
	var lhs, last *Pair
	for term := application.term; term != nil; term = cdr(term) {
		switch operator := environment.evaluate(car(term)).(type) {
		case Operator:
			var operands Term
			switch operator.(type) {
			case PrimitiveFunction:
				operands = cdr(term)
			default:
				operands = &Pair{lhs, &Pair{cdr(term), nil}}
			}
			term = operator.apply(environment, operands)
			return term
		default:
			e := &Pair{operator, nil}
			if lhs == nil {	lhs = e	} else { last.cdr = e }
			last = e
		}
	}
	return lhs
}

type Abstraction struct {
	parameters Term
	term Term
}

func (a Abstraction) apply(environment *Environment, values Term) Term {
	e := environment.NewChildEnvironment()
	e.Extend(a.parameters, values)
	return Closure{a.term, e}
}

func (abstraction Abstraction) String() string {
	return fmt.Sprintf("#<abstraction> %v %v", abstraction.parameters, abstraction.term)
}

type Closure struct {
	term Term
	environment *Environment
}

func (closure Closure) String() string {
	return fmt.Sprintf("#<Closure> %v %v\n", closure.term, closure.environment)
}

func (closure Closure) Evaluate(environment *Environment) Term {
	return closure.environment.evaluate(closure.term)
}

type Error string

func (error Error) String() string {
	return string(error)
}

type UnboundVariableError struct {
	variable Term
	operation string
}

func (e UnboundVariableError) String() string {
	return "Unbound Variable: " + e.variable.String() + " operation: " + e.operation
}

type Environment struct {
	frame  map[Symbol]Term
	parent *Environment
}

func (environment *Environment) String() string {
	return "#<environment>"
}

func NewEnvironment() *Environment {
	return &Environment{frame: make(map[Symbol]Term)}
}

// returns a new (child) environment from this environment extended
// with bindings given by variables, values.
func (environment *Environment) NewChildEnvironment() *Environment {
	child := NewEnvironment()
	child.parent = environment
	return child
}

func (environment *Environment) Closure(term Term) Term {
	switch v := term.(type) {
	case Application:
		return Closure{term, environment}
	}
	return term
}

func (environment *Environment) Extend(variables, values Term) {
	for ; variables != nil && values != nil; variables, values = cdr(variables), cdr(values) {
		switch variables.(type) {
		case *Pair:
			environment.Extend(car(variables), car(values))
		default:
			environment.frame[variables.(Symbol)] = environment.parent.Closure(values)
			return
		}
	}
}

func (environment *Environment) Define(variable Symbol, value Term) {
	environment.frame[variable] = environment.Closure(value)
}

func (environment *Environment) Set(variable Symbol, value Term) {
	_, ok := environment.frame[variable]
	if ok {
		environment.frame[variable] = environment.Closure(value)
	} else if environment.parent != nil {
		environment.parent.Set(variable, value)
	} else {
		panic(UnboundVariableError{variable, "set"})
	}
}

func (environment *Environment) Get(variable Symbol) Term {
	value, ok := environment.frame[variable]
	if ok {
		return value
	} else if environment.parent != nil {
		return environment.parent.Get(variable)
	} else {
		panic(UnboundVariableError{variable, "get"})
	}
	return nil
}

func (environment *Environment) AddPrimitive(name string, function PrimitiveFunction) {
	environment.Define(Symbol(name), function)
}

func (environment *Environment) Evaluate(term Term) (result Term) {
	defer func() {
		switch x := recover().(type) {
		case Term:
			result = x
		case interface{}:
			result = Error(fmt.Sprintf("%v", x))
		}
	}()
	result = environment.evaluate(term)
	return
}

func (environment *Environment) evaluate(term Term) Term {
tailcall:
	switch t := term.(type) {
	case Evaluable:
		term = t.Evaluate(environment)
		goto tailcall
	}
	return term
}

func cons(car, cdr Term) Term {
	return &Pair{car, cdr}
}

func car(term Term) Term {
	return term.(*Pair).car
}

func cdr(term Term) Term {
	return term.(*Pair).cdr
}

func list_from(list Term, selector func(Term) Term) (result Term) {
	if list != nil {
		result = &Pair{selector(car(list)), list_from(cdr(list), selector)}
	}
	return
}

func concat(pairs ...*Pair) (result *Pair) {
	var last *Pair
	for _, pair := range pairs {
		var term Term = pair
		for ; term != nil; term = cdr(term) {
			if result == nil {
				result = &Pair{car(term), nil}
				last = result
			} else {
				p := &Pair{car(term), nil}
				last.cdr = p
				last = p
			}
		}
	}
	return result
}
<commit_msg>renamed Evaluable interface to Reducible<commit_after>package hu

import (
	"fmt"
	"bytes"
	"big"
)

type Term interface {
	String() string
}

type Reducible interface {
	Reduce(*Environment) Term
}

type Rune int

func (rune Rune) String() string {
	return string(rune)
}

type Boolean bool

func (b Boolean) String() (result string) {
	if b {
		result  = "true"
	} else {
		result  = "false"
	}
	return
}

type Number struct {
	value *big.Int
}

func (n *Number) String() string {
	return n.value.String()
}

type Symbol string

func (s Symbol) String() string {
	return string(s)
}

func (s Symbol) Reduce(environment *Environment) Term {
	return environment.Get(s)
}

type String string

func (s String) String() string {
	var out bytes.Buffer
	for _, rune := range s {
		switch rune {
		case '\n':
			out.WriteString("\\n")
			break
		case '\\':
			out.WriteString("\\\\")
			break
		case '"':
			out.WriteString("\\\"")
			break
		default:
			out.WriteRune(rune)
		}
	}
	return out.String()
}

type Pair struct {
	car, cdr Term
}

func (pair *Pair) String() string {
	return fmt.Sprintf("(%v %v)", pair.car, pair.cdr)
}

type Operator interface {
	apply(*Environment, Term) Term
}

type PrimitiveFunction func(*Environment, Term) Term

func (pf PrimitiveFunction) apply(environment *Environment, term Term) Term {
	return pf(environment, term)
}

func (pf PrimitiveFunction) String() string {
	return fmt.Sprintf("#<primitive-function> %p", pf)
}

type Primitive func(*Environment) Term

func (p Primitive) String() string {
	return fmt.Sprintf("#<primitive> %p", p)
}

func (p Primitive) Reduce(environment *Environment) Term {
	return p(environment)
}

type Application struct {
	term Term
}

func (application Application) String() string {
	return fmt.Sprintf("{%v}", application.term)
}

func (application Application) Reduce(environment *Environment) Term {
	var lhs, last *Pair
	for term := application.term; term != nil; term = cdr(term) {
		switch operator := environment.evaluate(car(term)).(type) {
		case Operator:
			var operands Term
			switch operator.(type) {
			case PrimitiveFunction:
				operands = cdr(term)
			default:
				operands = &Pair{lhs, &Pair{cdr(term), nil}}
			}
			term = operator.apply(environment, operands)
			return term
		default:
			e := &Pair{operator, nil}
			if lhs == nil {	lhs = e	} else { last.cdr = e }
			last = e
		}
	}
	return lhs
}

type Abstraction struct {
	parameters Term
	term Term
}

func (a Abstraction) apply(environment *Environment, values Term) Term {
	e := environment.NewChildEnvironment()
	e.Extend(a.parameters, values)
	return Closure{a.term, e}
}

func (abstraction Abstraction) String() string {
	return fmt.Sprintf("#<abstraction> %v %v", abstraction.parameters, abstraction.term)
}

type Closure struct {
	term Term
	environment *Environment
}

func (closure Closure) String() string {
	return fmt.Sprintf("#<Closure> %v %v\n", closure.term, closure.environment)
}

func (closure Closure) Reduce(environment *Environment) Term {
	return closure.environment.evaluate(closure.term)
}

type Error string

func (error Error) String() string {
	return string(error)
}

type UnboundVariableError struct {
	variable Term
	operation string
}

func (e UnboundVariableError) String() string {
	return "Unbound Variable: " + e.variable.String() + " operation: " + e.operation
}

type Environment struct {
	frame  map[Symbol]Term
	parent *Environment
}

func (environment *Environment) String() string {
	return "#<environment>"
}

func NewEnvironment() *Environment {
	return &Environment{frame: make(map[Symbol]Term)}
}

// returns a new (child) environment from this environment extended
// with bindings given by variables, values.
func (environment *Environment) NewChildEnvironment() *Environment {
	child := NewEnvironment()
	child.parent = environment
	return child
}

func (environment *Environment) Closure(term Term) Term {
	switch v := term.(type) {
	case Application:
		return Closure{term, environment}
	}
	return term
}

func (environment *Environment) Extend(variables, values Term) {
	for ; variables != nil && values != nil; variables, values = cdr(variables), cdr(values) {
		switch variables.(type) {
		case *Pair:
			environment.Extend(car(variables), car(values))
		default:
			environment.frame[variables.(Symbol)] = environment.parent.Closure(values)
			return
		}
	}
}

func (environment *Environment) Define(variable Symbol, value Term) {
	environment.frame[variable] = environment.Closure(value)
}

func (environment *Environment) Set(variable Symbol, value Term) {
	_, ok := environment.frame[variable]
	if ok {
		environment.frame[variable] = environment.Closure(value)
	} else if environment.parent != nil {
		environment.parent.Set(variable, value)
	} else {
		panic(UnboundVariableError{variable, "set"})
	}
}

func (environment *Environment) Get(variable Symbol) Term {
	value, ok := environment.frame[variable]
	if ok {
		return value
	} else if environment.parent != nil {
		return environment.parent.Get(variable)
	} else {
		panic(UnboundVariableError{variable, "get"})
	}
	return nil
}

func (environment *Environment) AddPrimitive(name string, function PrimitiveFunction) {
	environment.Define(Symbol(name), function)
}

func (environment *Environment) Evaluate(term Term) (result Term) {
	defer func() {
		switch x := recover().(type) {
		case Term:
			result = x
		case interface{}:
			result = Error(fmt.Sprintf("%v", x))
		}
	}()
	result = environment.evaluate(term)
	return
}

func (environment *Environment) evaluate(term Term) Term {
tailcall:
	switch t := term.(type) {
	case Reducible:
		term = t.Reduce(environment)
		goto tailcall
	}
	return term
}

func cons(car, cdr Term) Term {
	return &Pair{car, cdr}
}

func car(term Term) Term {
	return term.(*Pair).car
}

func cdr(term Term) Term {
	return term.(*Pair).cdr
}

func list_from(list Term, selector func(Term) Term) (result Term) {
	if list != nil {
		result = &Pair{selector(car(list)), list_from(cdr(list), selector)}
	}
	return
}

func concat(pairs ...*Pair) (result *Pair) {
	var last *Pair
	for _, pair := range pairs {
		var term Term = pair
		for ; term != nil; term = cdr(term) {
			if result == nil {
				result = &Pair{car(term), nil}
				last = result
			} else {
				p := &Pair{car(term), nil}
				last.cdr = p
				last = p
			}
		}
	}
	return result
}
<|endoftext|>


<commit_before>// +build go1.7

// Package middleware provides some usable transport middleware to deal with
// propagating Zipkin traces across service boundaries.
package middleware

import (
	"fmt"
	"net"
	"net/http"
	"strconv"

	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
)

// RequestFunc is a middleware function for outgoing HTTP requests.
type RequestFunc func(req *http.Request) *http.Request

// ToHTTPRequest returns a RequestFunc that injects an OpenTracing Span found in
// context into the HTTP Headers. If no such Span can be found, the RequestFunc
// is a noop.
func ToHTTPRequest(tracer opentracing.Tracer) RequestFunc {
	return func(req *http.Request) *http.Request {
		// Retrieve the Span from context.
		if span := opentracing.SpanFromContext(req.Context()); span != nil {

			// We are going to use this span in a client request, so mark as such.
			ext.SpanKindRPCClient.Set(span)

			// Add some standard OpenTracing tags, useful in an HTTP request.
			ext.HTTPMethod.Set(span, req.Method)
			ext.HTTPUrl.Set(span, req.URL.RequestURI())

			// Add information on the peer service we're about to contact.
			if host, portString, err := net.SplitHostPort(req.URL.Host); err == nil {
				ext.PeerHostname.Set(span, host)
				if port, err := strconv.Atoi(portString); err != nil {
					ext.PeerPort.Set(span, uint16(port))
				}
			} else {
				ext.PeerHostname.Set(span, req.URL.Host)
			}

			// Inject the Span context into the outgoing HTTP Request.
			if err := tracer.Inject(
				span.Context(),
				opentracing.TextMap,
				opentracing.HTTPHeadersCarrier(req.Header),
			); err != nil {
				fmt.Printf("error encountered while trying to inject span: %+v", err)
			}
		}
		return req
	}
}

// HandlerFunc is a middleware function for incoming HTTP requests.
type HandlerFunc func(next http.Handler) http.Handler

// FromHTTPRequest returns a Middleware HandlerFunc that tries to join with an
// OpenTracing trace found in the HTTP request headers and starts a new Span
// called `operationName`. If no trace could be found in the HTTP request
// headers, the Span will be a trace root. The Span is incorporated in the
// HTTP Context object and can be retrieved with
// opentracing.SpanFromContext(ctx).
func FromHTTPRequest(tracer opentracing.Tracer, operationName string,
) HandlerFunc {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			// Try to join to a trace propagated in `req`.
			wireContext, err := tracer.Extract(
				opentracing.TextMap,
				opentracing.HTTPHeadersCarrier(req.Header),
			)
			if err != nil {
				fmt.Printf("error encountered while trying to extract span: %+v\n", err)
			}

			// create span
			span := tracer.StartSpan(operationName, ext.RPCServerOption(wireContext))
			span.SetTag("serverSide", "here")
			defer span.Finish()

			// store span in context
			ctx := opentracing.ContextWithSpan(req.Context(), span)

			// update request context to include our new span
			req = req.WithContext(ctx)

			// next middleware or actual request handler
			next.ServeHTTP(w, req)
		})
	}
}
<commit_msg>minor improvements to HTTP request middleware example<commit_after>// +build go1.7

// Package middleware provides some usable transport middleware to deal with
// propagating Zipkin traces across service boundaries.
package middleware

import (
	"fmt"
	"net"
	"net/http"
	"strconv"

	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"

	"github.com/openzipkin/zipkin-go-opentracing/_thrift/gen-go/zipkincore"
)

// RequestFunc is a middleware function for outgoing HTTP requests.
type RequestFunc func(req *http.Request) *http.Request

// ToHTTPRequest returns a RequestFunc that injects an OpenTracing Span found in
// context into the HTTP Headers. If no such Span can be found, the RequestFunc
// is a noop.
func ToHTTPRequest(tracer opentracing.Tracer) RequestFunc {
	return func(req *http.Request) *http.Request {
		// Retrieve the Span from context.
		if span := opentracing.SpanFromContext(req.Context()); span != nil {

			// We are going to use this span in a client request, so mark as such.
			ext.SpanKindRPCClient.Set(span)

			// Add some standard OpenTracing tags, useful in an HTTP request.
			ext.HTTPMethod.Set(span, req.Method)
			span.SetTag(zipkincore.HTTP_HOST, req.URL.Host)
			span.SetTag(zipkincore.HTTP_PATH, req.URL.Path)
			ext.HTTPUrl.Set(
				span,
				fmt.Sprintf("%s://%s%s", req.URL.Scheme, req.URL.Host, req.URL.Path),
			)

			// Add information on the peer service we're about to contact.
			if host, portString, err := net.SplitHostPort(req.URL.Host); err == nil {
				ext.PeerHostname.Set(span, host)
				if port, err := strconv.Atoi(portString); err != nil {
					ext.PeerPort.Set(span, uint16(port))
				}
			} else {
				ext.PeerHostname.Set(span, req.URL.Host)
			}

			// Inject the Span context into the outgoing HTTP Request.
			if err := tracer.Inject(
				span.Context(),
				opentracing.TextMap,
				opentracing.HTTPHeadersCarrier(req.Header),
			); err != nil {
				fmt.Printf("error encountered while trying to inject span: %+v", err)
			}
		}
		return req
	}
}

// HandlerFunc is a middleware function for incoming HTTP requests.
type HandlerFunc func(next http.Handler) http.Handler

// FromHTTPRequest returns a Middleware HandlerFunc that tries to join with an
// OpenTracing trace found in the HTTP request headers and starts a new Span
// called `operationName`. If no trace could be found in the HTTP request
// headers, the Span will be a trace root. The Span is incorporated in the
// HTTP Context object and can be retrieved with
// opentracing.SpanFromContext(ctx).
func FromHTTPRequest(tracer opentracing.Tracer, operationName string,
) HandlerFunc {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			// Try to join to a trace propagated in `req`.
			wireContext, err := tracer.Extract(
				opentracing.TextMap,
				opentracing.HTTPHeadersCarrier(req.Header),
			)
			if err != nil {
				fmt.Printf("error encountered while trying to extract span: %+v\n", err)
			}

			// create span
			span := tracer.StartSpan(operationName, ext.RPCServerOption(wireContext))
			span.SetTag("serverSide", "here")
			defer span.Finish()

			// store span in context
			ctx := opentracing.ContextWithSpan(req.Context(), span)

			// update request context to include our new span
			req = req.WithContext(ctx)

			// next middleware or actual request handler
			next.ServeHTTP(w, req)
		})
	}
}
<|endoftext|>


<commit_before>package should

import (
	"fmt"
	"strings"

	"github.com/y0ssar1an/q"
)

// tools for working with failure messages

const (
	// ShortSeparator ends the failure message short portion (and begins the long
	// portion)
	ShortSeparator = "\n"

	// ShortLength is an arbitrary length used to shorten failure messages that
	// don't contain ShortSeparator
	ShortLength = 80

	// LongSeparator ends the failure message explanation section (and begins the
	// details)
	LongSeparator = "\n# DETAILS:"

	// DetailsSeparator ends the failure debugging portion (and begins details for
	// debugging asserts and test runner.)
	DetailsSeparator = "\n# INTERNALS:"

	// SectionSeparator separates the long, details, and internals sections.
	SectionSeparator = "\n~~~~~~~~~~\n"
)

func trim(s string) string {
	return strings.Trim(s, " \n\t\r")
}

func splitShortLong(s string) (short, long string) {
	sl := strings.SplitN(trim(s), ShortSeparator, 2)
	q.Q(s, `"`, trim(s), `"`, sl)
	if len(sl) > 1 {
		return trim(sl[0]), trim(sl[1])
	}
	if len(s) > ShortLength {
		return trim(s[:ShortLength]), trim(s[ShortLength:])
	}
	return trim(s), ""
}

// SplitMsg divides a failure message into parts that may be muted depending on verbosity levels
func SplitMsg(msg string) (short, long, details, meta string) {
	if msg == "" {
		return
	}
	secs := strings.Split(msg, SectionSeparator)
	short, long = splitShortLong(secs[0])
	if len(secs) > 1 {
		details = trim(secs[1])
	}
	if len(secs) > 2 {
		meta = trim(secs[2])
	}
	return
}

func oldSplitMsg(msg string) (short, long, details, meta string) {
	msgZ := len(msg)
	findAndClean := func(start int, find string) (string, int) {
		fmt.Printf("Searching from %d for %s.\n", start, find)
		if start >= msgZ {
			return "", msgZ
		}
		pos := strings.Index(msg[start:], find)
		if pos < 0 { // not found
			return "", start
		}
		return msg[start:pos], pos + len(find)
	}
	// shortZ := findOrSetToLength(ShortSeparator)
	// longZ := findOrSetToLength(LongSeparator)
	pos := 0
	short, pos = findAndClean(pos, ShortSeparator)
	if short == "" { // special case: not formatted by our rules or only a short message
		short = msg
		return
	}
	long, _ = findAndClean(pos, LongSeparator)
	// details = msg[detailsZ:]
	// meta = fail[metaZ:]
	return
}

// JoinMsg creates a failure message from its components
func JoinMsg(short, long, details, meta string) (result string) {
	result = short + ShortSeparator + long + SectionSeparator + details + SectionSeparator + meta
	return
}
<commit_msg>Removed debug code<commit_after>package should

import (
	"fmt"
	"strings"
)

// tools for working with failure messages

const (
	// ShortSeparator ends the failure message short portion (and begins the long
	// portion)
	ShortSeparator = "\n"

	// ShortLength is an arbitrary length used to shorten failure messages that
	// don't contain ShortSeparator
	ShortLength = 80

	// LongSeparator ends the failure message explanation section (and begins the
	// details)
	LongSeparator = "\n# DETAILS:"

	// DetailsSeparator ends the failure debugging portion (and begins details for
	// debugging asserts and test runner.)
	DetailsSeparator = "\n# INTERNALS:"

	// SectionSeparator separates the long, details, and internals sections.
	SectionSeparator = "\n~~~~~~~~~~\n"
)

func trim(s string) string {
	return strings.Trim(s, " \n\t\r")
}

func splitShortLong(s string) (short, long string) {
	sl := strings.SplitN(trim(s), ShortSeparator, 2)
	if len(sl) > 1 {
		return trim(sl[0]), trim(sl[1])
	}
	if len(s) > ShortLength {
		return trim(s[:ShortLength]), trim(s[ShortLength:])
	}
	return trim(s), ""
}

// SplitMsg divides a failure message into parts that may be muted depending on verbosity levels
func SplitMsg(msg string) (short, long, details, meta string) {
	if msg == "" {
		return
	}
	secs := strings.Split(msg, SectionSeparator)
	short, long = splitShortLong(secs[0])
	if len(secs) > 1 {
		details = trim(secs[1])
	}
	if len(secs) > 2 {
		meta = trim(secs[2])
	}
	return
}

func oldSplitMsg(msg string) (short, long, details, meta string) {
	msgZ := len(msg)
	findAndClean := func(start int, find string) (string, int) {
		fmt.Printf("Searching from %d for %s.\n", start, find)
		if start >= msgZ {
			return "", msgZ
		}
		pos := strings.Index(msg[start:], find)
		if pos < 0 { // not found
			return "", start
		}
		return msg[start:pos], pos + len(find)
	}
	// shortZ := findOrSetToLength(ShortSeparator)
	// longZ := findOrSetToLength(LongSeparator)
	pos := 0
	short, pos = findAndClean(pos, ShortSeparator)
	if short == "" { // special case: not formatted by our rules or only a short message
		short = msg
		return
	}
	long, _ = findAndClean(pos, LongSeparator)
	// details = msg[detailsZ:]
	// meta = fail[metaZ:]
	return
}

// JoinMsg creates a failure message from its components
func JoinMsg(short, long, details, meta string) (result string) {
	result = short + ShortSeparator + long + SectionSeparator + details + SectionSeparator + meta
	return
}
<|endoftext|>


<commit_before>package pg

import (
	"net"
	"time"

	"gopkg.in/pg.v4/internal/pool"
)

// Database connection options.
type Options struct {
	// The network type, either tcp or unix.
	// Default is tcp.
	Network  string
	Addr     string
	User     string
	Password string
	Database string
	// Whether to use secure TCP/IP connections (TLS).
	SSL bool

	// Run-time configuration parameters to be set on connection.
	Params map[string]interface{}

	// The maximum number of retries before giving up.
	// Default is to not retry failed queries.
	MaxRetries int

	// The deadline for establishing new connections. If reached,
	// dial will fail with a timeout.
	// Default is 5 seconds.
	DialTimeout time.Duration
	// The timeout for socket reads. If reached, commands will fail
	// with a timeout error instead of blocking.
	// Default is no timeout.
	ReadTimeout time.Duration
	// The timeout for socket writes. If reached, commands will fail
	// with a timeout error instead of blocking.
	// Default is no timeout.
	WriteTimeout time.Duration

	// The maximum number of open socket connections.
	// Default is 10 connections.
	PoolSize int
	// The amount of time client waits for free connection if all
	// connections are busy before returning an error.
	// Default is 5 seconds.
	PoolTimeout time.Duration
	// The amount of time after which client closes idle connections.
	// Default is to not close idle connections.
	IdleTimeout time.Duration
	// The frequency of idle checks.
	// Default is 1 minute.
	IdleCheckFrequency time.Duration
}

func (opt *Options) getNetwork() string {
	if opt == nil || opt.Network == "" {
		return "tcp"
	}
	return opt.Network
}

func (opt *Options) getAddr() string {
	if opt.Addr != "" {
		return opt.Addr
	}
	if opt.getNetwork() == "unix" {
		return "/var/run/postgresql/.s.PGSQL.5432"
	}
	return "localhost:5432"
}

func (opt *Options) getUser() string {
	if opt == nil || opt.User == "" {
		return ""
	}
	return opt.User
}

func (opt *Options) getPassword() string {
	if opt == nil || opt.Password == "" {
		return ""
	}
	return opt.Password
}

func (opt *Options) getDatabase() string {
	if opt == nil || opt.Database == "" {
		return ""
	}
	return opt.Database
}

func (opt *Options) getPoolSize() int {
	if opt == nil || opt.PoolSize == 0 {
		return 10
	}
	return opt.PoolSize
}

func (opt *Options) getPoolTimeout() time.Duration {
	if opt == nil || opt.PoolTimeout == 0 {
		return 5 * time.Second
	}
	return opt.PoolTimeout
}

func (opt *Options) getDialTimeout() time.Duration {
	if opt.DialTimeout == 0 {
		return 5 * time.Second
	}
	return opt.DialTimeout
}

func (opt *Options) getIdleTimeout() time.Duration {
	return opt.IdleTimeout
}

func (opt *Options) getIdleCheckFrequency() time.Duration {
	if opt.IdleCheckFrequency == 0 {
		return time.Minute
	}
	return opt.IdleCheckFrequency
}

func (opt *Options) getSSL() bool {
	return opt.SSL
}

func (opt *Options) getDialer() func() (net.Conn, error) {
	return func() (net.Conn, error) {
		return net.DialTimeout(opt.getNetwork(), opt.getAddr(), opt.getDialTimeout())
	}
}

func newConnPool(opt *Options) *pool.ConnPool {
	p := pool.NewConnPool(
		opt.getDialer(),
		opt.getPoolSize(),
		opt.getPoolTimeout(),
		opt.getIdleTimeout(),
		opt.getIdleCheckFrequency(),
	)
	p.OnClose = func(cn *pool.Conn) error {
		return terminateConn(cn)
	}
	return p
}
<commit_msg>Add comment on Addr field. Fixes #131.<commit_after>package pg

import (
	"net"
	"time"

	"gopkg.in/pg.v4/internal/pool"
)

// Database connection options.
type Options struct {
	// The network type, either tcp or unix.
	// Default is tcp.
	Network string
	// TCP host:port or Unix socket depending on Network.
	Addr     string
	User     string
	Password string
	Database string
	// Whether to use secure TCP/IP connections (TLS).
	SSL bool

	// PostgreSQL run-time configuration parameters to be set on connection.
	Params map[string]interface{}

	// The maximum number of retries before giving up.
	// Default is to not retry failed queries.
	MaxRetries int

	// The deadline for establishing new connections. If reached,
	// dial will fail with a timeout.
	// Default is 5 seconds.
	DialTimeout time.Duration
	// The timeout for socket reads. If reached, commands will fail
	// with a timeout error instead of blocking.
	// Default is no timeout.
	ReadTimeout time.Duration
	// The timeout for socket writes. If reached, commands will fail
	// with a timeout error instead of blocking.
	// Default is no timeout.
	WriteTimeout time.Duration

	// The maximum number of open socket connections.
	// Default is 10 connections.
	PoolSize int
	// The amount of time client waits for free connection if all
	// connections are busy before returning an error.
	// Default is 5 seconds.
	PoolTimeout time.Duration
	// The amount of time after which client closes idle connections.
	// Default is to not close idle connections.
	IdleTimeout time.Duration
	// The frequency of idle checks.
	// Default is 1 minute.
	IdleCheckFrequency time.Duration
}

func (opt *Options) getNetwork() string {
	if opt == nil || opt.Network == "" {
		return "tcp"
	}
	return opt.Network
}

func (opt *Options) getAddr() string {
	if opt.Addr != "" {
		return opt.Addr
	}
	if opt.getNetwork() == "unix" {
		return "/var/run/postgresql/.s.PGSQL.5432"
	}
	return "localhost:5432"
}

func (opt *Options) getUser() string {
	if opt == nil || opt.User == "" {
		return ""
	}
	return opt.User
}

func (opt *Options) getPassword() string {
	if opt == nil || opt.Password == "" {
		return ""
	}
	return opt.Password
}

func (opt *Options) getDatabase() string {
	if opt == nil || opt.Database == "" {
		return ""
	}
	return opt.Database
}

func (opt *Options) getPoolSize() int {
	if opt == nil || opt.PoolSize == 0 {
		return 10
	}
	return opt.PoolSize
}

func (opt *Options) getPoolTimeout() time.Duration {
	if opt == nil || opt.PoolTimeout == 0 {
		return 5 * time.Second
	}
	return opt.PoolTimeout
}

func (opt *Options) getDialTimeout() time.Duration {
	if opt.DialTimeout == 0 {
		return 5 * time.Second
	}
	return opt.DialTimeout
}

func (opt *Options) getIdleTimeout() time.Duration {
	return opt.IdleTimeout
}

func (opt *Options) getIdleCheckFrequency() time.Duration {
	if opt.IdleCheckFrequency == 0 {
		return time.Minute
	}
	return opt.IdleCheckFrequency
}

func (opt *Options) getSSL() bool {
	return opt.SSL
}

func (opt *Options) getDialer() func() (net.Conn, error) {
	return func() (net.Conn, error) {
		return net.DialTimeout(opt.getNetwork(), opt.getAddr(), opt.getDialTimeout())
	}
}

func newConnPool(opt *Options) *pool.ConnPool {
	p := pool.NewConnPool(
		opt.getDialer(),
		opt.getPoolSize(),
		opt.getPoolTimeout(),
		opt.getIdleTimeout(),
		opt.getIdleCheckFrequency(),
	)
	p.OnClose = func(cn *pool.Conn) error {
		return terminateConn(cn)
	}
	return p
}
<|endoftext|>


<commit_before>package mesos_master_api
import (
	"github.com/layer-x/layerx-commons/lxlog"
	"github.com/Sirupsen/logrus"
	"net/http"
	"github.com/layer-x/layerx-mesos-tpi_v2/mesos_master_api/mesos_api_helpers"
	"github.com/layer-x/layerx-commons/lxerrors"
	"github.com/layer-x/layerx-commons/lxactionqueue"
	"github.com/layer-x/layerx-mesos-tpi_v2/mesos_master_api/mesos_data"
	"github.com/layer-x/layerx-mesos-tpi_v2/framework_manager"
	"github.com/mesos/mesos-go/mesosproto"
	"github.com/gogo/protobuf/proto"
	"github.com/layer-x/layerx-core_v2/layerx_tpi"
	"github.com/go-martini/martini"
)

const (
	GET_MASTER_STATE = "/master/state.json"
	GET_MASTER_STATE_DEPRECATED = "/state.json"
	MESOS_SCHEDULER_CALL = "/master/mesos.scheduler.Call"
	REGISTER_FRAMEWORK_MESSAGE = "/master/mesos.internal.RegisterFrameworkMessage"
	REREGISTER_FRAMEWORK_MESSAGE = "/master/mesos.internal.ReregisterFrameworkMessage"
	UNREGISTER_FRAMEWORK_MESSAGE = "/master/mesos.internal.UnregisterFrameworkMessage"
	LAUNCH_TASKS_MESSAGE = "/master/mesos.internal.LaunchTasksMessage"
	RECONCILE_TASKS_MESSAGE = "/master/mesos.internal.ReconcileTasksMessage"
	KILL_TASK_MESSAGE = "/master/mesos.internal.KillTaskMessage"
	STATUS_UPDATE_ACKNOWLEDGEMENT_MESSAGE = "/master/mesos.internal.StatusUpdateAcknowledgementMessage"
	REVIVE_OFFERS_MESSAGE = "/master/mesos.internal.ReviveOffersMessage"
)

var empty = []byte{}

type mesosApiServerWrapper struct {
	actionQueue      lxactionqueue.ActionQueue
	frameworkManager framework_manager.FrameworkManager
	tpi              *layerx_tpi.LayerXTpi
}

func NewMesosApiServerWrapper(tpi *layerx_tpi.LayerXTpi, actionQueue lxactionqueue.ActionQueue, frameworkManager framework_manager.FrameworkManager) *mesosApiServerWrapper {
	return &mesosApiServerWrapper{
		actionQueue: actionQueue,
		frameworkManager: frameworkManager,
		tpi: tpi,
	}
}

func (wrapper *mesosApiServerWrapper) WrapWithMesos(m *martini.ClassicMartini, masterUpidString string, driverErrc chan error) *martini.ClassicMartini {
	getMasterStateHandler := func(res http.ResponseWriter) {
		getStateFn := func() ([]byte, int, error) {
			data, err := mesos_api_helpers.GetMesosState(masterUpidString)
			if err != nil {
				return empty, 500, lxerrors.New("retreiving master state", err)
			}
			return data, 200, nil
		}
		data, statusCode, err := wrapper.queueOperation(getStateFn)
		if err != nil {
			res.WriteHeader(statusCode)
			lxlog.Errorf(logrus.Fields{
				"request_sent_by": masterUpidString,
			}, "Retreiving master state")
			driverErrc <- err
			return
		}
		res.Write(data)
	}
	mesosSchedulerCallHandler := func(req *http.Request, res http.ResponseWriter) {
		processMesosCallFn := func() ([]byte, int, error) {
			upid, data, statusCode, err := mesos_api_helpers.ProcessMesosHttpRequest(req)
			if err != nil {
				return empty, statusCode, lxerrors.New("parsing reregisterFramework request", err)
			}
			err = wrapper.processMesosCall(data, upid)
			if err != nil {
				lxlog.Errorf(logrus.Fields{
					"error": err,
				}, "could not read process scheduler call request")
				return empty, 500, lxerrors.New("could not read process scheduler call request", err)
			}
			return empty, 202, nil
		}
		_, statusCode, err := wrapper.queueOperation(processMesosCallFn)
		if err != nil {
			res.WriteHeader(statusCode)
			lxlog.Errorf(logrus.Fields{
				"error": err.Error(),
				"request_sent_by": masterUpidString,
			}, "processing mesos call message")
			driverErrc <- err
			return
		}
		res.WriteHeader(statusCode)
	}
	registerFrameworkMessageHandler := func(req *http.Request, res http.ResponseWriter) {
		registerFrameworkFn := func() ([]byte, int, error) {
			upid, data, statusCode, err := mesos_api_helpers.ProcessMesosHttpRequest(req)
			if err != nil {
				return empty, statusCode, lxerrors.New("parsing registerFramework request", err)
			}
			var registerRequest mesosproto.RegisterFrameworkMessage
			err = proto.Unmarshal(data, &registerRequest)
			if err != nil {
				return empty, 500, lxerrors.New("could not parse data to protobuf msg Call", err)
			}
			err = mesos_api_helpers.HandleRegisterRequest(wrapper.tpi, wrapper.frameworkManager, upid, registerRequest.GetFramework())
			if err != nil {
				lxlog.Errorf(logrus.Fields{
					"error": err,
				}, "could not handle register framework request")
				return empty, 500, lxerrors.New("could not handle register framework request", err)
			}
			return empty, 202, nil
		}
		_, statusCode, err := wrapper.queueOperation(registerFrameworkFn)
		if err != nil {
			res.WriteHeader(statusCode)
			lxlog.Errorf(logrus.Fields{
				"error": err.Error(),
				"request_sent_by": masterUpidString,
			}, "processing register framework message")
			driverErrc <- err
			return
		}
		res.WriteHeader(statusCode)
	}
	reregisterFrameworkMessageHandler := func(req *http.Request, res http.ResponseWriter) {
		reregisterFrameworkFn := func() ([]byte, int, error) {
			upid, data, statusCode, err := mesos_api_helpers.ProcessMesosHttpRequest(req)
			if err != nil {
				return empty, statusCode, lxerrors.New("parsing reregisterFramework request", err)
			}
			var reregisterRequest mesosproto.ReregisterFrameworkMessage
			err = proto.Unmarshal(data, &reregisterRequest)
			if err != nil {
				return empty, 500, lxerrors.New("could not unmarshal data to reregisterRequest", err)
			}
			err = mesos_api_helpers.HandleRegisterRequest(wrapper.tpi, wrapper.frameworkManager, upid, reregisterRequest.GetFramework())
			if err != nil {
				lxlog.Errorf(logrus.Fields{
					"error": err,
				}, "could not handle reregister framework request")
				return empty, 500, lxerrors.New("could not handle reregister framework request", err)
			}
			return empty, 202, nil
		}
		_, statusCode, err := wrapper.queueOperation(reregisterFrameworkFn)
		if err != nil {
			res.WriteHeader(statusCode)
			lxlog.Errorf(logrus.Fields{
				"error": err.Error(),
				"request_sent_by": masterUpidString,
			}, "processing register framework message")
			driverErrc <- err
			return
		}
		res.WriteHeader(statusCode)
	}

	m.Get(GET_MASTER_STATE, getMasterStateHandler)
	m.Get(GET_MASTER_STATE_DEPRECATED, getMasterStateHandler)
	m.Post(MESOS_SCHEDULER_CALL, mesosSchedulerCallHandler)
	m.Post(REGISTER_FRAMEWORK_MESSAGE, registerFrameworkMessageHandler)
	m.Post(REREGISTER_FRAMEWORK_MESSAGE, reregisterFrameworkMessageHandler)
	return m
}

func (wrapper *mesosApiServerWrapper) queueOperation(f func() ([]byte, int, error)) ([]byte, int, error) {
	datac := make(chan []byte)
	statusCodec := make(chan int)
	errc := make(chan error)
	wrapper.actionQueue.Push(
		func() {
			data, statusCode, err := f()
			datac <- data
			statusCodec <- statusCode
			errc <- err
		})
	return <-datac, <-statusCodec, <-errc
}

func (wrapper *mesosApiServerWrapper) processMesosCall(data []byte, upid *mesos_data.UPID) error {
	var call mesosproto.Call
	err := proto.Unmarshal(data, &call)
	if err != nil {
		return lxerrors.New("could not parse data to protobuf msg Call", err)
	}
	callType := call.GetType()
	lxlog.Debugf(logrus.Fields{
		"call_type":     callType.String(),
		"framework_pid": upid.String(),
		"whole call":    call.String(),
	}, "Received mesosproto.Call")

	switch callType {
	case mesosproto.Call_SUBSCRIBE:
		subscribe := call.Subscribe
		err = mesos_api_helpers.HandleRegisterRequest(wrapper.tpi, wrapper.frameworkManager, upid, subscribe.GetFrameworkInfo())
		if err != nil {
			return lxerrors.New("processing subscribe request", err)
		}
		break
	default:
		return lxerrors.New("processing unknown call type: " + callType.String(), nil)
	}

	return nil
}
<commit_msg>change one line spacing because ocd<commit_after>package mesos_master_api
import (
	"github.com/layer-x/layerx-commons/lxlog"
	"github.com/Sirupsen/logrus"
	"net/http"
	"github.com/layer-x/layerx-mesos-tpi_v2/mesos_master_api/mesos_api_helpers"
	"github.com/layer-x/layerx-commons/lxerrors"
	"github.com/layer-x/layerx-commons/lxactionqueue"
	"github.com/layer-x/layerx-mesos-tpi_v2/mesos_master_api/mesos_data"
	"github.com/layer-x/layerx-mesos-tpi_v2/framework_manager"
	"github.com/mesos/mesos-go/mesosproto"
	"github.com/gogo/protobuf/proto"
	"github.com/layer-x/layerx-core_v2/layerx_tpi"
	"github.com/go-martini/martini"
)

const (
	GET_MASTER_STATE = "/master/state.json"
	GET_MASTER_STATE_DEPRECATED = "/state.json"
	MESOS_SCHEDULER_CALL = "/master/mesos.scheduler.Call"
	REGISTER_FRAMEWORK_MESSAGE = "/master/mesos.internal.RegisterFrameworkMessage"
	REREGISTER_FRAMEWORK_MESSAGE = "/master/mesos.internal.ReregisterFrameworkMessage"
	UNREGISTER_FRAMEWORK_MESSAGE = "/master/mesos.internal.UnregisterFrameworkMessage"
	LAUNCH_TASKS_MESSAGE = "/master/mesos.internal.LaunchTasksMessage"
	RECONCILE_TASKS_MESSAGE = "/master/mesos.internal.ReconcileTasksMessage"
	KILL_TASK_MESSAGE = "/master/mesos.internal.KillTaskMessage"
	STATUS_UPDATE_ACKNOWLEDGEMENT_MESSAGE = "/master/mesos.internal.StatusUpdateAcknowledgementMessage"
	REVIVE_OFFERS_MESSAGE = "/master/mesos.internal.ReviveOffersMessage"
)

var empty = []byte{}

type mesosApiServerWrapper struct {
	actionQueue      lxactionqueue.ActionQueue
	frameworkManager framework_manager.FrameworkManager
	tpi              *layerx_tpi.LayerXTpi
}

func NewMesosApiServerWrapper(tpi *layerx_tpi.LayerXTpi, actionQueue lxactionqueue.ActionQueue, frameworkManager framework_manager.FrameworkManager) *mesosApiServerWrapper {
	return &mesosApiServerWrapper{
		actionQueue: actionQueue,
		frameworkManager: frameworkManager,
		tpi: tpi,
	}
}

func (wrapper *mesosApiServerWrapper) WrapWithMesos(m *martini.ClassicMartini, masterUpidString string, driverErrc chan error) *martini.ClassicMartini {
	getMasterStateHandler := func(res http.ResponseWriter) {
		getStateFn := func() ([]byte, int, error) {
			data, err := mesos_api_helpers.GetMesosState(masterUpidString)
			if err != nil {
				return empty, 500, lxerrors.New("retreiving master state", err)
			}
			return data, 200, nil
		}
		data, statusCode, err := wrapper.queueOperation(getStateFn)
		if err != nil {
			res.WriteHeader(statusCode)
			lxlog.Errorf(logrus.Fields{
				"request_sent_by": masterUpidString,
			}, "Retreiving master state")
			driverErrc <- err
			return
		}
		res.Write(data)
	}
	mesosSchedulerCallHandler := func(req *http.Request, res http.ResponseWriter) {
		processMesosCallFn := func() ([]byte, int, error) {
			upid, data, statusCode, err := mesos_api_helpers.ProcessMesosHttpRequest(req)
			if err != nil {
				return empty, statusCode, lxerrors.New("parsing reregisterFramework request", err)
			}
			err = wrapper.processMesosCall(data, upid)
			if err != nil {
				lxlog.Errorf(logrus.Fields{
					"error": err,
				}, "could not read process scheduler call request")
				return empty, 500, lxerrors.New("could not read process scheduler call request", err)
			}
			return empty, 202, nil
		}
		_, statusCode, err := wrapper.queueOperation(processMesosCallFn)
		if err != nil {
			res.WriteHeader(statusCode)
			lxlog.Errorf(logrus.Fields{
				"error": err.Error(),
				"request_sent_by": masterUpidString,
			}, "processing mesos call message")
			driverErrc <- err
			return
		}
		res.WriteHeader(statusCode)
	}
	registerFrameworkMessageHandler := func(req *http.Request, res http.ResponseWriter) {
		registerFrameworkFn := func() ([]byte, int, error) {
			upid, data, statusCode, err := mesos_api_helpers.ProcessMesosHttpRequest(req)
			if err != nil {
				return empty, statusCode, lxerrors.New("parsing registerFramework request", err)
			}
			var registerRequest mesosproto.RegisterFrameworkMessage
			err = proto.Unmarshal(data, &registerRequest)
			if err != nil {
				return empty, 500, lxerrors.New("could not parse data to protobuf msg Call", err)
			}
			err = mesos_api_helpers.HandleRegisterRequest(wrapper.tpi, wrapper.frameworkManager, upid, registerRequest.GetFramework())
			if err != nil {
				lxlog.Errorf(logrus.Fields{
					"error": err,
				}, "could not handle register framework request")
				return empty, 500, lxerrors.New("could not handle register framework request", err)
			}
			return empty, 202, nil
		}
		_, statusCode, err := wrapper.queueOperation(registerFrameworkFn)
		if err != nil {
			res.WriteHeader(statusCode)
			lxlog.Errorf(logrus.Fields{
				"error": err.Error(),
				"request_sent_by": masterUpidString,
			}, "processing register framework message")
			driverErrc <- err
			return
		}
		res.WriteHeader(statusCode)
	}
	reregisterFrameworkMessageHandler := func(req *http.Request, res http.ResponseWriter) {
		reregisterFrameworkFn := func() ([]byte, int, error) {
			upid, data, statusCode, err := mesos_api_helpers.ProcessMesosHttpRequest(req)
			if err != nil {
				return empty, statusCode, lxerrors.New("parsing reregisterFramework request", err)
			}
			var reregisterRequest mesosproto.ReregisterFrameworkMessage
			err = proto.Unmarshal(data, &reregisterRequest)
			if err != nil {
				return empty, 500, lxerrors.New("could not unmarshal data to reregisterRequest", err)
			}
			err = mesos_api_helpers.HandleRegisterRequest(wrapper.tpi, wrapper.frameworkManager, upid, reregisterRequest.GetFramework())
			if err != nil {
				lxlog.Errorf(logrus.Fields{
					"error": err,
				}, "could not handle reregister framework request")
				return empty, 500, lxerrors.New("could not handle reregister framework request", err)
			}
			return empty, 202, nil
		}
		_, statusCode, err := wrapper.queueOperation(reregisterFrameworkFn)
		if err != nil {
			res.WriteHeader(statusCode)
			lxlog.Errorf(logrus.Fields{
				"error": err.Error(),
				"request_sent_by": masterUpidString,
			}, "processing reregister framework message")
			driverErrc <- err
			return
		}
		res.WriteHeader(statusCode)
	}

	m.Get(GET_MASTER_STATE, getMasterStateHandler)
	m.Get(GET_MASTER_STATE_DEPRECATED, getMasterStateHandler)
	m.Post(MESOS_SCHEDULER_CALL, mesosSchedulerCallHandler)
	m.Post(REGISTER_FRAMEWORK_MESSAGE, registerFrameworkMessageHandler)
	m.Post(REREGISTER_FRAMEWORK_MESSAGE, reregisterFrameworkMessageHandler)
	return m
}

func (wrapper *mesosApiServerWrapper) queueOperation(f func() ([]byte, int, error)) ([]byte, int, error) {
	datac := make(chan []byte)
	statusCodec := make(chan int)
	errc := make(chan error)
	wrapper.actionQueue.Push(
		func() {
			data, statusCode, err := f()
			datac <- data
			statusCodec <- statusCode
			errc <- err
		})
	return <-datac, <-statusCodec, <-errc
}

func (wrapper *mesosApiServerWrapper) processMesosCall(data []byte, upid *mesos_data.UPID) error {
	var call mesosproto.Call
	err := proto.Unmarshal(data, &call)
	if err != nil {
		return lxerrors.New("could not parse data to protobuf msg Call", err)
	}
	callType := call.GetType()
	lxlog.Debugf(logrus.Fields{
		"call_type":     callType.String(),
		"framework_pid": upid.String(),
		"whole call":    call.String(),
	}, "Received mesosproto.Call")

	switch callType {
	case mesosproto.Call_SUBSCRIBE:
		subscribe := call.Subscribe
		err = mesos_api_helpers.HandleRegisterRequest(wrapper.tpi, wrapper.frameworkManager, upid, subscribe.GetFrameworkInfo())
		if err != nil {
			return lxerrors.New("processing subscribe request", err)
		}
		break
	default:
		return lxerrors.New("processing unknown call type: " + callType.String(), nil)
	}

	return nil
}
<|endoftext|>


<commit_before>package storage

import (
    "encoding/json"
    "fmt"
    "github.com/influxdata/influxdb/client/v2"
    "log"
)

const (
    database = "_internal"
)

func InfluxDBClient(consumerId string) client.Client {
    c, err := client.NewHTTPClient(client.HTTPConfig{
        Addr:     "http://" + consumerId + "-i-influxdb.default:8086",
    })
    if err != nil {
        log.Fatalln("Error: ", err)
    }
    return c
}

func GetStorageUsed(c client.Client) int64 {
    q := client.Query{
        Command: fmt.Sprintf("select sum(diskBytes) FROM tsm1_filestore WHERE time > now() - 19s"),
        Database: database,
    }
    resp, err := c.Query(q)
    if err != nil {
        log.Fatalln("Error:", err)
    }
    if resp.Error() != nil {
        log.Fatalln("Error:", resp.Error())
    }

    res, err := resp.Results[0].Series[0].Values[0][1].(json.Number).Int64()
    if err != nil {
        log.Fatalln("Error: ", err)
    }
    return res
}

//func main() {
//    consumerId := "test1"
//    c := InfluxDBClient(consumerId)
//    log.Printf("Mean values: diskBytes='%d'", GetStorageUsed(c))
//}
<commit_msg>remove port number<commit_after>package storage

import (
    "encoding/json"
    "fmt"
    "github.com/influxdata/influxdb/client/v2"
    "log"
)

const (
    database = "_internal"
)

func InfluxDBClient(consumerId string) client.Client {
    c, err := client.NewHTTPClient(client.HTTPConfig{
        Addr:     "http://" + consumerId + "-i-influxdb.default",
    })
    if err != nil {
        log.Fatalln("Error: ", err)
    }
    return c
}

func GetStorageUsed(c client.Client) int64 {
    q := client.Query{
        Command: fmt.Sprintf("select sum(diskBytes) FROM tsm1_filestore WHERE time > now() - 19s"),
        Database: database,
    }
    resp, err := c.Query(q)
    if err != nil {
        log.Fatalln("Error:", err)
    }
    if resp.Error() != nil {
        log.Fatalln("Error:", resp.Error())
    }

    res, err := resp.Results[0].Series[0].Values[0][1].(json.Number).Int64()
    if err != nil {
        log.Fatalln("Error: ", err)
    }
    return res
}

//func main() {
//    consumerId := "test1"
//    c := InfluxDBClient(consumerId)
//    log.Printf("Mean values: diskBytes='%d'", GetStorageUsed(c))
//}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/ChristopherRabotin/smd"
)

const (
	debug = false
)

/*
 * This example shows how to find the greatest heliocentric velocity at the end of a spiral by iterating on the initial
 * true anomaly.
 */

func sc() *smd.Spacecraft {
	eps := smd.NewUnlimitedEPS()
	thrusters := []smd.EPThruster{smd.NewGenericEP(5, 5000)} // VASIMR (approx.)
	dryMass := 10000.0
	fuelMass := 5000.0
	return smd.NewSpacecraft("Spiral", dryMass, fuelMass, eps, thrusters, false, []*smd.Cargo{},
		[]smd.Waypoint{smd.NewToHyperbolic(nil)})
}

func initEarthOrbit(ω, ν float64) *smd.Orbit {
	a, e := smd.Radii2ae(39300+smd.Earth.Radius, 290+smd.Earth.Radius)
	i := 28.0
	//ω := 10.0
	Ω := 5.0
	return smd.NewOrbitFromOE(a, e, i, Ω, ω, ν, smd.Earth)
}

// initMarsOrbit returns the initial orbit.
func initMarsOrbit(i, Ω, ω, ν float64) *smd.Orbit {
	// Exomars TGO.
	a, e := smd.Radii2ae(44500+smd.Mars.Radius, 426+smd.Mars.Radius)
	//i := 1.0
	//ω := 1.0
	//Ω := 1.0
	//ν := 15.0
	return smd.NewOrbitFromOE(a, e, i, Ω, ω, ν, smd.Mars)
}

func main() {
	//name := "spiral-mars"
	depart := time.Date(2018, 11, 8, 0, 0, 0, 0, time.UTC)
	chgframePath := "../../cmd/refframes/chgframe.py"
	maxV := -1e3
	minV := +1e3
	var maxOrbit smd.Orbit
	var minOrbit smd.Orbit
	tsv := "%i (degrees), raan (degrees), arg peri (degrees),nu (degrees),V(km/s)\n"
	stepSize := 30.
	for i := 0.0; i < 360; i += stepSize {
		for Ω := 0.0; Ω < 360; Ω += stepSize {
			for ω := 0.0; ω < 360; ω += stepSize {
				for ν := 0.0; ν < 360; ν += stepSize {
					initOrbit := initMarsOrbit(i, Ω, ω, ν)
					astro := smd.NewMission(sc(), initOrbit, depart, depart.Add(-1), smd.Cartesian, smd.Perturbations{}, smd.ExportConfig{})
					astro.Propagate()

					// Run chgframe
					// We're now done so let's convert the position and velocity to heliocentric and check the output.
					R, V := initOrbit.RV()
					state := fmt.Sprintf("[%f,%f,%f,%f,%f,%f]", R[0], R[1], R[2], V[0], V[1], V[2])
					if debug {
						fmt.Printf("\n=== RUNNING CMD ===\npython %s -t J2000 -f IAU_Earth -e \"%s\" -s \"%s\"\n", chgframePath, astro.CurrentDT.Format(time.ANSIC), state)
					}
					cmd := exec.Command("python", chgframePath, "-t", "J2000", "-f", "IAU_Mars", "-e", astro.CurrentDT.Format(time.ANSIC), "-s", state)
					cmdOut, err := cmd.Output()
					if err != nil {
						fmt.Fprintln(os.Stderr, "Error converting orbit to helio ", err)
						os.Exit(1)
					}
					out := string(cmdOut)

					// Process output
					newState := strings.TrimSpace(string(out))
					// Cf. https://play.golang.org/p/g-a4idjhIb
					newState = newState[1 : len(newState)-1]
					components := strings.Split(newState, ",")
					var nR = make([]float64, 3)
					var nV = make([]float64, 3)
					for i := 0; i < 6; i++ {
						fl, err := strconv.ParseFloat(strings.TrimSpace(components[i]), 64)
						if err != nil {
							panic(err)
						}
						if i < 3 {
							nR[i] = fl
						} else {
							nV[i-3] = fl
						}
					}
					vNorm := math.Sqrt(math.Pow(nV[0], 2) + math.Pow(nV[1], 2) + math.Pow(nV[2], 2))
					// Add to TSV file
					tsv += fmt.Sprintf("%f,%f,%f,%f,%f\n", i, Ω, ω, ν, vNorm)
					if vNorm > maxV {
						maxV = vNorm
						maxOrbit = *initMarsOrbit(i, Ω, ω, ν)
					} else if vNorm < minV {
						minV = vNorm
						minOrbit = *initMarsOrbit(i, Ω, ω, ν)
					}
					if debug {
						fmt.Printf("\nν=%f\t=>V=%+v\t|V|=%f\n", ν, nV, vNorm)
					}
				}
			}
			fmt.Printf("\n\n=== RESULT ===\n\nmaxV=%.3f km/s\t%s\nminV=%.3f km/s\t%s\n\n", maxV, maxOrbit, minV, minOrbit)
			// Write CSV file.
			f, err := os.Create("./results.csv")
			if err != nil {
				panic(err)
			}
			defer f.Close()
			if _, err := f.WriteString(tsv); err != nil {
				panic(err)
			}
		}
	}
}
func init() {
	runtime.GOMAXPROCS(3)
}
<commit_msg>First cloud deployment<commit_after>package main

import (
	"fmt"
	"math"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/ChristopherRabotin/smd"
)

const (
	debug = false
)

/*
 * This example shows how to find the greatest heliocentric velocity at the end of a spiral by iterating on the initial
 * true anomaly.
 */

func sc() *smd.Spacecraft {
	eps := smd.NewUnlimitedEPS()
	thrusters := []smd.EPThruster{smd.NewGenericEP(5, 5000)} // VASIMR (approx.)
	dryMass := 10000.0
	fuelMass := 5000.0
	return smd.NewSpacecraft("Spiral", dryMass, fuelMass, eps, thrusters, false, []*smd.Cargo{},
		[]smd.Waypoint{smd.NewToHyperbolic(nil)})
}

func initEarthOrbit(ω, ν float64) *smd.Orbit {
	a, e := smd.Radii2ae(39300+smd.Earth.Radius, 290+smd.Earth.Radius)
	i := 28.0
	//ω := 10.0
	Ω := 5.0
	return smd.NewOrbitFromOE(a, e, i, Ω, ω, ν, smd.Earth)
}

// initMarsOrbit returns the initial orbit.
func initMarsOrbit(i, Ω, ω, ν float64) *smd.Orbit {
	// Exomars TGO.
	a, e := smd.Radii2ae(44500+smd.Mars.Radius, 426+smd.Mars.Radius)
	//i := 1.0
	//ω := 1.0
	//Ω := 1.0
	//ν := 15.0
	return smd.NewOrbitFromOE(a, e, i, Ω, ω, ν, smd.Mars)
}

func main() {
	//name := "spiral-mars"
	depart := time.Date(2018, 11, 8, 0, 0, 0, 0, time.UTC)
	chgframePath := "../../cmd/refframes/chgframe.py"
	maxV := -1e3
	minV := +1e3
	var maxOrbit smd.Orbit
	var minOrbit smd.Orbit
	a, e, _, _, _, _, _, _, _ := initMarsOrbit(10, 10, 10, 10).Elements()
	tsv := fmt.Sprintf("#a=%f km\te=%f\n#V(km/s), i (degrees), raan (degrees), arg peri (degrees),nu (degrees)\n", a, e)
	stepSize := 5.
	for i := 1.0; i < 90; i += stepSize {
		for Ω := 0.0; Ω < 360; Ω += stepSize {
			for ω := 0.0; ω < 360; ω += stepSize {
				for ν := 0.0; ν < 360; ν += stepSize {
					initOrbit := initMarsOrbit(i, Ω, ω, ν)
					astro := smd.NewMission(sc(), initOrbit, depart, depart.Add(-1), smd.Cartesian, smd.Perturbations{}, smd.ExportConfig{})
					astro.Propagate()

					// Run chgframe
					// We're now done so let's convert the position and velocity to heliocentric and check the output.
					R, V := initOrbit.RV()
					state := fmt.Sprintf("[%f,%f,%f,%f,%f,%f]", R[0], R[1], R[2], V[0], V[1], V[2])
					if debug {
						fmt.Printf("\n=== RUNNING CMD ===\npython %s -t J2000 -f IAU_Earth -e \"%s\" -s \"%s\"\n", chgframePath, astro.CurrentDT.Format(time.ANSIC), state)
					}
					cmd := exec.Command("python", chgframePath, "-t", "J2000", "-f", "IAU_Mars", "-e", astro.CurrentDT.Format(time.ANSIC), "-s", state)
					cmdOut, err := cmd.Output()
					if err != nil {
						fmt.Fprintln(os.Stderr, "Error converting orbit to helio ", err)
						os.Exit(1)
					}
					out := string(cmdOut)

					// Process output
					newState := strings.TrimSpace(string(out))
					// Cf. https://play.golang.org/p/g-a4idjhIb
					newState = newState[1 : len(newState)-1]
					components := strings.Split(newState, ",")
					var nR = make([]float64, 3)
					var nV = make([]float64, 3)
					for i := 0; i < 6; i++ {
						fl, err := strconv.ParseFloat(strings.TrimSpace(components[i]), 64)
						if err != nil {
							panic(err)
						}
						if i < 3 {
							nR[i] = fl
						} else {
							nV[i-3] = fl
						}
					}
					vNorm := math.Sqrt(math.Pow(nV[0], 2) + math.Pow(nV[1], 2) + math.Pow(nV[2], 2))
					// Add to TSV file
					tsv += fmt.Sprintf("%f,%f,%f,%f,%f\n", vNorm, i, Ω, ω, ν)
					if vNorm > maxV {
						maxV = vNorm
						maxOrbit = *initMarsOrbit(i, Ω, ω, ν)
					} else if vNorm < minV {
						minV = vNorm
						minOrbit = *initMarsOrbit(i, Ω, ω, ν)
					}
					if debug {
						fmt.Printf("\nν=%f\t=>V=%+v\t|V|=%f\n", ν, nV, vNorm)
					}
				}
			}
		}
	}
	fmt.Printf("\n\n=== RESULT ===\n\nmaxV=%.3f km/s\t%s\nminV=%.3f km/s\t%s\n\n", maxV, maxOrbit, minV, minOrbit)
	// Write CSV file.
	f, err := os.Create(fmt.Sprintf("./results-.csv"))
	if err != nil {
		panic(err)
	}
	defer f.Close()
	if _, err := f.WriteString(tsv); err != nil {
		panic(err)
	}
}
func init() {
	runtime.GOMAXPROCS(3)
}
<|endoftext|>


<commit_before>package config

import (
	"github.com/kelseyhightower/envconfig"
)

// S3 is the envconfig compatible struct to configure S3 access
type S3 struct {
	Endpoint string `envconfig:"AWS_ENDPOINT" default:"s3.amazonaws.com"`
	Bucket   string `envconfig:"AWS_BUCKET" default:"goprox"`
	Key      string `envconfig:"AWS_KEY"`
	Secret   string `envconfig:"AWS_SECRET"`
}

// GetS3 gets the S3 config using envconfig
func GetS3(appName string) (*S3, error) {
	conf := new(S3)
	if err := envconfig.Process(appName, conf); err != nil {
		return nil, err
	}
	return conf, nil
}
<commit_msg>making key and secret required<commit_after>package config

import (
	"github.com/kelseyhightower/envconfig"
)

// S3 is the envconfig compatible struct to configure S3 access
type S3 struct {
	Endpoint string `envconfig:"AWS_ENDPOINT" default:"s3.amazonaws.com"`
	Bucket   string `envconfig:"AWS_BUCKET" default:"goprox"`
	Key      string `envconfig:"AWS_KEY" required:"true"`
	Secret   string `envconfig:"AWS_SECRET" required:"true"`
}

// GetS3 gets the S3 config using envconfig
func GetS3(appName string) (*S3, error) {
	conf := new(S3)
	if err := envconfig.Process(appName, conf); err != nil {
		return nil, err
	}
	return conf, nil
}
<|endoftext|>


<commit_before>package strtool

import (
	"strings"
)

func TrimRightSpace(s string) string {
	return strings.TrimRight(string(s), "\r\n\t ")
}

<commit_msg>add strtool.Md5<commit_after>package strtool

import (
	"crypto/md5"
	"fmt"
	"strings"
)

func TrimRightSpace(s string) string {
	return strings.TrimRight(string(s), "\r\n\t ")
}

func Md5(s string) string {
	h := md5.New()
	h.Write([]byte(s))
	return fmt.Sprintf("%x", h.Sum(nil))
}
<|endoftext|>


<commit_before>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package configure provides a very simple gnu configure/make style configure
// script generating a simple Makefile and go file containing all the configured
// variables.
package configure

import (
	"bytes"
	"fmt"
	"github.com/jessevdk/go-flags"
	"io"
	"os"
	"path"
	"reflect"
	"regexp"
	"sort"
	"strings"
)

// Options contains all the standard configure options to specify various
// directories. Use NewOptions to create an instance of this type with the
// common default values for each variable.
type Options struct {
	Prefix        string `long:"prefix" description:"install architecture-independent files in PREFIX"`
	ExecPrefix    string `long:"execprefix" description:"install architecture-dependent files in EPREFIX"`
	BinDir        string `long:"bindir" description:"user executables"`
	LibExecDir    string `long:"libexecdir" description:"program executables"`
	SysConfDir    string `long:"sysconfdir" description:"read-only single-machine data"`
	LibDir        string `long:"libdir" description:"program executables"`
	DataRootDir   string `long:"datarootdir" description:"read-only arch.-independent data root"`
	DataDir       string `long:"datadir" description:"read-only arc.-independent data"`
	ManDir        string `long:"mandir" description:"man documentation"`
}

// NewOptions creates a new Options with common default values.
func NewOptions() *Options {
	return &Options{
		Prefix:        "/usr/local",
		ExecPrefix:    "${prefix}",
		BinDir:        "${execprefix}/bin",
		LibExecDir:    "${execprefix}/libexec",
		LibDir:        "${execprefix}/lib",
		SysConfDir:    "${prefix}/etc",
		DataRootDir:   "${prefix}/share",
		DataDir:       "${datarootdir}",
		ManDir:        "${datarootdir}/man",
	}
}

// Package is the package name in which the GoConfig file will be written
var Package = "main"

// Makefile is the filename of the makefile that will be generated
var Makefile = "go.make"

// GoConfig is the filename of the go file that will be generated containing
// all the variable values.
var GoConfig = "appconfig"

// GoConfigVariable is the name of the variable inside the GoConfig file
// containing all the variable values.
var GoConfigVariable = "AppConfig"

// Target is the executable name to build. If left empty, the name is deduced
// from the directory (similar to what go does)
var Target = ""

// Version is the application version
var Version []int = []int{0, 1}

type expandStringPart struct {
	Value      string
	IsVariable bool
}

func (x *expandStringPart) expand(m map[string]*expandString) (string, []string) {
	if x.IsVariable {
		s, ok := m[x.Value]

		if !ok {
			return "", nil
		} else {
			ret := s.expand(m)
			rets := make([]string, len(s.dependencies), len(s.dependencies)+1)

			copy(rets, s.dependencies)

			return ret, append(rets, x.Value)
		}
	}

	return x.Value, nil
}

type expandString struct {
	Name  string
	Parts []expandStringPart

	dependencies []string
	value        string
	hasExpanded  bool
}

func (x *expandString) dependsOn(name string) bool {
	i := sort.SearchStrings(x.dependencies, name)

	return i < len(x.dependencies) && x.dependencies[i] == name
}

func (x *expandString) expand(m map[string]*expandString) string {
	if !x.hasExpanded {
		// Prevent infinite loop by circular dependencies
		x.hasExpanded = true
		buf := bytes.Buffer{}

		for _, v := range x.Parts {
			s, deps := v.expand(m)
			buf.WriteString(s)

			x.dependencies = append(x.dependencies, deps...)
		}

		sort.Strings(x.dependencies)
		x.value = buf.String()
	}

	return x.value
}

// Config represents the current configuration. See Configure for more
// information.
type Config struct {
	*flags.Parser

	values   map[string]interface{}
	expanded map[string]*expandString
}

func (x *Config) extract() map[string]interface{} {
	ret := make(map[string]interface{})

	for _, grp := range x.Parser.Groups {
		for longname, option := range grp.LongNames {
			ret[longname] = option.Value.Interface()
		}
	}

	return ret
}

func (x *Config) expand() map[string]*expandString {
	ret := make(map[string]*expandString)

	r, _ := regexp.Compile(`\$\{[^}]*\}`)

	for name, val := range x.values {
		es := expandString{
			Name: name,
		}

		// Find all variable references
		s := fmt.Sprintf("%v", val)

		matches := r.FindAllStringIndex(s, -1)

		for i, match := range matches {
			var prefix string

			if i == 0 {
				prefix = s[0:match[0]]
			} else {
				prefix = s[matches[i-1][1]:match[0]]
			}

			if len(prefix) != 0 {
				es.Parts = append(es.Parts, expandStringPart{Value: prefix, IsVariable: false})
			}

			varname := s[match[0]+2 : match[1]-1]
			es.Parts = append(es.Parts, expandStringPart{Value: varname, IsVariable: true})
		}

		if len(matches) == 0 {
			es.Parts = append(es.Parts, expandStringPart{Value: s, IsVariable: false})
		} else {
			last := matches[len(matches)-1]
			suffix := s[last[1]:]

			if len(suffix) != 0 {
				es.Parts = append(es.Parts, expandStringPart{Value: suffix, IsVariable: false})
			}
		}

		ret[name] = &es
	}

	for _, val := range ret {
		val.expand(ret)
	}

	return ret
}

// Configure runs the configure process with options as provided by the given
// data variable. If data is nil, the default options will be used
// (see NewOptions). Note that the data provided is simply passed to go-flags.
// For more information on flags parsing, see the documentation of go-flags.
// If GoConfig is not empty, then the go configuration will be written to the
// GoConfig file. Similarly, if Makefile is not empty, the Makefile will be
// written.
func Configure(data interface{}) (*Config, error) {
	if data == nil {
		data = NewOptions()
	}

	parser := flags.NewParser(data, flags.PrintErrors)

	if _, err := parser.Parse(); err != nil {
		return nil, err
	}

	ret := &Config{
		Parser: parser,
	}

	ret.values = ret.extract()
	ret.expanded = ret.expand()

	if len(GoConfig) != 0 {
		filename := GoConfig

		if !strings.HasSuffix(filename, ".go") {
			filename += ".go"
		}

		f, err := os.Create(filename)

		if err != nil {
			return nil, err
		}

		ret.WriteGoConfig(f)
		f.Close()
	}

	if len(Makefile) != 0 {
		f, err := os.Create(Makefile)

		if err != nil {
			return nil, err
		}

		ret.WriteMakefile(f)
		f.Close()

		os.Chmod(Makefile, 0755)

		f, err = os.OpenFile(path.Join(path.Dir(Makefile), "Makefile"),
		                     os.O_CREATE | os.O_EXCL | os.O_WRONLY,
		                     0644)

		if err == nil {
			fmt.Fprintf(f, "include %s\n", path.Base(Makefile))
			f.Close()
		}
	}

	return ret, nil
}

// Expand expands the variable value indicated by name
func (x *Config) Expand(name string) string {
	return x.expanded[name].expand(x.expanded)
}

// WriteGoConfig writes the go configuration file containing all the variable
// values to the given writer. Note that it will write a package line if
// the Package variable is not empty. The GoConfigVariable name will
// be used as the variable name for the configuration.
func (x *Config) WriteGoConfig(writer io.Writer) {
	if len(Package) > 0 {
		fmt.Fprintf(writer, "package %v\n\n", Package)
	}

	fmt.Fprintf(writer, "var %s = struct {\n", GoConfigVariable)
	values := make([]string, 0)

	variables := make([]string, 0, len(x.values))
	optionmap := make(map[string]*flags.Option)

	// Write all options
	for _, grp := range x.Parser.Groups {
		for _, option := range grp.LongNames {
			name := option.Field.Name

			variables = append(variables, name)
			optionmap[name] = option
		}
	}

	sort.Strings(variables)

	for i, name := range variables {
		if i != 0 {
			io.WriteString(writer, "\n")
		}

		option := optionmap[name]
		val := option.Value.Interface()

		fmt.Fprintf(writer, "\t// %s\n", option.Description)
		fmt.Fprintf(writer, "\t%v %T\n", name, val)

		var value string

		if option.Value.Type().Kind() == reflect.String {
			value = fmt.Sprintf("%#v", x.Expand(option.LongName))
		} else {
			value = fmt.Sprintf("%#v", val)
		}

		values = append(values, value)
	}

	if len(variables) > 0 {
		io.WriteString(writer, "\n")
	}

	io.WriteString(writer, "\t// Application version\n")
	io.WriteString(writer, "\tVersion []int\n")
	fmt.Fprintln(writer, "}{")

	for _, v := range values {
		fmt.Fprintf(writer, "\t%v,\n", v)
	}

	for i, v := range Version {
		if i != 0 {
			io.WriteString(writer, ", ")
		} else {
			io.WriteString(writer, "\t[]int{")
		}

		fmt.Fprintf(writer, "%v", v)
	}

	fmt.Fprintln(writer, "},")
	fmt.Fprintln(writer, "}")
}

// WriteMakefile writes a Makefile for the given parser to the given writer.
// The Makefile contains the common build, clean, distclean, install and
// uninstall rules.
func (x *Config) WriteMakefile(writer io.Writer) {
	// Write a very basic makefile
	io.WriteString(writer, "#!/usr/bin/make -f\n\n")

	vars := make([]*expandString, 0, len(x.expanded))

	for name, v := range x.expanded {
		inserted := false

		// Insert into vars based on dependencies
		for i, vv := range vars {
			if vv.dependsOn(name) {
				tail := vars[i:]

				if i == 0 {
					vars = append([]*expandString{v}, vars...)
				} else {
					vars = append(append(vars[0:i-1], v), tail...)
				}

				inserted = true
				break
			}
		}

		if !inserted {
			vars = append(vars, v)
		}
	}

	if len(vars) > 0 {
		io.WriteString(writer, "# Variables\n")

		for _, v := range vars {
			fmt.Fprintf(writer, "%s = ", v.Name)

			for _, part := range v.Parts {
				if part.IsVariable {
					fmt.Fprintf(writer, "$(%s)", part.Value)
				} else {
					fmt.Fprintf(writer, "%s", part.Value)
				}
			}

			io.WriteString(writer, "\n")
		}

		io.WriteString(writer, "\n")
	}

	target := Target

	if len(target) == 0 {
		arg := os.Args[0]
		var rpath string

		if path.IsAbs(arg) {
			rpath = arg
		} else {
			wd, _ := os.Getwd()
			rpath = path.Clean(path.Join(wd, os.Args[0]))
		}

		target = path.Base(path.Dir(rpath))
	}

	fmt.Fprintf(writer, "TARGET = %s\n", target)
	fmt.Fprintf(writer, "\nSOURCES = $(wildcard *.go)\n\n")

	io.WriteString(writer, "# Rules\n")
	io.WriteString(writer, "$(TARGET): $(SOURCES)\n")
	io.WriteString(writer, "\tgo build -o $(TARGET) $(SOURCES)\n\n")

	io.WriteString(writer, "clean:\n")
	io.WriteString(writer, "\trm -f $(TARGET)\n\n")

	io.WriteString(writer, "distclean: clean\n\n")

	io.WriteString(writer, "install: $(TARGET)\n")
	io.WriteString(writer, "\tmkdir -p $(DESTDIR)$(bindir) && cp $(TARGET) $(DESTDIR)$(bindir)/$(TARGET)\n\n")

	io.WriteString(writer, "uninstall:\n")
	io.WriteString(writer, "\trm -f $(DESTDIR)$(bindir)/$(TARGET)\n\n")

	io.WriteString(writer, ".PHONY: install uninstall distclean clean")
}
<commit_msg>Extract target name from runtime source information<commit_after>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package configure provides a very simple gnu configure/make style configure
// script generating a simple Makefile and go file containing all the configured
// variables.
package configure

import (
	"bytes"
	"fmt"
	"github.com/jessevdk/go-flags"
	"io"
	"os"
	"path"
	"reflect"
	"regexp"
	"sort"
	"strings"
	"runtime"
)

// Options contains all the standard configure options to specify various
// directories. Use NewOptions to create an instance of this type with the
// common default values for each variable.
type Options struct {
	Prefix        string `long:"prefix" description:"install architecture-independent files in PREFIX"`
	ExecPrefix    string `long:"execprefix" description:"install architecture-dependent files in EPREFIX"`
	BinDir        string `long:"bindir" description:"user executables"`
	LibExecDir    string `long:"libexecdir" description:"program executables"`
	SysConfDir    string `long:"sysconfdir" description:"read-only single-machine data"`
	LibDir        string `long:"libdir" description:"program executables"`
	DataRootDir   string `long:"datarootdir" description:"read-only arch.-independent data root"`
	DataDir       string `long:"datadir" description:"read-only arc.-independent data"`
	ManDir        string `long:"mandir" description:"man documentation"`
}

// NewOptions creates a new Options with common default values.
func NewOptions() *Options {
	return &Options{
		Prefix:        "/usr/local",
		ExecPrefix:    "${prefix}",
		BinDir:        "${execprefix}/bin",
		LibExecDir:    "${execprefix}/libexec",
		LibDir:        "${execprefix}/lib",
		SysConfDir:    "${prefix}/etc",
		DataRootDir:   "${prefix}/share",
		DataDir:       "${datarootdir}",
		ManDir:        "${datarootdir}/man",
	}
}

// Package is the package name in which the GoConfig file will be written
var Package = "main"

// Makefile is the filename of the makefile that will be generated
var Makefile = "go.make"

// GoConfig is the filename of the go file that will be generated containing
// all the variable values.
var GoConfig = "appconfig"

// GoConfigVariable is the name of the variable inside the GoConfig file
// containing all the variable values.
var GoConfigVariable = "AppConfig"

// Target is the executable name to build. If left empty, the name is deduced
// from the directory (similar to what go does)
var Target = ""

// Version is the application version
var Version []int = []int{0, 1}

type expandStringPart struct {
	Value      string
	IsVariable bool
}

func (x *expandStringPart) expand(m map[string]*expandString) (string, []string) {
	if x.IsVariable {
		s, ok := m[x.Value]

		if !ok {
			return "", nil
		} else {
			ret := s.expand(m)
			rets := make([]string, len(s.dependencies), len(s.dependencies)+1)

			copy(rets, s.dependencies)

			return ret, append(rets, x.Value)
		}
	}

	return x.Value, nil
}

type expandString struct {
	Name  string
	Parts []expandStringPart

	dependencies []string
	value        string
	hasExpanded  bool
}

func (x *expandString) dependsOn(name string) bool {
	i := sort.SearchStrings(x.dependencies, name)

	return i < len(x.dependencies) && x.dependencies[i] == name
}

func (x *expandString) expand(m map[string]*expandString) string {
	if !x.hasExpanded {
		// Prevent infinite loop by circular dependencies
		x.hasExpanded = true
		buf := bytes.Buffer{}

		for _, v := range x.Parts {
			s, deps := v.expand(m)
			buf.WriteString(s)

			x.dependencies = append(x.dependencies, deps...)
		}

		sort.Strings(x.dependencies)
		x.value = buf.String()
	}

	return x.value
}

// Config represents the current configuration. See Configure for more
// information.
type Config struct {
	*flags.Parser

	values   map[string]interface{}
	expanded map[string]*expandString
}

func (x *Config) extract() map[string]interface{} {
	ret := make(map[string]interface{})

	for _, grp := range x.Parser.Groups {
		for longname, option := range grp.LongNames {
			ret[longname] = option.Value.Interface()
		}
	}

	return ret
}

func (x *Config) expand() map[string]*expandString {
	ret := make(map[string]*expandString)

	r, _ := regexp.Compile(`\$\{[^}]*\}`)

	for name, val := range x.values {
		es := expandString{
			Name: name,
		}

		// Find all variable references
		s := fmt.Sprintf("%v", val)

		matches := r.FindAllStringIndex(s, -1)

		for i, match := range matches {
			var prefix string

			if i == 0 {
				prefix = s[0:match[0]]
			} else {
				prefix = s[matches[i-1][1]:match[0]]
			}

			if len(prefix) != 0 {
				es.Parts = append(es.Parts, expandStringPart{Value: prefix, IsVariable: false})
			}

			varname := s[match[0]+2 : match[1]-1]
			es.Parts = append(es.Parts, expandStringPart{Value: varname, IsVariable: true})
		}

		if len(matches) == 0 {
			es.Parts = append(es.Parts, expandStringPart{Value: s, IsVariable: false})
		} else {
			last := matches[len(matches)-1]
			suffix := s[last[1]:]

			if len(suffix) != 0 {
				es.Parts = append(es.Parts, expandStringPart{Value: suffix, IsVariable: false})
			}
		}

		ret[name] = &es
	}

	for _, val := range ret {
		val.expand(ret)
	}

	return ret
}

// Configure runs the configure process with options as provided by the given
// data variable. If data is nil, the default options will be used
// (see NewOptions). Note that the data provided is simply passed to go-flags.
// For more information on flags parsing, see the documentation of go-flags.
// If GoConfig is not empty, then the go configuration will be written to the
// GoConfig file. Similarly, if Makefile is not empty, the Makefile will be
// written.
func Configure(data interface{}) (*Config, error) {
	if data == nil {
		data = NewOptions()
	}

	parser := flags.NewParser(data, flags.PrintErrors)

	if _, err := parser.Parse(); err != nil {
		return nil, err
	}

	ret := &Config{
		Parser: parser,
	}

	ret.values = ret.extract()
	ret.expanded = ret.expand()

	if len(GoConfig) != 0 {
		filename := GoConfig

		if !strings.HasSuffix(filename, ".go") {
			filename += ".go"
		}

		f, err := os.Create(filename)

		if err != nil {
			return nil, err
		}

		ret.WriteGoConfig(f)
		f.Close()
	}

	if len(Makefile) != 0 {
		f, err := os.Create(Makefile)

		if err != nil {
			return nil, err
		}

		ret.WriteMakefile(f)
		f.Close()

		os.Chmod(Makefile, 0755)

		f, err = os.OpenFile(path.Join(path.Dir(Makefile), "Makefile"),
		                     os.O_CREATE | os.O_EXCL | os.O_WRONLY,
		                     0644)

		if err == nil {
			fmt.Fprintf(f, "include %s\n", path.Base(Makefile))
			f.Close()
		}
	}

	return ret, nil
}

// Expand expands the variable value indicated by name
func (x *Config) Expand(name string) string {
	return x.expanded[name].expand(x.expanded)
}

// WriteGoConfig writes the go configuration file containing all the variable
// values to the given writer. Note that it will write a package line if
// the Package variable is not empty. The GoConfigVariable name will
// be used as the variable name for the configuration.
func (x *Config) WriteGoConfig(writer io.Writer) {
	if len(Package) > 0 {
		fmt.Fprintf(writer, "package %v\n\n", Package)
	}

	fmt.Fprintf(writer, "var %s = struct {\n", GoConfigVariable)
	values := make([]string, 0)

	variables := make([]string, 0, len(x.values))
	optionmap := make(map[string]*flags.Option)

	// Write all options
	for _, grp := range x.Parser.Groups {
		for _, option := range grp.LongNames {
			name := option.Field.Name

			variables = append(variables, name)
			optionmap[name] = option
		}
	}

	sort.Strings(variables)

	for i, name := range variables {
		if i != 0 {
			io.WriteString(writer, "\n")
		}

		option := optionmap[name]
		val := option.Value.Interface()

		fmt.Fprintf(writer, "\t// %s\n", option.Description)
		fmt.Fprintf(writer, "\t%v %T\n", name, val)

		var value string

		if option.Value.Type().Kind() == reflect.String {
			value = fmt.Sprintf("%#v", x.Expand(option.LongName))
		} else {
			value = fmt.Sprintf("%#v", val)
		}

		values = append(values, value)
	}

	if len(variables) > 0 {
		io.WriteString(writer, "\n")
	}

	io.WriteString(writer, "\t// Application version\n")
	io.WriteString(writer, "\tVersion []int\n")
	fmt.Fprintln(writer, "}{")

	for _, v := range values {
		fmt.Fprintf(writer, "\t%v,\n", v)
	}

	for i, v := range Version {
		if i != 0 {
			io.WriteString(writer, ", ")
		} else {
			io.WriteString(writer, "\t[]int{")
		}

		fmt.Fprintf(writer, "%v", v)
	}

	fmt.Fprintln(writer, "},")
	fmt.Fprintln(writer, "}")
}

// WriteMakefile writes a Makefile for the given parser to the given writer.
// The Makefile contains the common build, clean, distclean, install and
// uninstall rules.
func (x *Config) WriteMakefile(writer io.Writer) {
	// Write a very basic makefile
	io.WriteString(writer, "#!/usr/bin/make -f\n\n")

	vars := make([]*expandString, 0, len(x.expanded))

	for name, v := range x.expanded {
		inserted := false

		// Insert into vars based on dependencies
		for i, vv := range vars {
			if vv.dependsOn(name) {
				tail := vars[i:]

				if i == 0 {
					vars = append([]*expandString{v}, vars...)
				} else {
					vars = append(append(vars[0:i-1], v), tail...)
				}

				inserted = true
				break
			}
		}

		if !inserted {
			vars = append(vars, v)
		}
	}

	if len(vars) > 0 {
		io.WriteString(writer, "# Variables\n")

		for _, v := range vars {
			fmt.Fprintf(writer, "%s = ", v.Name)

			for _, part := range v.Parts {
				if part.IsVariable {
					fmt.Fprintf(writer, "$(%s)", part.Value)
				} else {
					fmt.Fprintf(writer, "%s", part.Value)
				}
			}

			io.WriteString(writer, "\n")
		}

		io.WriteString(writer, "\n")
	}

	target := Target

	if len(target) == 0 {
		pc := make([]uintptr, 3)
		n := runtime.Callers(1, pc)

		me, _ := runtime.FuncForPC(pc[0]).FileLine(pc[0])

		for i := 1; i < n; i++ {
			f := runtime.FuncForPC(pc[i])
			fname, _ := f.FileLine(pc[i])

			if fname != me {
				target = path.Base(path.Dir(fname))
				break
			}
		}
	}

	fmt.Fprintf(writer, "TARGET = %s\n", target)
	fmt.Fprintf(writer, "\nSOURCES = $(wildcard *.go)\n\n")

	io.WriteString(writer, "# Rules\n")
	io.WriteString(writer, "$(TARGET): $(SOURCES)\n")
	io.WriteString(writer, "\tgo build -o $(TARGET) $(SOURCES)\n\n")

	io.WriteString(writer, "clean:\n")
	io.WriteString(writer, "\trm -f $(TARGET)\n\n")

	io.WriteString(writer, "distclean: clean\n\n")

	io.WriteString(writer, "install: $(TARGET)\n")
	io.WriteString(writer, "\tmkdir -p $(DESTDIR)$(bindir) && cp $(TARGET) $(DESTDIR)$(bindir)/$(TARGET)\n\n")

	io.WriteString(writer, "uninstall:\n")
	io.WriteString(writer, "\trm -f $(DESTDIR)$(bindir)/$(TARGET)\n\n")

	io.WriteString(writer, ".PHONY: install uninstall distclean clean")
}
<|endoftext|>