<commit_before>package main

import (
	"bytes"
	"code.google.com/p/freetype-go/freetype"
	"code.google.com/p/freetype-go/freetype/truetype"
	"flag"
	"fmt"
	"github.com/sugyan/ttygif"
	"image"
	"image/color"
	"image/color/palette"
	"image/draw"
	"image/gif"
	"io"
	"io/ioutil"
	"j4k.co/terminal"
	"os"
	"path/filepath"
)

// colors
var (
	TerminalColorRed          = color.RGBA{0xff, 0x00, 0x00, 0xff}
	TerminalColorGreen        = color.RGBA{0x00, 0xff, 0x00, 0xff}
	TerminalColorBlue         = color.RGBA{0x00, 0x00, 0xff, 0xff}
	TerminalColorYellow       = color.RGBA{0xff, 0xff, 0x00, 0xff}
	TerminalColorMagenta      = color.RGBA{0xff, 0x00, 0xff, 0xff}
	TerminalColorCyan         = color.RGBA{0x00, 0xff, 0xff, 0xff}
	TerminalColorLightGrey    = color.RGBA{0xcc, 0xcc, 0xcc, 0xff}
	TerminalColorDarkGrey     = color.RGBA{0x99, 0x99, 0x99, 0xff}
	TerminalColorLightRed     = color.RGBA{0xff, 0x33, 0x33, 0xff}
	TerminalColorLightGreen   = color.RGBA{0x33, 0xff, 0x33, 0xff}
	TerminalColorLightYellow  = color.RGBA{0xff, 0xff, 0x33, 0xff}
	TerminalColorLightBlue    = color.RGBA{0x33, 0x33, 0xff, 0xff}
	TerminalColorLightMagenta = color.RGBA{0xff, 0x33, 0xff, 0xff}
	TerminalColorLightCyan    = color.RGBA{0x33, 0xff, 0xff, 0xff}
	TerminalColorWhite        = color.RGBA{0xff, 0xff, 0xff, 0xff}
	TerminalColorGray         = color.RGBA{0x7f, 0x7f, 0x7f, 0x7f}
)

var font *truetype.Font

const fontSize = 18

func init() {
	fontData, err := Asset("font/Anonymous Pro Minus.ttf")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	font, err = freetype.ParseFont(fontData)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main() {
	input := flag.String("in", "ttyrecord", "input ttyrec file")
	output := flag.String("out", "tty.gif", "output gif file")
	speed := flag.Float64("s", 1.0, "play speed")
	flag.Parse()

	err := generateGIF(*input, *output, *speed)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	absPath, err := filepath.Abs(*output)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fmt.Printf("%s created!\n", absPath)
}

func generateGIF(input string, output string, speed float64) (err error) {
	// input
	inFile, err := os.Open(input)
	if err != nil {
		return
	}
	defer inFile.Close()

	// virtual terminal
	var state = terminal.State{}
	vt, err := terminal.Create(&state, ioutil.NopCloser(bytes.NewBuffer([]byte{})))
	if err != nil {
		return
	}
	defer vt.Close()

	// read ttyrecord
	reader := ttygif.NewTtyReader(inFile)
	var (
		first  = true
		prevTv ttygif.TimeVal
		images []*image.Paletted
		delays []int
	)
	for {
		var data *ttygif.TtyData
		data, err = reader.ReadData()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				return
			}
		}
		var diff ttygif.TimeVal
		if first {
			first = false
		} else {
			diff = data.TimeVal.Subtract(prevTv)
		}
		prevTv = data.TimeVal

		// calc delay and capture
		delay := int(float64(diff.Sec*1000000+diff.Usec)/speed) / 10000
		if delay > 0 {
			var img *image.Paletted
			img, err = capture(&state)
			if err != nil {
				return
			}
			images = append(images, img)
			delays = append(delays, delay)
		}
		// write to vt
		_, err = vt.Write(*data.Buffer)
		if err != nil {
			return
		}
	}

	outFile, err := os.Create(output)
	err = gif.EncodeAll(outFile, &gif.GIF{
		Image: images,
		Delay: delays,
	})
	if err != nil {
		return
	}
	return nil
}

func capture(state *terminal.State) (paletted *image.Paletted, err error) {
	fb := font.Bounds(fontSize)

	paletted = image.NewPaletted(image.Rect(0, 0, 80*int(fb.XMax-fb.XMin)+10, 24*int(fb.YMax-fb.YMin)), palette.WebSafe)
	draw.Draw(paletted, paletted.Bounds(), image.Black, image.ZP, draw.Src)
	c := freetype.NewContext()
	c.SetFont(font)
	c.SetFontSize(fontSize)
	c.SetDst(paletted)
	c.SetClip(paletted.Bounds())
	for row := 0; row < 24; row++ {
		for col := 0; col < 80; col++ {
			ch, fg, bg := state.Cell(col, row)
			if bg != terminal.DefaultBG {
				var uniform *image.Uniform
				switch bg {
				case terminal.Red:
					uniform = image.NewUniform(TerminalColorRed)
				case terminal.Green:
					uniform = image.NewUniform(TerminalColorGreen)
				case terminal.Blue:
					uniform = image.NewUniform(TerminalColorBlue)
				case terminal.Yellow:
					uniform = image.NewUniform(TerminalColorYellow)
				case terminal.Magenta:
					uniform = image.NewUniform(TerminalColorMagenta)
				case terminal.Cyan:
					uniform = image.NewUniform(TerminalColorCyan)
				case terminal.LightGrey:
					uniform = image.NewUniform(TerminalColorLightGrey)
				case terminal.DarkGrey:
					uniform = image.NewUniform(TerminalColorDarkGrey)
				case terminal.LightRed:
					uniform = image.NewUniform(TerminalColorLightRed)
				case terminal.LightGreen:
					uniform = image.NewUniform(TerminalColorLightGreen)
				case terminal.LightYellow:
					uniform = image.NewUniform(TerminalColorLightYellow)
				case terminal.LightBlue:
					uniform = image.NewUniform(TerminalColorLightBlue)
				case terminal.LightMagenta:
					uniform = image.NewUniform(TerminalColorLightMagenta)
				case terminal.LightCyan:
					uniform = image.NewUniform(TerminalColorLightCyan)
				case terminal.White:
					uniform = image.NewUniform(TerminalColorWhite)
				case terminal.DefaultFG:
					uniform = image.White
				default:
					uniform = image.Transparent
				}
				draw.Draw(paletted, image.Rect(5+col*int(fb.XMax-fb.XMin), row*int(fb.YMax-fb.YMin)-int(fb.YMin), 5+(col+1)*int(fb.XMax-fb.XMin), (row+1)*int(fb.YMax-fb.YMin)-int(fb.YMin)), uniform, image.ZP, draw.Src)
			}
			switch fg {
			case terminal.Red:
				c.SetSrc(image.NewUniform(TerminalColorRed))
			case terminal.Green:
				c.SetSrc(image.NewUniform(TerminalColorGreen))
			case terminal.Blue:
				c.SetSrc(image.NewUniform(TerminalColorBlue))
			case terminal.Yellow:
				c.SetSrc(image.NewUniform(TerminalColorYellow))
			case terminal.Magenta:
				c.SetSrc(image.NewUniform(TerminalColorMagenta))
			case terminal.Cyan:
				c.SetSrc(image.NewUniform(TerminalColorCyan))
			case terminal.LightGrey:
				c.SetSrc(image.NewUniform(TerminalColorLightGrey))
			case terminal.DarkGrey:
				c.SetSrc(image.NewUniform(TerminalColorDarkGrey))
			case terminal.LightRed:
				c.SetSrc(image.NewUniform(TerminalColorLightRed))
			case terminal.LightGreen:
				c.SetSrc(image.NewUniform(TerminalColorLightGreen))
			case terminal.LightYellow:
				c.SetSrc(image.NewUniform(TerminalColorLightYellow))
			case terminal.LightBlue:
				c.SetSrc(image.NewUniform(TerminalColorLightBlue))
			case terminal.LightMagenta:
				c.SetSrc(image.NewUniform(TerminalColorLightMagenta))
			case terminal.LightCyan:
				c.SetSrc(image.NewUniform(TerminalColorLightCyan))
			case terminal.White:
				c.SetSrc(image.NewUniform(TerminalColorWhite))
			case terminal.DefaultFG:
				c.SetSrc(image.White)
			case terminal.DefaultBG:
				c.SetSrc(image.Black)
			default:
				// TODO??
				c.SetSrc(image.NewUniform(TerminalColorGray))
			}
			str := string(ch)
			_, err = c.DrawString(str, freetype.Pt(5+col*int(fb.XMax-fb.XMin), (row+1)*int(fb.YMax-fb.YMin)))
			if err != nil {
				return
			}
		}
	}

	return paletted, nil
}
<commit_msg>256color<commit_after>package main

import (
	"bytes"
	"code.google.com/p/freetype-go/freetype"
	"code.google.com/p/freetype-go/freetype/truetype"
	"flag"
	"fmt"
	"github.com/errnoh/term.color"
	"github.com/sugyan/ttygif"
	"image"
	"image/color/palette"
	"image/draw"
	"image/gif"
	"io"
	"io/ioutil"
	"j4k.co/terminal"
	"os"
	"path/filepath"
)

var font *truetype.Font

const fontSize = 18

func init() {
	fontData, err := Asset("font/Anonymous Pro Minus.ttf")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	font, err = freetype.ParseFont(fontData)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main() {
	input := flag.String("in", "ttyrecord", "input ttyrec file")
	output := flag.String("out", "tty.gif", "output gif file")
	speed := flag.Float64("s", 1.0, "play speed")
	flag.Parse()

	err := generateGIF(*input, *output, *speed)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	absPath, err := filepath.Abs(*output)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fmt.Printf("%s created!\n", absPath)
}

func generateGIF(input string, output string, speed float64) (err error) {
	// input
	inFile, err := os.Open(input)
	if err != nil {
		return
	}
	defer inFile.Close()

	// virtual terminal
	var state = terminal.State{}
	vt, err := terminal.Create(&state, ioutil.NopCloser(bytes.NewBuffer([]byte{})))
	if err != nil {
		return
	}
	defer vt.Close()

	// read ttyrecord
	reader := ttygif.NewTtyReader(inFile)
	var (
		first  = true
		prevTv ttygif.TimeVal
		images []*image.Paletted
		delays []int
	)
	for {
		var data *ttygif.TtyData
		data, err = reader.ReadData()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				return
			}
		}
		var diff ttygif.TimeVal
		if first {
			first = false
		} else {
			diff = data.TimeVal.Subtract(prevTv)
		}
		prevTv = data.TimeVal

		// calc delay and capture
		delay := int(float64(diff.Sec*1000000+diff.Usec)/speed) / 10000
		if delay > 0 {
			var img *image.Paletted
			img, err = capture(&state)
			if err != nil {
				return
			}
			images = append(images, img)
			delays = append(delays, delay)
		}
		// write to vt
		_, err = vt.Write(*data.Buffer)
		if err != nil {
			return
		}
	}

	outFile, err := os.Create(output)
	err = gif.EncodeAll(outFile, &gif.GIF{
		Image: images,
		Delay: delays,
	})
	if err != nil {
		return
	}
	return nil
}

func capture(state *terminal.State) (paletted *image.Paletted, err error) {
	fb := font.Bounds(fontSize)

	paletted = image.NewPaletted(image.Rect(0, 0, 80*int(fb.XMax-fb.XMin)+10, 24*int(fb.YMax-fb.YMin)), palette.WebSafe)
	draw.Draw(paletted, paletted.Bounds(), image.Black, image.ZP, draw.Src)
	c := freetype.NewContext()
	c.SetFont(font)
	c.SetFontSize(fontSize)
	c.SetDst(paletted)
	c.SetClip(paletted.Bounds())
	for row := 0; row < 24; row++ {
		for col := 0; col < 80; col++ {
			ch, fg, bg := state.Cell(col, row)
			if bg != terminal.DefaultBG {
				uniform := image.NewUniform(color.Term256{Val: uint8(bg)})
				draw.Draw(paletted, image.Rect(5+col*int(fb.XMax-fb.XMin), row*int(fb.YMax-fb.YMin)-int(fb.YMin), 5+(col+1)*int(fb.XMax-fb.XMin), (row+1)*int(fb.YMax-fb.YMin)-int(fb.YMin)), uniform, image.ZP, draw.Src)
			}
			switch fg {
			case terminal.DefaultFG:
				c.SetSrc(image.White)
			case terminal.DefaultBG:
				c.SetSrc(image.Black)
			default:
				c.SetSrc(image.NewUniform(color.Term256{Val: uint8(fg)}))
			}
			str := string(ch)
			_, err = c.DrawString(str, freetype.Pt(5+col*int(fb.XMax-fb.XMin), (row+1)*int(fb.YMax-fb.YMin)))
			if err != nil {
				return
			}
		}
	}

	return paletted, nil
}
<|endoftext|>


<commit_before>package capn

import (
	"bytes"
	"errors"
	"io"
	"math"
)

var (
	errBufferCall     = errors.New("capn: can't call on a memory buffer")
	ErrInvalidSegment = errors.New("capn: invalid segment id")
	ErrTooMuchData    = errors.New("capn: too much data in stream")
)

type buffer Segment

// NewBuffer creates an expanding single segment buffer. Creating new objects
// will expand the buffer. Data can be nil (or length 0 with some capacity) if
// creating a new session. If parsing an existing segment than data should be
// the segment contents and will not be copied.
func NewBuffer(data []byte) *Segment {
	if uint64(len(data)) > uint64(math.MaxUint32) {
		return nil
	}

	b := &buffer{}
	b.Message = b
	b.Data = data
	return (*Segment)(b)
}

func (b *buffer) NewSegment(minsz int) (*Segment, error) {
	if uint64(len(b.Data)) > uint64(math.MaxUint32-minsz) {
		return nil, ErrOverlarge
	}
	b.Data = append(b.Data, make([]byte, minsz)...)
	b.Data = b.Data[:len(b.Data)-minsz]
	return (*Segment)(b), nil
}

func (b *buffer) Lookup(segid uint32) (*Segment, error) {
	if segid == 0 {
		return (*Segment)(b), nil
	} else {
		return nil, ErrInvalidSegment
	}
}

type multiBuffer struct {
	segments []*Segment
}

// NewMultiBuffer creates a new multi segment message. Creating new objects
// will try and reuse the buffers available, but will create new ones if there
// is insufficient capacity. When parsing an existing message data should be
// the list of segments. The data buffers will not be copied.
func NewMultiBuffer(data [][]byte) *Segment {
	m := &multiBuffer{make([]*Segment, len(data))}
	for i, d := range data {
		m.segments[i] = &Segment{m, d, uint32(i)}
	}
	if len(data) > 0 {
		return m.segments[0]
	}
	return &Segment{m, nil, 0xFFFFFFFF}
}

var (
	MaxSegmentNumber = 1024
	MaxTotalSize     = 1024 * 1024 * 1024
)

func (m *multiBuffer) NewSegment(minsz int) (*Segment, error) {
	for _, s := range m.segments {
		if len(s.Data)+minsz <= cap(s.Data) {
			return s, nil
		}
	}

	if minsz < 4096 {
		minsz = 4096
	}
	s := &Segment{m, make([]byte, 0, minsz), uint32(len(m.segments))}
	m.segments = append(m.segments, s)
	return s, nil
}

func (m *multiBuffer) Lookup(segid uint32) (*Segment, error) {
	if uint(segid) < uint(len(m.segments)) {
		return m.segments[segid], nil
	} else {
		return nil, ErrInvalidSegment
	}
}

// ReadFromStream reads a non-packed serialized stream from r. buf is used to
// buffer the read contents, can be nil, and is provided so that the buffer
// can be reused between messages. The returned segment is the first segment
// read, which contains the root pointer.
func ReadFromStream(r io.Reader, buf *bytes.Buffer) (*Segment, error) {
	if buf == nil {
		buf = new(bytes.Buffer)
	} else {
		buf.Reset()
	}

	if _, err := io.CopyN(buf, r, 4); err != nil {
		return nil, err
	}

	if little32(buf.Bytes()[:]) >= uint32(MaxSegmentNumber) {
		return nil, ErrTooMuchData
	}

	segnum := int(little32(buf.Bytes()[:]) + 1)
	hdrsz := 8*(segnum/2) + 4

	if _, err := io.CopyN(buf, r, int64(hdrsz)); err != nil {
		return nil, err
	}

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(buf.Bytes()[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, ErrTooMuchData
		}
		total += int(sz) * 8
	}

	if _, err := io.CopyN(buf, r, int64(total)); err != nil {
		return nil, err
	}

	hdrv := buf.Bytes()[4 : hdrsz+4]
	datav := buf.Bytes()[hdrsz+4:]
	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], nil
}

// ReadFromMemoryZeroCopy: like ReadFromStream, but reads a non-packed
// serialized stream that already resides in memory in the argument data.
// The returned segment is the first segment read, which contains
// the root pointer. The returned bytesRead says how many bytes are pointed
// to by seg. The caller should do data = data[bytesRead:] between
// successive calls to ReadFromMemoryZeroCopy().
func ReadFromMemoryZeroCopy(data []byte) (seg *Segment, bytesRead int64, err error) {

	if little32(data[0:4]) >= uint32(MaxSegmentNumber) {
		return nil, 0, ErrTooMuchData
	}

	segnum := int(little32(data[0:4]) + 1)
	hdrsz := 8*(segnum/2) + 4

	b := data[0 : (hdrsz+4)]

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(b[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, 0, ErrTooMuchData
		}
		total += int(sz) * 8
	}

	hdrv := data[4 : (hdrsz+4)]
	datav := data[hdrsz+4:]
	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], int64(4+hdrsz+total), nil
}

// WriteTo writes the message that the segment is part of to the
// provided stream in serialized form.
func (s *Segment) WriteTo(w io.Writer) (int64, error) {
	segnum := uint32(1)
	for {
		if seg, _ := s.Message.Lookup(segnum); seg == nil {
			break
		}
		segnum++
	}

	hdrv := make([]uint8, 8*(segnum/2)+8)
	putLittle32(hdrv, segnum-1)
	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		putLittle32(hdrv[4*i+4:], uint32(len(seg.Data)/8))
	}

	if n, err := w.Write(hdrv); err != nil {
		return int64(n), err
	}
	written := int64(len(hdrv))

	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		if n, err := w.Write(seg.Data); err != nil {
			return written + int64(n), err
		} else {
			written += int64(n)
		}
	}

	return written, nil
}
<commit_msg>ReadFromMemoryZeroCopy() in mem.go allows go-capnp to read capnp objects from an input []byte instead of an io.Reader<commit_after>package capn

import (
	"bytes"
	"errors"
	"io"
	"math"
)

var (
	errBufferCall     = errors.New("capn: can't call on a memory buffer")
	ErrInvalidSegment = errors.New("capn: invalid segment id")
	ErrTooMuchData    = errors.New("capn: too much data in stream")
)

type buffer Segment

// NewBuffer creates an expanding single segment buffer. Creating new objects
// will expand the buffer. Data can be nil (or length 0 with some capacity) if
// creating a new session. If parsing an existing segment than data should be
// the segment contents and will not be copied.
func NewBuffer(data []byte) *Segment {
	if uint64(len(data)) > uint64(math.MaxUint32) {
		return nil
	}

	b := &buffer{}
	b.Message = b
	b.Data = data
	return (*Segment)(b)
}

func (b *buffer) NewSegment(minsz int) (*Segment, error) {
	if uint64(len(b.Data)) > uint64(math.MaxUint32-minsz) {
		return nil, ErrOverlarge
	}
	b.Data = append(b.Data, make([]byte, minsz)...)
	b.Data = b.Data[:len(b.Data)-minsz]
	return (*Segment)(b), nil
}

func (b *buffer) Lookup(segid uint32) (*Segment, error) {
	if segid == 0 {
		return (*Segment)(b), nil
	} else {
		return nil, ErrInvalidSegment
	}
}

type multiBuffer struct {
	segments []*Segment
}

// NewMultiBuffer creates a new multi segment message. Creating new objects
// will try and reuse the buffers available, but will create new ones if there
// is insufficient capacity. When parsing an existing message data should be
// the list of segments. The data buffers will not be copied.
func NewMultiBuffer(data [][]byte) *Segment {
	m := &multiBuffer{make([]*Segment, len(data))}
	for i, d := range data {
		m.segments[i] = &Segment{m, d, uint32(i)}
	}
	if len(data) > 0 {
		return m.segments[0]
	}
	return &Segment{m, nil, 0xFFFFFFFF}
}

var (
	MaxSegmentNumber = 1024
	MaxTotalSize     = 1024 * 1024 * 1024
)

func (m *multiBuffer) NewSegment(minsz int) (*Segment, error) {
	for _, s := range m.segments {
		if len(s.Data)+minsz <= cap(s.Data) {
			return s, nil
		}
	}

	if minsz < 4096 {
		minsz = 4096
	}
	s := &Segment{m, make([]byte, 0, minsz), uint32(len(m.segments))}
	m.segments = append(m.segments, s)
	return s, nil
}

func (m *multiBuffer) Lookup(segid uint32) (*Segment, error) {
	if uint(segid) < uint(len(m.segments)) {
		return m.segments[segid], nil
	} else {
		return nil, ErrInvalidSegment
	}
}

// ReadFromStream reads a non-packed serialized stream from r. buf is used to
// buffer the read contents, can be nil, and is provided so that the buffer
// can be reused between messages. The returned segment is the first segment
// read, which contains the root pointer.
func ReadFromStream(r io.Reader, buf *bytes.Buffer) (*Segment, error) {
	if buf == nil {
		buf = new(bytes.Buffer)
	} else {
		buf.Reset()
	}

	if _, err := io.CopyN(buf, r, 4); err != nil {
		return nil, err
	}

	if little32(buf.Bytes()[:]) >= uint32(MaxSegmentNumber) {
		return nil, ErrTooMuchData
	}

	segnum := int(little32(buf.Bytes()[:]) + 1)
	hdrsz := 8*(segnum/2) + 4

	if _, err := io.CopyN(buf, r, int64(hdrsz)); err != nil {
		return nil, err
	}

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(buf.Bytes()[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, ErrTooMuchData
		}
		total += int(sz) * 8
	}

	if _, err := io.CopyN(buf, r, int64(total)); err != nil {
		return nil, err
	}

	hdrv := buf.Bytes()[4 : hdrsz+4]
	datav := buf.Bytes()[hdrsz+4:]
	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], nil
}

// ReadFromMemoryZeroCopy: like ReadFromStream, but reads a non-packed
// serialized stream that already resides in memory in the argument data.
// The returned segment is the first segment read, which contains
// the root pointer. The returned bytesRead says how many bytes were
// consumed from data in making seg. The caller should advance the
// data slice by doing data = data[bytesRead:] between successive calls
// to ReadFromMemoryZeroCopy().
func ReadFromMemoryZeroCopy(data []byte) (seg *Segment, bytesRead int64, err error) {

	if little32(data[0:4]) >= uint32(MaxSegmentNumber) {
		return nil, 0, ErrTooMuchData
	}

	segnum := int(little32(data[0:4]) + 1)
	hdrsz := 8*(segnum/2) + 4

	b := data[0 : (hdrsz+4)]

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(b[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, 0, ErrTooMuchData
		}
		total += int(sz) * 8
	}

	hdrv := data[4 : (hdrsz+4)]
	datav := data[hdrsz+4:]
	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], int64(4+hdrsz+total), nil
}

// WriteTo writes the message that the segment is part of to the
// provided stream in serialized form.
func (s *Segment) WriteTo(w io.Writer) (int64, error) {
	segnum := uint32(1)
	for {
		if seg, _ := s.Message.Lookup(segnum); seg == nil {
			break
		}
		segnum++
	}

	hdrv := make([]uint8, 8*(segnum/2)+8)
	putLittle32(hdrv, segnum-1)
	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		putLittle32(hdrv[4*i+4:], uint32(len(seg.Data)/8))
	}

	if n, err := w.Write(hdrv); err != nil {
		return int64(n), err
	}
	written := int64(len(hdrv))

	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		if n, err := w.Write(seg.Data); err != nil {
			return written + int64(n), err
		} else {
			written += int64(n)
		}
	}

	return written, nil
}
<|endoftext|>


<commit_before>package mackerel

import (
	"fmt"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

func TestFindUsers(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/users" {
			t.Error("request URL should be but: ", req.URL.Path)
		}

		if req.Method != "GET" {
			t.Error("request method should be GET but: ", req.Method)
		}

		respJSON, _ := json.Marshal(map[string][]map[string]interface{}{
			"users": {
				{
					"id":                      "ABCDEFGHIJK",
					"screenName":              "myname",
					"email":                   "test@example.com",
					"authority":               "viewer",
					"isInRegistrationProcess": true,
					"isMFAEnabled":            true,
					"authenticationMethods":   []string{"password"},
					"joinedAt":                1560000000,
				},
			},
		})
		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	users, err := client.FindUsers()

	if err != nil {
		t.Error("err should be nil but: ", err)
	}

	if users[0].ID != "ABCDEFGHIJK" {
		t.Error("request sends json including id but: ", users[0].ID)
	}

	if users[0].ScreenName != "myname" {
		t.Error("request sends json including screenName but: ", users[0].ScreenName)
	}

	if users[0].Email != "test@example.com" {
		t.Error("request sends json including email but: ", users[0].Email)
	}

	if users[0].Authority != "viewer" {
		t.Error("request sends json including authority but: ", users[0].Authority)
	}

	if users[0].IsInRegistrationProcess != true {
		t.Error("request sends json including isInRegistrationProcess but: ", users[0].IsInRegistrationProcess)
	}

	if users[0].IsMFAEnabled != true {
		t.Error("request sends json including isMFAEnabled but: ", users[0].IsMFAEnabled)
	}

	if reflect.DeepEqual(users[0].AuthenticationMethods, []string{"password"}) != true {
		t.Errorf("Wrong data for users: %v", users[0].AuthenticationMethods)
	}

	if users[0].JoinedAt != 1560000000 {
		t.Error("request sends json including joinedAt but: ", users[0].JoinedAt)
	}
}
<commit_msg>mod ci error<commit_after>package mackerel

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

func TestFindUsers(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/users" {
			t.Error("request URL should be but: ", req.URL.Path)
		}

		if req.Method != "GET" {
			t.Error("request method should be GET but: ", req.Method)
		}

		respJSON, _ := json.Marshal(map[string][]map[string]interface{}{
			"users": {
				{
					"id":                      "ABCDEFGHIJK",
					"screenName":              "myname",
					"email":                   "test@example.com",
					"authority":               "viewer",
					"isInRegistrationProcess": true,
					"isMFAEnabled":            true,
					"authenticationMethods":   []string{"password"},
					"joinedAt":                1560000000,
				},
			},
		})
		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	users, err := client.FindUsers()

	if err != nil {
		t.Error("err should be nil but: ", err)
	}

	if users[0].ID != "ABCDEFGHIJK" {
		t.Error("request sends json including id but: ", users[0].ID)
	}

	if users[0].ScreenName != "myname" {
		t.Error("request sends json including screenName but: ", users[0].ScreenName)
	}

	if users[0].Email != "test@example.com" {
		t.Error("request sends json including email but: ", users[0].Email)
	}

	if users[0].Authority != "viewer" {
		t.Error("request sends json including authority but: ", users[0].Authority)
	}

	if users[0].IsInRegistrationProcess != true {
		t.Error("request sends json including isInRegistrationProcess but: ", users[0].IsInRegistrationProcess)
	}

	if users[0].IsMFAEnabled != true {
		t.Error("request sends json including isMFAEnabled but: ", users[0].IsMFAEnabled)
	}

	if reflect.DeepEqual(users[0].AuthenticationMethods, []string{"password"}) != true {
		t.Errorf("Wrong data for users: %v", users[0].AuthenticationMethods)
	}

	if users[0].JoinedAt != 1560000000 {
		t.Error("request sends json including joinedAt but: ", users[0].JoinedAt)
	}
}
<|endoftext|>


<commit_before>FROM debian:stretch

RUN apt-get update && apt-get install -y \
    build-essential libc6-dev \
    libpng16-16 libpng-dev \
    golang-go git

RUN mkdir -p /go
ENV GOPATH=/go
RUN go get -v -d github.com/urfave/cli

ADD . /go/src/github.com/qmsk/pngtile
WORKDIR /go/src/github.com/qmsk/pngtile

RUN make
RUN go install -v ./go/...
<commit_msg>Dockerfile.go: ENV PATH<commit_after>FROM debian:stretch

RUN apt-get update && apt-get install -y \
    build-essential libc6-dev \
    libpng16-16 libpng-dev \
    golang-go git

RUN mkdir -p /go
ENV GOPATH=/go
RUN go get -v -d github.com/urfave/cli

ADD . /go/src/github.com/qmsk/pngtile
WORKDIR /go/src/github.com/qmsk/pngtile

RUN make
RUN go install -v ./go/...

ENV PATH=/go/bin:$PATH
<|endoftext|>


<commit_before>package utils

import (
	"fmt"
	"reflect"
	"strconv"
)

// NewValue new struct value with reflect type
func NewValue(t reflect.Type) (v reflect.Value) {
	v = reflect.New(t)
	ov := v
	for t.Kind() == reflect.Ptr {
		v = v.Elem()
		t = t.Elem()
		e := reflect.New(t)
		v.Set(e)
	}

	if e := v.Elem(); e.Kind() == reflect.Map && e.IsNil() {
		v.Elem().Set(reflect.MakeMap(v.Elem().Type()))
	}
	return ov
}

// ToArray get array from value, will ignore blank string to convert it to array
func ToArray(value interface{}) (values []string) {
	switch value := value.(type) {
	case []string:
		values = []string{}
		for _, v := range value {
			if v != "" {
				values = append(values, v)
			}
		}
	case []interface{}:
		for _, v := range value {
			values = append(values, fmt.Sprint(v))
		}
	default:
		if value := fmt.Sprint(value); value != "" {
			values = []string{value}
		}
	}
	return
}

// ToString get string from value, if passed value is a slice, will use the first element
func ToString(value interface{}) string {
	if v, ok := value.([]string); ok {
		if len(v) > 0 {
			return v[0]
		}
		return ""
	} else if v, ok := value.(string); ok {
		return v
	} else if v, ok := value.([]interface{}); ok {
		if len(v) > 0 {
			return fmt.Sprintf("%v", v[0])
		}
		return ""
	}
	return fmt.Sprintf("%v", value)
}

// ToInt get int from value, if passed value is empty string, result will be 0
func ToInt(value interface{}) int64 {
	if result := ToString(value); result == "" {
		return 0
	} else if i, err := strconv.ParseInt(result, 10, 64); err == nil {
		return i
	} else {
		panic("failed to parse int: " + result)
	}
}

// ToUint get uint from value, if passed value is empty string, result will be 0
func ToUint(value interface{}) uint64 {
	if result := ToString(value); result == "" {
		return 0
	} else if i, err := strconv.ParseUint(result, 10, 64); err == nil {
		return i
	} else {
		panic("failed to parse uint: " + result)
	}
}

// ToFloat get float from value, if passed value is empty string, result will be 0
func ToFloat(value interface{}) float64 {
	if result := ToString(value); result == "" {
		return 0
	} else if i, err := strconv.ParseFloat(result, 64); err == nil {
		return i
	} else {
		panic("failed to parse float: " + result)
	}
}
<commit_msg>Refactor ToString<commit_after>package utils

import (
	"fmt"
	"reflect"
	"strconv"
)

// NewValue new struct value with reflect type
func NewValue(t reflect.Type) (v reflect.Value) {
	v = reflect.New(t)
	ov := v
	for t.Kind() == reflect.Ptr {
		v = v.Elem()
		t = t.Elem()
		e := reflect.New(t)
		v.Set(e)
	}

	if e := v.Elem(); e.Kind() == reflect.Map && e.IsNil() {
		v.Elem().Set(reflect.MakeMap(v.Elem().Type()))
	}
	return ov
}

// ToArray get array from value, will ignore blank string to convert it to array
func ToArray(value interface{}) (values []string) {
	switch value := value.(type) {
	case []string:
		values = []string{}
		for _, v := range value {
			if v != "" {
				values = append(values, v)
			}
		}
	case []interface{}:
		for _, v := range value {
			values = append(values, fmt.Sprint(v))
		}
	default:
		if value := fmt.Sprint(value); value != "" {
			values = []string{value}
		}
	}
	return
}

// ToString get string from value, if passed value is a slice, will use the first element
func ToString(value interface{}) string {
	if v, ok := value.([]string); ok {
		for _, s := range v {
			if s != "" {
				return s
			}
		}
		return ""
	} else if v, ok := value.(string); ok {
		return v
	} else if v, ok := value.([]interface{}); ok {
		for _, s := range v {
			if fmt.Sprint(s) != "" {
				return fmt.Sprint(s)
			}
		}
		return ""
	}
	return fmt.Sprintf("%v", value)
}

// ToInt get int from value, if passed value is empty string, result will be 0
func ToInt(value interface{}) int64 {
	if result := ToString(value); result == "" {
		return 0
	} else if i, err := strconv.ParseInt(result, 10, 64); err == nil {
		return i
	} else {
		panic("failed to parse int: " + result)
	}
}

// ToUint get uint from value, if passed value is empty string, result will be 0
func ToUint(value interface{}) uint64 {
	if result := ToString(value); result == "" {
		return 0
	} else if i, err := strconv.ParseUint(result, 10, 64); err == nil {
		return i
	} else {
		panic("failed to parse uint: " + result)
	}
}

// ToFloat get float from value, if passed value is empty string, result will be 0
func ToFloat(value interface{}) float64 {
	if result := ToString(value); result == "" {
		return 0
	} else if i, err := strconv.ParseFloat(result, 64); err == nil {
		return i
	} else {
		panic("failed to parse float: " + result)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"testing"
)

func TestMust(t *testing.T) {
	func() {
		defer func() {
			if r := recover(); r == nil {
				t.Errorf("must panic if err is given")
			}
		}()

		must(fmt.Errorf("error"))
	}()

	func() {
		defer func() {
			if r := recover(); r != nil {
				t.Errorf("must not panic if err is not given")
			}
		}()

		must(nil)
	}()
}
<commit_msg>test(gopwt): add tests to isGoFile2 and isTestGoFile<commit_after>package main

import (
	"fmt"
	"github.com/ToQoz/gopwt/assert"
	"testing"
)

func TestMust(t *testing.T) {
	func() {
		defer func() {
			if r := recover(); r == nil {
				t.Errorf("must panic if err is given")
			}
		}()

		must(fmt.Errorf("error"))
	}()

	func() {
		defer func() {
			if r := recover(); r != nil {
				t.Errorf("must not panic if err is not given")
			}
		}()

		must(nil)
	}()
}

func TestIsGoFile2(t *testing.T) {
	assert.OK(t, isGoFile2("a.go") == true, "a.go is go file")
	assert.OK(t, isGoFile2("a_test.go") == true, "a_test.go is go file")

	assert.OK(t, isGoFile2(".a.go") == false, ".a.go is not go file")
	assert.OK(t, isGoFile2("_a.go") == false, "_a.go is not go file")
	assert.OK(t, isGoFile2("a.goki") == false, "a.goki is not go file")
	assert.OK(t, isGoFile2("a") == false, "a is not go file")
}

func TestIsTestGoFile(t *testing.T) {
	assert.OK(t, isTestGoFile("a_test.go") == true, "a_test.go is test go file")

	assert.OK(t, isTestGoFile("a.go") == false, "a.go is test go file")
	assert.OK(t, isGoFile2(".a_test.go") == false, ".a_test.go is not go file")
	assert.OK(t, isGoFile2("_a_test.go") == false, "_a_test.go is not go file")
	assert.OK(t, isTestGoFile("_a.go") == false, "_a.go is not test go file")
	assert.OK(t, isTestGoFile("a.goki") == false, "a.goki is not test go file")
	assert.OK(t, isTestGoFile("a") == false, "a is not test go file")
}
<|endoftext|>


<commit_before>package gogrs

import "testing"

func BenchmarkRanInt(t *testing.B) {
	for i := 0; i < t.N; i++ {
		RandInt()
	}
}
<commit_msg>Add some bench.<commit_after>package gogrs

import "testing"

func BenchmarkRanInt(t *testing.B) {
	for i := 0; i < t.N; i++ {
		RandInt()
	}
}

func BenchmarkSumFloat64(t *testing.B) {
	var sample = []float64{20.2, 20.3, 100.25, 100.75}
	for i := 0; i < t.N; i++ {
		SumFloat64(sample)
	}
}

func BenchmarkAvgFloat64(t *testing.B) {
	var sample = []float64{20.2, 20.3, 100.25, 100.75}
	for i := 0; i < t.N; i++ {
		AvgFlast64(sample)
	}
}
<|endoftext|>


<commit_before>package docker

import (
	"github.com/dotcloud/docker/utils"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"testing"
)

// This file contains utility functions for docker's unit test suite.
// It has to be named XXX_test.go, apparently, in other to access private functions
// from other XXX_test.go functions.

// Create a temporary runtime suitable for unit testing.
// Call t.Fatal() at the first error.
func mkRuntime(f Fataler) *Runtime {
	runtime, err := newTestRuntime()
	if err != nil {
		f.Fatal(err)
	}
	return runtime
}

// A common interface to access the Fatal method of
// both testing.B and testing.T.
type Fataler interface {
	Fatal(args ...interface{})
}

func newTestRuntime() (*Runtime, error) {
	root, err := ioutil.TempDir("", "docker-test")
	if err != nil {
		return nil, err
	}
	if err := os.Remove(root); err != nil {
		return nil, err
	}
	if err := utils.CopyDirectory(unitTestStoreBase, root); err != nil {
		return nil, err
	}

	runtime, err := NewRuntimeFromDirectory(root, false)
	if err != nil {
		return nil, err
	}
	runtime.UpdateCapabilities(true)
	return runtime, nil
}

// Write `content` to the file at path `dst`, creating it if necessary,
// as well as any missing directories.
// The file is truncated if it already exists.
// Call t.Fatal() at the first error.
func writeFile(dst, content string, t *testing.T) {
	// Create subdirectories if necessary
	if err := os.MkdirAll(path.Dir(dst), 0700); err != nil && !os.IsExist(err) {
		t.Fatal(err)
	}
	f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
	if err != nil {
		t.Fatal(err)
	}
	// Write content (truncate if it exists)
	if _, err := io.Copy(f, strings.NewReader(content)); err != nil {
		t.Fatal(err)
	}
}

// Return the contents of file at path `src`.
// Call t.Fatal() at the first error (including if the file doesn't exist)
func readFile(src string, t *testing.T) (content string) {
	f, err := os.Open(src)
	if err != nil {
		t.Fatal(err)
	}
	data, err := ioutil.ReadAll(f)
	if err != nil {
		t.Fatal(err)
	}
	return string(data)
}

// Create a test container from the given runtime `r` and run arguments `args`.
// The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
// The caller is responsible for destroying the container.
// Call t.Fatal() at the first error.
func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConfig, error) {
	config, hostConfig, _, err := ParseRun(args, nil)
	if err != nil {
		return nil, nil, err
	}
	config.Image = GetTestImage(r).ID
	c, err := NewBuilder(r).Create(config)
	if err != nil {
		t.Fatal(err)
		return nil, nil, err
	}
	return c, hostConfig, nil
}

// Create a test container, start it, wait for it to complete, destroy it,
// and return its standard output as a string.
// The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
// If t is not nil, call t.Fatal() at the first error. Otherwise return errors normally.
func runContainer(r *Runtime, args []string, t *testing.T) (output string, err error) {
	defer func() {
		if err != nil && t != nil {
			t.Fatal(err)
		}
	}()
	container, hostConfig, err := mkContainer(r, args, t)
	if err != nil {
		return "", err
	}
	defer r.Destroy(container)
	stdout, err := container.StdoutPipe()
	if err != nil {
		return "", err
	}
	defer stdout.Close()
	if err := container.Start(hostConfig); err != nil {
		return "", err
	}
	container.Wait()
	data, err := ioutil.ReadAll(stdout)
	if err != nil {
		return "", err
	}
	output = string(data)
	return
}

func TestMergeConfig(t *testing.T) {
	volumesImage := make(map[string]struct{})
	volumesImage["/test1"] = struct{}{}
	volumesImage["/test2"] = struct{}{}
	configImage := &Config{
		Dns:       []string{"1.1.1.1", "2.2.2.2"},
		PortSpecs: []string{"1111:1111", "2222:2222"},
		Env:       []string{"VAR1=1", "VAR2=2"},
		Volumes:   volumesImage,
	}

	volumesUser := make(map[string]struct{})
	volumesUser["/test3"] = struct{}{}
	configUser := &Config{
		Dns:       []string{"3.3.3.3"},
		PortSpecs: []string{"3333:2222", "3333:3333"},
		Env:       []string{"VAR2=3", "VAR3=3"},
		Volumes:   volumesUser,
	}

	MergeConfig(configUser, configImage)

	if len(configUser.Dns) != 3 {
		t.Fatalf("Expected 3 dns, 1.1.1.1, 2.2.2.2 and 3.3.3.3, found %d", len(configUser.Dns))
	}
	for _, dns := range configUser.Dns {
		if dns != "1.1.1.1" && dns != "2.2.2.2" && dns != "3.3.3.3" {
			t.Fatalf("Expected 1.1.1.1 or 2.2.2.2 or 3.3.3.3, found %s", dns)
		}
	}

	if len(configUser.PortSpecs) != 3 {
		t.Fatalf("Expected 3 portSpecs, 1111:1111, 3333:2222 and 3333:3333, found %d", len(configUser.PortSpecs))
	}
	for _, portSpecs := range configUser.PortSpecs {
		if portSpecs != "1111:1111" && portSpecs != "3333:2222" && portSpecs != "3333:3333" {
			t.Fatalf("Expected 1111:1111 or 3333:2222 or 3333:3333, found %s", portSpecs)
		}
	}
	if len(configUser.Env) != 3 {
		t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
	}
	for _, env := range configUser.Env {
		if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
			t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
		}
	}

	if len(configUser.Volumes) != 3 {
		t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
	}
	for v, _ := range configUser.Volumes {
		if v != "/test1" && v != "/test2" && v != "/test3" {
			t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
		}
	}
}
<commit_msg>add regression test from @crosbymichael<commit_after>package docker

import (
	"github.com/dotcloud/docker/utils"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"testing"
)

// This file contains utility functions for docker's unit test suite.
// It has to be named XXX_test.go, apparently, in other to access private functions
// from other XXX_test.go functions.

// Create a temporary runtime suitable for unit testing.
// Call t.Fatal() at the first error.
func mkRuntime(f Fataler) *Runtime {
	runtime, err := newTestRuntime()
	if err != nil {
		f.Fatal(err)
	}
	return runtime
}

// A common interface to access the Fatal method of
// both testing.B and testing.T.
type Fataler interface {
	Fatal(args ...interface{})
}

func newTestRuntime() (*Runtime, error) {
	root, err := ioutil.TempDir("", "docker-test")
	if err != nil {
		return nil, err
	}
	if err := os.Remove(root); err != nil {
		return nil, err
	}
	if err := utils.CopyDirectory(unitTestStoreBase, root); err != nil {
		return nil, err
	}

	runtime, err := NewRuntimeFromDirectory(root, false)
	if err != nil {
		return nil, err
	}
	runtime.UpdateCapabilities(true)
	return runtime, nil
}

// Write `content` to the file at path `dst`, creating it if necessary,
// as well as any missing directories.
// The file is truncated if it already exists.
// Call t.Fatal() at the first error.
func writeFile(dst, content string, t *testing.T) {
	// Create subdirectories if necessary
	if err := os.MkdirAll(path.Dir(dst), 0700); err != nil && !os.IsExist(err) {
		t.Fatal(err)
	}
	f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
	if err != nil {
		t.Fatal(err)
	}
	// Write content (truncate if it exists)
	if _, err := io.Copy(f, strings.NewReader(content)); err != nil {
		t.Fatal(err)
	}
}

// Return the contents of file at path `src`.
// Call t.Fatal() at the first error (including if the file doesn't exist)
func readFile(src string, t *testing.T) (content string) {
	f, err := os.Open(src)
	if err != nil {
		t.Fatal(err)
	}
	data, err := ioutil.ReadAll(f)
	if err != nil {
		t.Fatal(err)
	}
	return string(data)
}

// Create a test container from the given runtime `r` and run arguments `args`.
// The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
// The caller is responsible for destroying the container.
// Call t.Fatal() at the first error.
func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConfig, error) {
	config, hostConfig, _, err := ParseRun(args, nil)
	if err != nil {
		return nil, nil, err
	}
	config.Image = GetTestImage(r).ID
	c, err := NewBuilder(r).Create(config)
	if err != nil {
		t.Fatal(err)
		return nil, nil, err
	}
	return c, hostConfig, nil
}

// Create a test container, start it, wait for it to complete, destroy it,
// and return its standard output as a string.
// The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
// If t is not nil, call t.Fatal() at the first error. Otherwise return errors normally.
func runContainer(r *Runtime, args []string, t *testing.T) (output string, err error) {
	defer func() {
		if err != nil && t != nil {
			t.Fatal(err)
		}
	}()
	container, hostConfig, err := mkContainer(r, args, t)
	if err != nil {
		return "", err
	}
	defer r.Destroy(container)
	stdout, err := container.StdoutPipe()
	if err != nil {
		return "", err
	}
	defer stdout.Close()
	if err := container.Start(hostConfig); err != nil {
		return "", err
	}
	container.Wait()
	data, err := ioutil.ReadAll(stdout)
	if err != nil {
		return "", err
	}
	output = string(data)
	return
}

func TestMergeConfig(t *testing.T) {
	volumesImage := make(map[string]struct{})
	volumesImage["/test1"] = struct{}{}
	volumesImage["/test2"] = struct{}{}
	configImage := &Config{
		Dns:       []string{"1.1.1.1", "2.2.2.2"},
		PortSpecs: []string{"1111:1111", "2222:2222"},
		Env:       []string{"VAR1=1", "VAR2=2"},
		Volumes:   volumesImage,
	}

	volumesUser := make(map[string]struct{})
	volumesUser["/test3"] = struct{}{}
	configUser := &Config{
		Dns:       []string{"3.3.3.3"},
		PortSpecs: []string{"3333:2222", "3333:3333"},
		Env:       []string{"VAR2=3", "VAR3=3"},
		Volumes:   volumesUser,
	}

	MergeConfig(configUser, configImage)

	if len(configUser.Dns) != 3 {
		t.Fatalf("Expected 3 dns, 1.1.1.1, 2.2.2.2 and 3.3.3.3, found %d", len(configUser.Dns))
	}
	for _, dns := range configUser.Dns {
		if dns != "1.1.1.1" && dns != "2.2.2.2" && dns != "3.3.3.3" {
			t.Fatalf("Expected 1.1.1.1 or 2.2.2.2 or 3.3.3.3, found %s", dns)
		}
	}

	if len(configUser.PortSpecs) != 3 {
		t.Fatalf("Expected 3 portSpecs, 1111:1111, 3333:2222 and 3333:3333, found %d", len(configUser.PortSpecs))
	}
	for _, portSpecs := range configUser.PortSpecs {
		if portSpecs != "1111:1111" && portSpecs != "3333:2222" && portSpecs != "3333:3333" {
			t.Fatalf("Expected 1111:1111 or 3333:2222 or 3333:3333, found %s", portSpecs)
		}
	}
	if len(configUser.Env) != 3 {
		t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
	}
	for _, env := range configUser.Env {
		if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
			t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
		}
	}

	if len(configUser.Volumes) != 3 {
		t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
	}
	for v, _ := range configUser.Volumes {
		if v != "/test1" && v != "/test2" && v != "/test3" {
			t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
		}
	}
}

func TestMergeConfigPublicPortNotHonored(t *testing.T) {
	volumesImage := make(map[string]struct{})
	volumesImage["/test1"] = struct{}{}
	volumesImage["/test2"] = struct{}{}
	configImage := &Config{
		Dns:       []string{"1.1.1.1", "2.2.2.2"},
		PortSpecs: []string{"1111", "2222"},
		Env:       []string{"VAR1=1", "VAR2=2"},
		Volumes:   volumesImage,
	}

	volumesUser := make(map[string]struct{})
	volumesUser["/test3"] = struct{}{}
	configUser := &Config{
		Dns:       []string{"3.3.3.3"},
		PortSpecs: []string{"1111:3333"},
		Env:       []string{"VAR2=3", "VAR3=3"},
		Volumes:   volumesUser,
	}

	MergeConfig(configUser, configImage)

	contains := func(a []string, expect string) bool {
		for _, p := range a {
			if p == expect {
				return true
			}
		}
		return false
	}

	if !contains(configUser.PortSpecs, "2222") {
		t.Logf("Expected '2222' Ports: %v", configUser.PortSpecs)
		t.Fail()
	}

	if !contains(configUser.PortSpecs, "1111:3333") {
		t.Logf("Expected '1111:3333' Ports: %v", configUser.PortSpecs)
		t.Fail()
	}
}
<|endoftext|>


<commit_before>package adeptus

import (
	"testing"
)

func Test_in(t *testing.T) {
	cases := []struct {
		in    string
		slice []string
		out   bool
	}{
		{
			in:    "",
			slice: []string{},
			out:   false,
		},
		{
			in:    "a",
			slice: []string{"b", "c"},
			out:   false,
		},
		{
			in:    "a",
			slice: []string{"a", "b", "c"},
			out:   true,
		},
	}

	for i, c := range cases {
		out := in(c.in, c.slice)
		if out != c.out {
			t.Logf("Unexpected output on case %d:", i+1)
			t.Logf("Expected %t", c.out)
			t.Logf("Having %t", out)
			t.Fail()
		}
	}
}
<commit_msg>Add more tests to the in() utility<commit_after>package adeptus

import (
	"testing"
)

func Test_in(t *testing.T) {
	cases := []struct {
		in    string
		slice []string
		out   bool
	}{
		{
			in:    "a",
			slice: []string{},
			out:   false,
		},
		{
			in:    "a",
			slice: []string{"b", "c"},
			out:   false,
		},
		{
			in:    "a",
			slice: []string{"a", "b", "c"},
			out:   true,
		},
		{
			in:    "b",
			slice: []string{"a", "b", "c"},
			out:   true,
		},
		{
			in:    "c",
			slice: []string{"a", "b", "c"},
			out:   true,
		},
		{
			in:    "d",
			slice: []string{"a", "b", "c"},
			out:   false,
		},
	}

	for i, c := range cases {
		out := in(c.in, c.slice)
		if out != c.out {
			t.Logf("Unexpected output on case %d:", i+1)
			t.Logf("Expected %t", c.out)
			t.Logf("Having %t", out)
			t.Fail()
		}
	}
}
<|endoftext|>


<commit_before>package midi

import (
	"bytes"
	"fmt"

	"gitlab.com/gomidi/midi/v2/internal/utils"
)

// Message is a complete midi message (not including meta messages)
type Message []byte

// Bytes returns the underlying bytes of the message.
func (m Message) Bytes() []byte {
	return []byte(m)
}

// IsPlayable returns, if the message can be send to an instrument.
func (m Message) IsPlayable() bool {
	if m.Type() <= UnknownMsg {
		return false
	}

	return m.Type() < firstMetaMsg
}

// IsOneOf returns true, if the message has one of the given types.
func (m Message) IsOneOf(checkers ...Type) bool {
	for _, checker := range checkers {
		if m.Is(checker) {
			return true
		}
	}
	return false
}

// Type returns the type of the message.
func (m Message) Type() Type {
	return getType(m)
}

// Is returns true, if the message is of the given type.
func (m Message) Is(t Type) bool {
	return m.Type().Is(t)
}

// GetNoteOn returns true if (and only if) the message is a NoteOnMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetNoteOn(channel, key, velocity *uint8) (is bool) {
	if !m.Is(NoteOnMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*key, *velocity = utils.ParseTwoUint7(m[1], m[2])
	return true
}

// GetNoteStart returns true if (and only if) the message is a NoteOnMsg with a velocity > 0.
// Then it also extracts the data to the given arguments.
func (m Message) GetNoteStart(channel, key, velocity *uint8) (is bool) {
	if !m.Is(NoteOnMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*key, *velocity = utils.ParseTwoUint7(m[1], m[2])
	if *velocity == 0 {
		return false
	}
	return true
}

// GetNoteOff returns true if (and only if) the message is a NoteOffMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetNoteOff(channel, key, velocity *uint8) (is bool) {
	if !m.Is(NoteOffMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*key, *velocity = utils.ParseTwoUint7(m[1], m[2])
	return true
}

// GetChannel returns true if (and only if) the message is a ChannelMsg.
// Then it also extracts the channel to the given argument.
func (m Message) GetChannel(channel *uint8) (is bool) {
	if !m.Is(ChannelMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	return true
}

// GetNoteEnd returns true if (and only if) the message is a NoteOnMsg with a velocity == 0 or a NoteOffMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetNoteEnd(channel, key *uint8) (is bool) {
	if !m.Is(NoteOnMsg) && !m.Is(NoteOffMsg) {
		return false
	}

	var velocity uint8

	_, *channel = utils.ParseStatus(m[0])
	*key, velocity = utils.ParseTwoUint7(m[1], m[2])
	return m.Is(NoteOffMsg) || velocity == 0
}

// GetPolyAfterTouch returns true if (and only if) the message is a PolyAfterTouchMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetPolyAfterTouch(channel, key, pressure *uint8) (is bool) {
	if !m.Is(PolyAfterTouchMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*key, *pressure = utils.ParseTwoUint7(m[1], m[2])
	return true
}

// GetAfterTouch returns true if (and only if) the message is a AfterTouchMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetAfterTouch(channel, pressure *uint8) (is bool) {
	if !m.Is(AfterTouchMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*pressure = utils.ParseUint7(m[1])
	return true
}

// GetProgramChange returns true if (and only if) the message is a ProgramChangeMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetProgramChange(channel, program *uint8) (is bool) {
	if !m.Is(ProgramChangeMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*program = utils.ParseUint7(m[1])
	return true
}

// GetPitchBend returns true if (and only if) the message is a PitchBendMsg.
// Then it also extracts the data to the given arguments.
// Either relative or absolute may be nil, if not needed.
func (m Message) GetPitchBend(channel *uint8, relative *int16, absolute *uint16) (is bool) {
	if !m.Is(PitchBendMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])

	rel, abs := utils.ParsePitchWheelVals(m[1], m[2])
	if relative != nil {
		*relative = rel
	}
	if absolute != nil {
		*absolute = abs
	}
	return true
}

// GetControlChange returns true if (and only if) the message is a ControlChangeMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetControlChange(channel, controller, value *uint8) (is bool) {
	if !m.Is(ControlChangeMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*controller, *value = utils.ParseTwoUint7(m[1], m[2])
	return true
}

/*
MTC Quarter Frame

These are the MTC (i.e. SMPTE based) equivalent of the F8 Timing Clock messages,
though offer much higher resolution, as they are sent at a rate of 96 to 120 times
a second (depending on the SMPTE frame rate). Each Quarter Frame message provides
partial timecode information, 8 sequential messages being required to fully
describe a timecode instant. The reconstituted timecode refers to when the first
partial was received. The most significant nibble of the data byte indicates the
partial (aka Message Type).

Partial	Data byte	Usage
1	0000 bcde	Frame number LSBs 	abcde = Frame number (0 to frameRate-1)
2	0001 000a	Frame number MSB
3	0010 cdef	Seconds LSBs 	abcdef = Seconds (0-59)
4	0011 00ab	Seconds MSBs
5	0100 cdef	Minutes LSBs 	abcdef = Minutes (0-59)
6	0101 00ab	Minutes MSBs
7	0110 defg	Hours LSBs 	ab = Frame Rate (00 = 24, 01 = 25, 10 = 30drop, 11 = 30nondrop)
cdefg = Hours (0-23)
8	0111 0abc	Frame Rate, and Hours MSB
*/

// GetMTC returns true if (and only if) the message is a MTCMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetMTC(quarterframe *uint8) (is bool) {
	if !m.Is(MTCMsg) {
		return false
	}

	*quarterframe = utils.ParseUint7(m[1])
	return true
}

// GetSongSelect returns true if (and only if) the message is a SongSelectMsg.
// Then it also extracts the song number to the given argument.
func (m Message) GetSongSelect(song *uint8) (is bool) {
	if !m.Is(SongSelectMsg) {
		return false
	}

	*song = utils.ParseUint7(m[1])
	return true
}

// GetSPP returns true if (and only if) the message is a SPPMsg.
// Then it also extracts the spp to the given argument.
func (m Message) GetSPP(spp *uint16) (is bool) {
	if !m.Is(SPPMsg) {
		return false
	}

	_, *spp = utils.ParsePitchWheelVals(m[2], m[1])
	return true
}

// String represents the Message as a string that contains the Type and its properties.
func (m Message) String() string {
	var bf bytes.Buffer
	fmt.Fprintf(&bf, m.Type().String())

	var channel, val1, val2 uint8
	var pitchabs uint16
	var pitchrel int16
	var spp uint16
	var sysex []byte

	switch {
	case m.GetNoteOn(&channel, &val1, &val2):
		fmt.Fprintf(&bf, " channel: %v key: %v velocity: %v", channel, val1, val2)
	case m.GetNoteOff(&channel, &val1, &val2):
		if val2 > 0 {
			fmt.Fprintf(&bf, " channel: %v key: %v velocity: %v", channel, val1, val2)
		} else {
			fmt.Fprintf(&bf, " channel: %v key: %v", channel, val1)
		}
	case m.GetPolyAfterTouch(&channel, &val1, &val2):
		fmt.Fprintf(&bf, " channel: %v key: %v pressure: %v", channel, val1, val2)
	case m.GetAfterTouch(&channel, &val1):
		fmt.Fprintf(&bf, " channel: %v pressure: %v", channel, val1)
	case m.GetControlChange(&channel, &val1, &val2):
		fmt.Fprintf(&bf, " channel: %v controller: %v value: %v", channel, val1, val2)
	case m.GetProgramChange(&channel, &val1):
		fmt.Fprintf(&bf, " channel: %v program: %v", channel, val1)
	case m.GetPitchBend(&channel, &pitchrel, &pitchabs):
		fmt.Fprintf(&bf, " channel: %v pitch: %v (%v)", channel, pitchrel, pitchabs)
	case m.GetMTC(&val1):
		fmt.Fprintf(&bf, " mtc: %v", val1)
	case m.GetSPP(&spp):
		fmt.Fprintf(&bf, " spp: %v", spp)
	case m.GetSongSelect(&val1):
		fmt.Fprintf(&bf, " song: %v", val1)
	case m.GetSysEx(&sysex):
		fmt.Fprintf(&bf, " data: % X", sysex)
	default:
	}

	return bf.String()
}

// GetSysEx returns true, if the message is a sysex message.
// Then it extracts the inner bytes to the given slice.
func (m Message) GetSysEx(bt *[]byte) bool {
	if len(m) < 3 {
		return false
	}

	if !m.Is(SysExMsg) {
		return false
	}

	if m[0] == 0xF0 && m[len(m)-1] == 0xF7 {
		*bt = m[1 : len(m)-1]
		return true
	}

	return false
}
<commit_msg>all to pass nil for velocity param when using GetNoteOff<commit_after>package midi

import (
	"bytes"
	"fmt"

	"gitlab.com/gomidi/midi/v2/internal/utils"
)

// Message is a complete midi message (not including meta messages)
type Message []byte

// Bytes returns the underlying bytes of the message.
func (m Message) Bytes() []byte {
	return []byte(m)
}

// IsPlayable returns, if the message can be send to an instrument.
func (m Message) IsPlayable() bool {
	if m.Type() <= UnknownMsg {
		return false
	}

	return m.Type() < firstMetaMsg
}

// IsOneOf returns true, if the message has one of the given types.
func (m Message) IsOneOf(checkers ...Type) bool {
	for _, checker := range checkers {
		if m.Is(checker) {
			return true
		}
	}
	return false
}

// Type returns the type of the message.
func (m Message) Type() Type {
	return getType(m)
}

// Is returns true, if the message is of the given type.
func (m Message) Is(t Type) bool {
	return m.Type().Is(t)
}

// GetNoteOn returns true if (and only if) the message is a NoteOnMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetNoteOn(channel, key, velocity *uint8) (is bool) {
	if !m.Is(NoteOnMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*key, *velocity = utils.ParseTwoUint7(m[1], m[2])
	return true
}

// GetNoteStart returns true if (and only if) the message is a NoteOnMsg with a velocity > 0.
// Then it also extracts the data to the given arguments.
func (m Message) GetNoteStart(channel, key, velocity *uint8) (is bool) {
	if !m.Is(NoteOnMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*key, *velocity = utils.ParseTwoUint7(m[1], m[2])
	if *velocity == 0 {
		return false
	}
	return true
}

// GetNoteOff returns true if (and only if) the message is a NoteOffMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetNoteOff(channel, key, velocity *uint8) (is bool) {
	if !m.Is(NoteOffMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	var vel uint8
	*key, vel = utils.ParseTwoUint7(m[1], m[2])
	if velocity != nil {
		*velocity = vel
	}
	return true
}

// GetChannel returns true if (and only if) the message is a ChannelMsg.
// Then it also extracts the channel to the given argument.
func (m Message) GetChannel(channel *uint8) (is bool) {
	if !m.Is(ChannelMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	return true
}

// GetNoteEnd returns true if (and only if) the message is a NoteOnMsg with a velocity == 0 or a NoteOffMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetNoteEnd(channel, key *uint8) (is bool) {
	if !m.Is(NoteOnMsg) && !m.Is(NoteOffMsg) {
		return false
	}

	var velocity uint8

	_, *channel = utils.ParseStatus(m[0])
	*key, velocity = utils.ParseTwoUint7(m[1], m[2])
	return m.Is(NoteOffMsg) || velocity == 0
}

// GetPolyAfterTouch returns true if (and only if) the message is a PolyAfterTouchMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetPolyAfterTouch(channel, key, pressure *uint8) (is bool) {
	if !m.Is(PolyAfterTouchMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*key, *pressure = utils.ParseTwoUint7(m[1], m[2])
	return true
}

// GetAfterTouch returns true if (and only if) the message is a AfterTouchMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetAfterTouch(channel, pressure *uint8) (is bool) {
	if !m.Is(AfterTouchMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*pressure = utils.ParseUint7(m[1])
	return true
}

// GetProgramChange returns true if (and only if) the message is a ProgramChangeMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetProgramChange(channel, program *uint8) (is bool) {
	if !m.Is(ProgramChangeMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*program = utils.ParseUint7(m[1])
	return true
}

// GetPitchBend returns true if (and only if) the message is a PitchBendMsg.
// Then it also extracts the data to the given arguments.
// Either relative or absolute may be nil, if not needed.
func (m Message) GetPitchBend(channel *uint8, relative *int16, absolute *uint16) (is bool) {
	if !m.Is(PitchBendMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])

	rel, abs := utils.ParsePitchWheelVals(m[1], m[2])
	if relative != nil {
		*relative = rel
	}
	if absolute != nil {
		*absolute = abs
	}
	return true
}

// GetControlChange returns true if (and only if) the message is a ControlChangeMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetControlChange(channel, controller, value *uint8) (is bool) {
	if !m.Is(ControlChangeMsg) {
		return false
	}

	_, *channel = utils.ParseStatus(m[0])
	*controller, *value = utils.ParseTwoUint7(m[1], m[2])
	return true
}

/*
MTC Quarter Frame

These are the MTC (i.e. SMPTE based) equivalent of the F8 Timing Clock messages,
though offer much higher resolution, as they are sent at a rate of 96 to 120 times
a second (depending on the SMPTE frame rate). Each Quarter Frame message provides
partial timecode information, 8 sequential messages being required to fully
describe a timecode instant. The reconstituted timecode refers to when the first
partial was received. The most significant nibble of the data byte indicates the
partial (aka Message Type).

Partial	Data byte	Usage
1	0000 bcde	Frame number LSBs 	abcde = Frame number (0 to frameRate-1)
2	0001 000a	Frame number MSB
3	0010 cdef	Seconds LSBs 	abcdef = Seconds (0-59)
4	0011 00ab	Seconds MSBs
5	0100 cdef	Minutes LSBs 	abcdef = Minutes (0-59)
6	0101 00ab	Minutes MSBs
7	0110 defg	Hours LSBs 	ab = Frame Rate (00 = 24, 01 = 25, 10 = 30drop, 11 = 30nondrop)
cdefg = Hours (0-23)
8	0111 0abc	Frame Rate, and Hours MSB
*/

// GetMTC returns true if (and only if) the message is a MTCMsg.
// Then it also extracts the data to the given arguments.
func (m Message) GetMTC(quarterframe *uint8) (is bool) {
	if !m.Is(MTCMsg) {
		return false
	}

	*quarterframe = utils.ParseUint7(m[1])
	return true
}

// GetSongSelect returns true if (and only if) the message is a SongSelectMsg.
// Then it also extracts the song number to the given argument.
func (m Message) GetSongSelect(song *uint8) (is bool) {
	if !m.Is(SongSelectMsg) {
		return false
	}

	*song = utils.ParseUint7(m[1])
	return true
}

// GetSPP returns true if (and only if) the message is a SPPMsg.
// Then it also extracts the spp to the given argument.
func (m Message) GetSPP(spp *uint16) (is bool) {
	if !m.Is(SPPMsg) {
		return false
	}

	_, *spp = utils.ParsePitchWheelVals(m[2], m[1])
	return true
}

// String represents the Message as a string that contains the Type and its properties.
func (m Message) String() string {
	var bf bytes.Buffer
	fmt.Fprintf(&bf, m.Type().String())

	var channel, val1, val2 uint8
	var pitchabs uint16
	var pitchrel int16
	var spp uint16
	var sysex []byte

	switch {
	case m.GetNoteOn(&channel, &val1, &val2):
		fmt.Fprintf(&bf, " channel: %v key: %v velocity: %v", channel, val1, val2)
	case m.GetNoteOff(&channel, &val1, &val2):
		if val2 > 0 {
			fmt.Fprintf(&bf, " channel: %v key: %v velocity: %v", channel, val1, val2)
		} else {
			fmt.Fprintf(&bf, " channel: %v key: %v", channel, val1)
		}
	case m.GetPolyAfterTouch(&channel, &val1, &val2):
		fmt.Fprintf(&bf, " channel: %v key: %v pressure: %v", channel, val1, val2)
	case m.GetAfterTouch(&channel, &val1):
		fmt.Fprintf(&bf, " channel: %v pressure: %v", channel, val1)
	case m.GetControlChange(&channel, &val1, &val2):
		fmt.Fprintf(&bf, " channel: %v controller: %v value: %v", channel, val1, val2)
	case m.GetProgramChange(&channel, &val1):
		fmt.Fprintf(&bf, " channel: %v program: %v", channel, val1)
	case m.GetPitchBend(&channel, &pitchrel, &pitchabs):
		fmt.Fprintf(&bf, " channel: %v pitch: %v (%v)", channel, pitchrel, pitchabs)
	case m.GetMTC(&val1):
		fmt.Fprintf(&bf, " mtc: %v", val1)
	case m.GetSPP(&spp):
		fmt.Fprintf(&bf, " spp: %v", spp)
	case m.GetSongSelect(&val1):
		fmt.Fprintf(&bf, " song: %v", val1)
	case m.GetSysEx(&sysex):
		fmt.Fprintf(&bf, " data: % X", sysex)
	default:
	}

	return bf.String()
}

// GetSysEx returns true, if the message is a sysex message.
// Then it extracts the inner bytes to the given slice.
func (m Message) GetSysEx(bt *[]byte) bool {
	if len(m) < 3 {
		return false
	}

	if !m.Is(SysExMsg) {
		return false
	}

	if m[0] == 0xF0 && m[len(m)-1] == 0xF7 {
		*bt = m[1 : len(m)-1]
		return true
	}

	return false
}
<|endoftext|>


<commit_before>// Package config contains the model and loader of the goreleaser configuration
// file.
package config

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/apex/log"
	yaml "gopkg.in/yaml.v2"
)

// Repo represents any kind of repo (github, gitlab, etc)
type Repo struct {
	Owner string `yaml:",omitempty"`
	Name  string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// String of the repo, e.g. owner/name
func (r Repo) String() string {
	return r.Owner + "/" + r.Name
}

// Homebrew contains the brew section
type Homebrew struct {
	GitHub       Repo     `yaml:",omitempty"`
	Folder       string   `yaml:",omitempty"`
	Caveats      string   `yaml:",omitempty"`
	Plist        string   `yaml:",omitempty"`
	Install      string   `yaml:",omitempty"`
	Dependencies []string `yaml:",omitempty"`
	Test         string   `yaml:",omitempty"`
	Conflicts    []string `yaml:",omitempty"`
	Description  string   `yaml:",omitempty"`
	Homepage     string   `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Hooks define actions to run before and/or after something
type Hooks struct {
	Pre  string `yaml:",omitempty"`
	Post string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// IgnoredBuild represents a build ignored by the user
type IgnoredBuild struct {
	Goos, Goarch, Goarm string

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Build contains the build configuration section
type Build struct {
	Goos    []string       `yaml:",omitempty"`
	Goarch  []string       `yaml:",omitempty"`
	Goarm   []string       `yaml:",omitempty"`
	Ignore  []IgnoredBuild `yaml:",omitempty"`
	Main    string         `yaml:",omitempty"`
	Ldflags string         `yaml:",omitempty"`
	Flags   string         `yaml:",omitempty"`
	Binary  string         `yaml:",omitempty"`
	Hooks   Hooks          `yaml:",omitempty"`
	Env     []string       `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// FormatOverride is used to specify a custom format for a specific GOOS.
type FormatOverride struct {
	Goos   string `yaml:",omitempty"`
	Format string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Archive config used for the archive
type Archive struct {
	Format          string            `yaml:",omitempty"`
	FormatOverrides []FormatOverride  `yaml:"format_overrides,omitempty"`
	NameTemplate    string            `yaml:"name_template,omitempty"`
	Replacements    map[string]string `yaml:",omitempty"`
	Files           []string          `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Release config used for the GitHub release
type Release struct {
	GitHub Repo `yaml:",omitempty"`
	Draft  bool `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// FPM config
type FPM struct {
	Formats      []string `yaml:",omitempty"`
	Dependencies []string `yaml:",omitempty"`
	Conflicts    []string `yaml:",omitempty"`
	Vendor       string   `yaml:",omitempty"`
	Homepage     string   `yaml:",omitempty"`
	Maintainer   string   `yaml:",omitempty"`
	Description  string   `yaml:",omitempty"`
	License      string   `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// AppsMetadata for the binaries that will be in the snap package
type SnapcraftAppMetadata struct {
	Plugs  []string
	Daemon string
}

// Snapcraft config
type Snapcraft struct {
	Summary     string                          `yaml:",omitempty"`
	Description string                          `yaml:",omitempty"`
	Grade       string                          `yaml:",omitempty"`
	Confinement string                          `yaml:",omitempty"`
	Apps        map[string]SnapcraftAppMetadata `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Snapshot config
type Snapshot struct {
	NameTemplate string `yaml:"name_template,omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Project includes all project configuration
type Project struct {
	ProjectName string    `yaml:"project_name,omitempty"`
	Release     Release   `yaml:",omitempty"`
	Brew        Homebrew  `yaml:",omitempty"`
	Builds      []Build   `yaml:",omitempty"`
	Archive     Archive   `yaml:",omitempty"`
	FPM         FPM       `yaml:",omitempty"`
	Snapcraft   Snapcraft `yaml:",omitempty"`
	Snapshot    Snapshot  `yaml:",omitempty"`

	// this is a hack ¯\_(ツ)_/¯
	SingleBuild Build `yaml:"build,omitempty"`

	// test only property indicating the path to the dist folder
	Dist string `yaml:"-"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Load config file
func Load(file string) (config Project, err error) {
	f, err := os.Open(file)
	if err != nil {
		return
	}
	log.WithField("file", file).Info("loading config file")
	return LoadReader(f)
}

// LoadReader config via io.Reader
func LoadReader(fd io.Reader) (config Project, err error) {
	data, err := ioutil.ReadAll(fd)
	if err != nil {
		return config, err
	}
	if err := yaml.Unmarshal(data, &config); err != nil {
		return config, err
	}
	log.WithField("config", config).Debug("loaded config file")
	return config, checkOverflows(config)
}

func checkOverflows(config Project) error {
	var checker = &overflowChecker{}
	checker.check(config.XXX, "")
	checker.check(config.Archive.XXX, "archive")
	for i, ov := range config.Archive.FormatOverrides {
		checker.check(ov.XXX, fmt.Sprintf("archive.format_overrides[%d]", i))
	}
	checker.check(config.Brew.XXX, "brew")
	checker.check(config.Brew.GitHub.XXX, "brew.github")
	for i, build := range config.Builds {
		checker.check(build.XXX, fmt.Sprintf("builds[%d]", i))
		checker.check(build.Hooks.XXX, fmt.Sprintf("builds[%d].hooks", i))
		for j, ignored := range build.Ignore {
			checker.check(ignored.XXX, fmt.Sprintf("builds[%d].ignored_builds[%d]", i, j))
		}
	}
	checker.check(config.FPM.XXX, "fpm")
	checker.check(config.Snapcraft.XXX, "snapcraft")
	checker.check(config.Release.XXX, "release")
	checker.check(config.Release.GitHub.XXX, "release.github")
	checker.check(config.SingleBuild.XXX, "build")
	checker.check(config.SingleBuild.Hooks.XXX, "builds.hooks")
	for i, ignored := range config.SingleBuild.Ignore {
		checker.check(ignored.XXX, fmt.Sprintf("builds.ignored_builds[%d]", i))
	}
	checker.check(config.Snapshot.XXX, "snapshot")
	return checker.err()
}

type overflowChecker struct {
	fields []string
}

func (o *overflowChecker) check(m map[string]interface{}, ctx string) {
	for k := range m {
		var key = fmt.Sprintf("%s.%s", ctx, k)
		if ctx == "" {
			key = k
		}
		o.fields = append(o.fields, key)
	}
}

func (o *overflowChecker) err() error {
	if len(o.fields) == 0 {
		return nil
	}
	return fmt.Errorf(
		"unknown fields in the config file: %s",
		strings.Join(o.fields, ", "),
	)
}
<commit_msg>fix the comment<commit_after>// Package config contains the model and loader of the goreleaser configuration
// file.
package config

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/apex/log"
	yaml "gopkg.in/yaml.v2"
)

// Repo represents any kind of repo (github, gitlab, etc)
type Repo struct {
	Owner string `yaml:",omitempty"`
	Name  string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// String of the repo, e.g. owner/name
func (r Repo) String() string {
	return r.Owner + "/" + r.Name
}

// Homebrew contains the brew section
type Homebrew struct {
	GitHub       Repo     `yaml:",omitempty"`
	Folder       string   `yaml:",omitempty"`
	Caveats      string   `yaml:",omitempty"`
	Plist        string   `yaml:",omitempty"`
	Install      string   `yaml:",omitempty"`
	Dependencies []string `yaml:",omitempty"`
	Test         string   `yaml:",omitempty"`
	Conflicts    []string `yaml:",omitempty"`
	Description  string   `yaml:",omitempty"`
	Homepage     string   `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Hooks define actions to run before and/or after something
type Hooks struct {
	Pre  string `yaml:",omitempty"`
	Post string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// IgnoredBuild represents a build ignored by the user
type IgnoredBuild struct {
	Goos, Goarch, Goarm string

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Build contains the build configuration section
type Build struct {
	Goos    []string       `yaml:",omitempty"`
	Goarch  []string       `yaml:",omitempty"`
	Goarm   []string       `yaml:",omitempty"`
	Ignore  []IgnoredBuild `yaml:",omitempty"`
	Main    string         `yaml:",omitempty"`
	Ldflags string         `yaml:",omitempty"`
	Flags   string         `yaml:",omitempty"`
	Binary  string         `yaml:",omitempty"`
	Hooks   Hooks          `yaml:",omitempty"`
	Env     []string       `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// FormatOverride is used to specify a custom format for a specific GOOS.
type FormatOverride struct {
	Goos   string `yaml:",omitempty"`
	Format string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Archive config used for the archive
type Archive struct {
	Format          string            `yaml:",omitempty"`
	FormatOverrides []FormatOverride  `yaml:"format_overrides,omitempty"`
	NameTemplate    string            `yaml:"name_template,omitempty"`
	Replacements    map[string]string `yaml:",omitempty"`
	Files           []string          `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Release config used for the GitHub release
type Release struct {
	GitHub Repo `yaml:",omitempty"`
	Draft  bool `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// FPM config
type FPM struct {
	Formats      []string `yaml:",omitempty"`
	Dependencies []string `yaml:",omitempty"`
	Conflicts    []string `yaml:",omitempty"`
	Vendor       string   `yaml:",omitempty"`
	Homepage     string   `yaml:",omitempty"`
	Maintainer   string   `yaml:",omitempty"`
	Description  string   `yaml:",omitempty"`
	License      string   `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// SnapcraftAppMetadata for the binaries that will be in the snap package
type SnapcraftAppMetadata struct {
	Plugs  []string
	Daemon string
}

// Snapcraft config
type Snapcraft struct {
	Summary     string                          `yaml:",omitempty"`
	Description string                          `yaml:",omitempty"`
	Grade       string                          `yaml:",omitempty"`
	Confinement string                          `yaml:",omitempty"`
	Apps        map[string]SnapcraftAppMetadata `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Snapshot config
type Snapshot struct {
	NameTemplate string `yaml:"name_template,omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Project includes all project configuration
type Project struct {
	ProjectName string    `yaml:"project_name,omitempty"`
	Release     Release   `yaml:",omitempty"`
	Brew        Homebrew  `yaml:",omitempty"`
	Builds      []Build   `yaml:",omitempty"`
	Archive     Archive   `yaml:",omitempty"`
	FPM         FPM       `yaml:",omitempty"`
	Snapcraft   Snapcraft `yaml:",omitempty"`
	Snapshot    Snapshot  `yaml:",omitempty"`

	// this is a hack ¯\_(ツ)_/¯
	SingleBuild Build `yaml:"build,omitempty"`

	// test only property indicating the path to the dist folder
	Dist string `yaml:"-"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Load config file
func Load(file string) (config Project, err error) {
	f, err := os.Open(file)
	if err != nil {
		return
	}
	log.WithField("file", file).Info("loading config file")
	return LoadReader(f)
}

// LoadReader config via io.Reader
func LoadReader(fd io.Reader) (config Project, err error) {
	data, err := ioutil.ReadAll(fd)
	if err != nil {
		return config, err
	}
	if err := yaml.Unmarshal(data, &config); err != nil {
		return config, err
	}
	log.WithField("config", config).Debug("loaded config file")
	return config, checkOverflows(config)
}

func checkOverflows(config Project) error {
	var checker = &overflowChecker{}
	checker.check(config.XXX, "")
	checker.check(config.Archive.XXX, "archive")
	for i, ov := range config.Archive.FormatOverrides {
		checker.check(ov.XXX, fmt.Sprintf("archive.format_overrides[%d]", i))
	}
	checker.check(config.Brew.XXX, "brew")
	checker.check(config.Brew.GitHub.XXX, "brew.github")
	for i, build := range config.Builds {
		checker.check(build.XXX, fmt.Sprintf("builds[%d]", i))
		checker.check(build.Hooks.XXX, fmt.Sprintf("builds[%d].hooks", i))
		for j, ignored := range build.Ignore {
			checker.check(ignored.XXX, fmt.Sprintf("builds[%d].ignored_builds[%d]", i, j))
		}
	}
	checker.check(config.FPM.XXX, "fpm")
	checker.check(config.Snapcraft.XXX, "snapcraft")
	checker.check(config.Release.XXX, "release")
	checker.check(config.Release.GitHub.XXX, "release.github")
	checker.check(config.SingleBuild.XXX, "build")
	checker.check(config.SingleBuild.Hooks.XXX, "builds.hooks")
	for i, ignored := range config.SingleBuild.Ignore {
		checker.check(ignored.XXX, fmt.Sprintf("builds.ignored_builds[%d]", i))
	}
	checker.check(config.Snapshot.XXX, "snapshot")
	return checker.err()
}

type overflowChecker struct {
	fields []string
}

func (o *overflowChecker) check(m map[string]interface{}, ctx string) {
	for k := range m {
		var key = fmt.Sprintf("%s.%s", ctx, k)
		if ctx == "" {
			key = k
		}
		o.fields = append(o.fields, key)
	}
}

func (o *overflowChecker) err() error {
	if len(o.fields) == 0 {
		return nil
	}
	return fmt.Errorf(
		"unknown fields in the config file: %s",
		strings.Join(o.fields, ", "),
	)
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"path"
)

type Config struct {
	ConfigDir string
}

type Context struct {
	Network string
	Target  string
	Source  string
}

var C Config

func lookupvar(key, path string) interface{} {
	var f interface{}
	_, err := os.Stat(path)
	if err != nil {
		return nil
	}

	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil
	}

	err = json.Unmarshal(data, &f)

	return f.(map[string]interface{})[key]
}

func (c *Config) Lookup(context Context, key string) interface{} {
	var fpath string
	var value interface{}
	if context.Network != "" {
		if context.Source != "" {
			if context.Target != "" {
				fpath = path.Join(c.ConfigDir, context.Network, context.Source, context.Target+".json")

				log.Println("Context:", context, "Looking up", key, "in", fpath)
				value = lookupvar(key, fpath)
				if value != nil {
					log.Println("Context:", context, "Found", key, value)
					return value
				}
			}

			fpath = path.Join(c.ConfigDir, context.Network, context.Source+".json")

			log.Println("Context:", context, "Looking up", key, "in", fpath)
			value = lookupvar(key, fpath)
			if value != nil {
				log.Println("Context:", context, "Found", key, value)
				return value
			}
		}

		fpath = path.Join(c.ConfigDir, context.Network+".json")

		log.Println("Context:", context, "Looking up", key, "in", fpath)
		value = lookupvar(key, fpath)
		if value != nil {
			log.Println("Context:", context, "Found", key, value)
			return value
		}
	}

	fpath = path.Join(c.ConfigDir, "common.json")

	log.Println("Context:", context, "Looking up", key, "in", fpath)
	value = lookupvar(key, fpath)
	if value != nil {
		log.Println("Context:", context, "Found", key, value)
		return value
	} else {
		log.Println("Key", key, "not found")
		return nil
	}
}
<commit_msg>Partial implementation of configuration cache<commit_after>package config

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"path"
	"time"
)

type cacheEntry struct {
	ModTime  time.Time
	Contents interface{}
}

type Config struct {
	ConfigDir string
	Cache     map[string]cacheEntry
}

type Context struct {
	Network string
	Target  string
	Source  string
}

var C Config

func lookupvar(key, path string) interface{} {
	var f interface{}
	i, err := os.Stat(path)
	if err != nil {
		return nil
	}

	_, ok := C.Cache[path]
	if C.Cache[path].ModTime.Before(i.ModTime()) || !ok {
		log.Println("Stale cache for", path)
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return nil
		}

		err = json.Unmarshal(data, &f)
		if err != nil {
			log.Println("Cannot parse", path)
			return nil
		}

		log.Println("Updating cache for", path)
		C.Cache[path] = cacheEntry{
			ModTime:  i.ModTime(),
			Contents: f,
		}

		return f.(map[string]interface{})[key]
	} else {
		log.Println("Found cache for", path)
		return C.Cache[path].Contents.(map[string]interface{})[key]
	}
}

func (c *Config) Lookup(context Context, key string) interface{} {
	var fpath string
	var value interface{}
	if context.Network != "" {
		if context.Source != "" {
			if context.Target != "" {
				fpath = path.Join(c.ConfigDir, context.Network, context.Source, context.Target+".json")

				log.Println("Context:", context, "Looking up", key, "in", fpath)
				value = lookupvar(key, fpath)
				if value != nil {
					log.Println("Context:", context, "Found", key, value)
					return value
				}
			}

			fpath = path.Join(c.ConfigDir, context.Network, context.Source+".json")

			log.Println("Context:", context, "Looking up", key, "in", fpath)
			value = lookupvar(key, fpath)
			if value != nil {
				log.Println("Context:", context, "Found", key, value)
				return value
			}
		}

		fpath = path.Join(c.ConfigDir, context.Network+".json")

		log.Println("Context:", context, "Looking up", key, "in", fpath)
		value = lookupvar(key, fpath)
		if value != nil {
			log.Println("Context:", context, "Found", key, value)
			return value
		}
	}

	fpath = path.Join(c.ConfigDir, "common.json")

	log.Println("Context:", context, "Looking up", key, "in", fpath)
	value = lookupvar(key, fpath)
	if value != nil {
		log.Println("Context:", context, "Found", key, value)
		return value
	} else {
		log.Println("Key", key, "not found")
		return nil
	}
}
<|endoftext|>


<commit_before>/*
	config loads and understands the tegola config format.
*/
package config

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strings"
	"syscall"
	"time"

	"github.com/BurntSushi/toml"

	"github.com/go-spatial/tegola/internal/log"
)

// Config represents a tegola config file.
type Config struct {
	//	the tile buffer to use
	TileBuffer int64 `toml:"tile_buffer"`
	// LocationName is the file name or http server that the config was read from.
	// If this is an empty string, it means that the location was unknown. This is the case if
	// the Parse() function is used directly.
	LocationName string
	Webserver    Webserver              `toml:"webserver"`
	Cache        map[string]interface{} `toml:"cache"`
	// Map of providers.
	Providers []map[string]interface{}
	Maps      []Map
}

type Webserver struct {
	HostName          string `toml:"hostname"`
	Port              string `toml:"port"`
	CORSAllowedOrigin string `toml:"cors_allowed_origin"`
}

// A Map represents a map in the Tegola Config file.
type Map struct {
	Name        string     `toml:"name"`
	Attribution string     `toml:"attribution"`
	Bounds      []float64  `toml:"bounds"`
	Center      [3]float64 `toml:"center"`
	Layers      []MapLayer `toml:"layers"`
}

type MapLayer struct {
	//	Name is optional. If it's not defined the name of the ProviderLayer will be used.
	//	Name can also be used to group multiple ProviderLayers under the same namespace.
	Name          string      `toml:"name"`
	ProviderLayer string      `toml:"provider_layer"`
	MinZoom       *uint        `toml:"min_zoom"`
	MaxZoom       *uint        `toml:"max_zoom"`
	DefaultTags   interface{} `toml:"default_tags"`
	//	DontSimplify indicates wheather feature simplification should be applied.
	//	We use a negative in the name so the default is to simplify
	DontSimplify bool `toml:"dont_simplify"`
}

//	checks the config for issues
func (c *Config) Validate() error {

	//	check for map layer name / zoom collisions
	//	map of layers to providers
	mapLayers := map[string]map[string]MapLayer{}
	for _, m := range c.Maps {
		if _, ok := mapLayers[m.Name]; !ok {
			mapLayers[m.Name] = map[string]MapLayer{}
		}

		for _, l := range m.Layers {
			var name string

			if l.Name != "" {
				name = l.Name
			} else {
				//	split the provider layer (syntax is provider.layer)
				plParts := strings.Split(l.ProviderLayer, ".")
				if len(plParts) != 2 {
					return ErrInvalidProviderLayerName{
						ProviderLayerName: l.ProviderLayer,
					}
				}

				name = plParts[1]
			}

			//	check if we already have this layer
			if val, ok := mapLayers[m.Name][name]; ok {
				//	we have a hit. check for zoom range overlap
				if *val.MinZoom <= *l.MaxZoom && *l.MinZoom <= *val.MaxZoom {
					return ErrOverlappingLayerZooms{
						ProviderLayer1: val.ProviderLayer,
						ProviderLayer2: l.ProviderLayer,
					}
				}
				continue
			}

			//	add the MapLayer to our map
			mapLayers[m.Name][name] = l
		}
	}

	return nil
}

// Parse will parse the Tegola config file provided by the io.Reader.
func Parse(reader io.Reader, location string) (conf Config, err error) {
	//	decode conf file, don't care about the meta data.
	_, err = toml.DecodeReader(reader, &conf)
	conf.LocationName = location

	return conf, err
}

// replaceEnvVars replaces environment variable placeholders in reader stream with values
// i.e. "val = $VAR" -> "val = 3"
func replaceEnvVars(reader io.Reader) (io.Reader, error) {
	// Variable definition follows IEEE Std 1003.1-2001
	//   A dollar sign ($) followed by an upper-case letter, followed by
	//   zero or more upper-case letters, digits, or underscores (_).
	varNameRegexStr := `[A-Z]+[A-Z1-9_]*`
	// Var prepended by dollar sign ($)
	// Ex: $MY_VAR7
	regexStrDS := fmt.Sprintf(`\$%v`, varNameRegexStr)
	// Additionally, match a variable surrounded by curly braces with leading dollar sign.
	// Ex: ${MY_VAR7}
	regexStrBraces := fmt.Sprintf(`\$\{%v\}`, varNameRegexStr)

	// Regex to capture either syntax
	regexStr := fmt.Sprintf("(%v|%v)", regexStrDS, regexStrBraces)
	varFinder := regexp.MustCompile(regexStr)

	configBytes, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}

	configStr := string(configBytes)

	// Grab the regular & braced placeholders
	varPlaceHolders := varFinder.FindAllString(configStr, -1)

	varNameFinder := regexp.MustCompile(varNameRegexStr)

	for _, ph := range varPlaceHolders {
		// Get the environment variable value (drop the leading dollar sign ($) and surrounding braces ({}))
		varName := varNameFinder.FindString(ph)
		envVal, found := syscall.Getenv(varName)
		if !found {
			return nil, ErrMissingEnvVar{
				EnvVar: varName,
			}
		}

		// Explicit string replacement, no need for regex funny business any longer.
		configStr = strings.Replace(configStr, ph, envVal, -1)
	}

	return strings.NewReader(configStr), nil
}

// Load will load and parse the config file from the given location.
func Load(location string) (conf Config, err error) {
	var reader io.Reader

	//	check for http prefix
	if strings.HasPrefix(location, "http") {
		log.Infof("loading remote config (%v)", location)

		//	setup http client with a timeout
		var httpClient = &http.Client{
			Timeout: time.Second * 10,
		}

		//	make the http request
		res, err := httpClient.Get(location)
		if err != nil {
			return conf, fmt.Errorf("error fetching remote config file (%v): %v ", location, err)
		}

		//	set the reader to the response body
		reader = res.Body
	} else {
		log.Infof("loading local config (%v)", location)

		//	check the conf file exists
		if _, err := os.Stat(location); os.IsNotExist(err) {
			return conf, fmt.Errorf("config file at location (%v) not found!", location)
		}
		//	open the confi file
		reader, err = os.Open(location)
		if err != nil {
			return conf, fmt.Errorf("error opening local config file (%v): %v ", location, err)
		}
	}

	reader, err = replaceEnvVars(reader)
	if err != nil {
		return conf, err
	}

	return Parse(reader, location)
}

func LoadAndValidate(filename string) (cfg Config, err error) {
	cfg, err = Load(filename)
	if err != nil {
		return cfg, err
	}
	// validate our config
	return cfg, cfg.Validate()
}
<commit_msg>implemented default values for max_zoom and min_zoom<commit_after>/*
	config loads and understands the tegola config format.
*/
package config

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strings"
	"syscall"
	"time"

	"github.com/BurntSushi/toml"

	"github.com/go-spatial/tegola/internal/log"
	"github.com/go-spatial/tegola"
)

// Config represents a tegola config file.
type Config struct {
	//	the tile buffer to use
	TileBuffer int64 `toml:"tile_buffer"`
	// LocationName is the file name or http server that the config was read from.
	// If this is an empty string, it means that the location was unknown. This is the case if
	// the Parse() function is used directly.
	LocationName string
	Webserver    Webserver              `toml:"webserver"`
	Cache        map[string]interface{} `toml:"cache"`
	// Map of providers.
	Providers []map[string]interface{}
	Maps      []Map
}

type Webserver struct {
	HostName          string `toml:"hostname"`
	Port              string `toml:"port"`
	CORSAllowedOrigin string `toml:"cors_allowed_origin"`
}

// A Map represents a map in the Tegola Config file.
type Map struct {
	Name        string     `toml:"name"`
	Attribution string     `toml:"attribution"`
	Bounds      []float64  `toml:"bounds"`
	Center      [3]float64 `toml:"center"`
	Layers      []MapLayer `toml:"layers"`
}

type MapLayer struct {
	//	Name is optional. If it's not defined the name of the ProviderLayer will be used.
	//	Name can also be used to group multiple ProviderLayers under the same namespace.
	Name          string      `toml:"name"`
	ProviderLayer string      `toml:"provider_layer"`
	MinZoom       *uint        `toml:"min_zoom"`
	MaxZoom       *uint        `toml:"max_zoom"`
	DefaultTags   interface{} `toml:"default_tags"`
	//	DontSimplify indicates wheather feature simplification should be applied.
	//	We use a negative in the name so the default is to simplify
	DontSimplify bool `toml:"dont_simplify"`
}

//	checks the config for issues
func (c *Config) Validate() error {

	//	check for map layer name / zoom collisions
	//	map of layers to providers
	mapLayers := map[string]map[string]MapLayer{}
	for _, m := range c.Maps {
		if _, ok := mapLayers[m.Name]; !ok {
			mapLayers[m.Name] = map[string]MapLayer{}
		}

		for _, l := range m.Layers {
			var name string

			if l.Name != "" {
				name = l.Name
			} else {
				//	split the provider layer (syntax is provider.layer)
				plParts := strings.Split(l.ProviderLayer, ".")
				if len(plParts) != 2 {
					return ErrInvalidProviderLayerName{
						ProviderLayerName: l.ProviderLayer,
					}
				}

				name = plParts[1]
			}

			// MaxZoom default
			if l.MaxZoom == nil {
				ph := uint(tegola.MaxZ)
				l.MaxZoom = &ph
			}
			// MinZoom default
			if l.MinZoom == nil {
				ph := uint(tegola.MaxZ)
				l.MinZoom = &ph
			}

			//	check if we already have this layer
			if val, ok := mapLayers[m.Name][name]; ok {
				//	we have a hit. check for zoom range overlap
				if *val.MinZoom <= *l.MaxZoom && *l.MinZoom <= *val.MaxZoom {
					return ErrOverlappingLayerZooms{
						ProviderLayer1: val.ProviderLayer,
						ProviderLayer2: l.ProviderLayer,
					}
				}
				continue
			}

			//	add the MapLayer to our map
			mapLayers[m.Name][name] = l
		}
	}

	return nil
}

// Parse will parse the Tegola config file provided by the io.Reader.
func Parse(reader io.Reader, location string) (conf Config, err error) {
	//	decode conf file, don't care about the meta data.
	_, err = toml.DecodeReader(reader, &conf)
	conf.LocationName = location

	return conf, err
}

// replaceEnvVars replaces environment variable placeholders in reader stream with values
// i.e. "val = $VAR" -> "val = 3"
func replaceEnvVars(reader io.Reader) (io.Reader, error) {
	// Variable definition follows IEEE Std 1003.1-2001
	//   A dollar sign ($) followed by an upper-case letter, followed by
	//   zero or more upper-case letters, digits, or underscores (_).
	varNameRegexStr := `[A-Z]+[A-Z1-9_]*`
	// Var prepended by dollar sign ($)
	// Ex: $MY_VAR7
	regexStrDS := fmt.Sprintf(`\$%v`, varNameRegexStr)
	// Additionally, match a variable surrounded by curly braces with leading dollar sign.
	// Ex: ${MY_VAR7}
	regexStrBraces := fmt.Sprintf(`\$\{%v\}`, varNameRegexStr)

	// Regex to capture either syntax
	regexStr := fmt.Sprintf("(%v|%v)", regexStrDS, regexStrBraces)
	varFinder := regexp.MustCompile(regexStr)

	configBytes, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}

	configStr := string(configBytes)

	// Grab the regular & braced placeholders
	varPlaceHolders := varFinder.FindAllString(configStr, -1)

	varNameFinder := regexp.MustCompile(varNameRegexStr)

	for _, ph := range varPlaceHolders {
		// Get the environment variable value (drop the leading dollar sign ($) and surrounding braces ({}))
		varName := varNameFinder.FindString(ph)
		envVal, found := syscall.Getenv(varName)
		if !found {
			return nil, ErrMissingEnvVar{
				EnvVar: varName,
			}
		}

		// Explicit string replacement, no need for regex funny business any longer.
		configStr = strings.Replace(configStr, ph, envVal, -1)
	}

	return strings.NewReader(configStr), nil
}

// Load will load and parse the config file from the given location.
func Load(location string) (conf Config, err error) {
	var reader io.Reader

	//	check for http prefix
	if strings.HasPrefix(location, "http") {
		log.Infof("loading remote config (%v)", location)

		//	setup http client with a timeout
		var httpClient = &http.Client{
			Timeout: time.Second * 10,
		}

		//	make the http request
		res, err := httpClient.Get(location)
		if err != nil {
			return conf, fmt.Errorf("error fetching remote config file (%v): %v ", location, err)
		}

		//	set the reader to the response body
		reader = res.Body
	} else {
		log.Infof("loading local config (%v)", location)

		//	check the conf file exists
		if _, err := os.Stat(location); os.IsNotExist(err) {
			return conf, fmt.Errorf("config file at location (%v) not found!", location)
		}
		//	open the confi file
		reader, err = os.Open(location)
		if err != nil {
			return conf, fmt.Errorf("error opening local config file (%v): %v ", location, err)
		}
	}

	reader, err = replaceEnvVars(reader)
	if err != nil {
		return conf, err
	}

	return Parse(reader, location)
}

func LoadAndValidate(filename string) (cfg Config, err error) {
	cfg, err = Load(filename)
	if err != nil {
		return cfg, err
	}
	// validate our config
	return cfg, cfg.Validate()
}
<|endoftext|>