<commit_before>package radix

import (
	"log"
	"strconv"
	. "testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestScanner(t *T) {
	c := dial()

	// Make a random dataset
	prefix := randStr()
	fullMap := map[string]bool{}
	for i := 0; i < 100; i++ {
		key := prefix + ":" + strconv.Itoa(i)
		fullMap[key] = true
		require.Nil(t, c.Do(Cmd(nil, "SET", key, "1")))
	}

	// make sure we get all results when scanning with an existing prefix
	sc := NewScanner(c, ScanOpts{Command: "SCAN", Pattern: prefix + ":*"})
	var key string
	for sc.Next(&key) {
		delete(fullMap, key)
	}
	require.Nil(t, sc.Close())
	assert.Empty(t, fullMap)

	// make sure we don't get any results when scanning with a non-existing
	// prefix
	sc = NewScanner(c, ScanOpts{Command: "SCAN", Pattern: prefix + "DNE:*"})
	assert.False(t, sc.Next(nil))
	require.Nil(t, sc.Close())
}

// Similar to TestScanner, but scans over a set instead of the whole key space
func TestScannerSet(t *T) {
	c := dial()

	key := randStr()
	fullMap := map[string]bool{}
	for i := 0; i < 100; i++ {
		elem := strconv.Itoa(i)
		fullMap[elem] = true
		require.Nil(t, c.Do(Cmd(nil, "SADD", key, elem)))
	}

	// make sure we get all results when scanning an existing set
	sc := NewScanner(c, ScanOpts{Command: "SSCAN", Key: key})
	var val string
	for sc.Next(&val) {
		delete(fullMap, val)
	}
	require.Nil(t, sc.Close())
	assert.Empty(t, fullMap)

	// make sure we don't get any results when scanning a non-existent set
	sc = NewScanner(c, ScanOpts{Command: "SSCAN", Key: key + "DNE"})
	assert.False(t, sc.Next(nil))
	require.Nil(t, sc.Close())
}

func ExampleNewScanner_scan() {
	client, err := DefaultClientFunc("tcp", "126.0.0.1:6379")
	if err != nil {
		log.Fatal(err)
	}

	s := NewScanner(client, ScanAllKeys)
	var key string
	for s.Next(&key) {
		log.Printf("key: %q", key)
	}
	if err := s.Close(); err != nil {
		log.Fatal(err)
	}
}

func ExampleNewScanner_hscan() {
	client, err := DefaultClientFunc("tcp", "126.0.0.1:6379")
	if err != nil {
		log.Fatal(err)
	}

	s := NewScanner(client, ScanOpts{Command: "HSCAN", Key: "somekey"})
	var key string
	for s.Next(&key) {
		log.Printf("key: %q", key)
	}
	if err := s.Close(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Add a benchmark for Scanner<commit_after>package radix

import (
	"log"
	"strconv"
	. "testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestScanner(t *T) {
	c := dial()

	// Make a random dataset
	prefix := randStr()
	fullMap := map[string]bool{}
	for i := 0; i < 100; i++ {
		key := prefix + ":" + strconv.Itoa(i)
		fullMap[key] = true
		require.Nil(t, c.Do(Cmd(nil, "SET", key, "1")))
	}

	// make sure we get all results when scanning with an existing prefix
	sc := NewScanner(c, ScanOpts{Command: "SCAN", Pattern: prefix + ":*"})
	var key string
	for sc.Next(&key) {
		delete(fullMap, key)
	}
	require.Nil(t, sc.Close())
	assert.Empty(t, fullMap)

	// make sure we don't get any results when scanning with a non-existing
	// prefix
	sc = NewScanner(c, ScanOpts{Command: "SCAN", Pattern: prefix + "DNE:*"})
	assert.False(t, sc.Next(nil))
	require.Nil(t, sc.Close())
}

// Similar to TestScanner, but scans over a set instead of the whole key space
func TestScannerSet(t *T) {
	c := dial()

	key := randStr()
	fullMap := map[string]bool{}
	for i := 0; i < 100; i++ {
		elem := strconv.Itoa(i)
		fullMap[elem] = true
		require.Nil(t, c.Do(Cmd(nil, "SADD", key, elem)))
	}

	// make sure we get all results when scanning an existing set
	sc := NewScanner(c, ScanOpts{Command: "SSCAN", Key: key})
	var val string
	for sc.Next(&val) {
		delete(fullMap, val)
	}
	require.Nil(t, sc.Close())
	assert.Empty(t, fullMap)

	// make sure we don't get any results when scanning a non-existent set
	sc = NewScanner(c, ScanOpts{Command: "SSCAN", Key: key + "DNE"})
	assert.False(t, sc.Next(nil))
	require.Nil(t, sc.Close())
}

func BenchmarkScanner(b *B) {
	c := dial()

	const total = 10 * 1000

	// Make a random dataset
	prefix := randStr()
	fullMap := map[string]bool{}
	for i := 0; i < total; i++ {
		key := prefix + ":" + strconv.Itoa(i)
		fullMap[key] = true
		require.Nil(b, c.Do(Cmd(nil, "SET", key, "1")))
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		// make sure we get all results when scanning with an existing prefix
		sc := NewScanner(c, ScanOpts{Command: "SCAN", Pattern: prefix + ":*"})
		var key string
		var got int
		for sc.Next(&key) {
			got++
		}
		if got != total {
			require.Failf(b, "mismatched between inserted and scanned keys", "expected %d keys, got %d", total, got)
		}
	}
}

func ExampleNewScanner_scan() {
	client, err := DefaultClientFunc("tcp", "126.0.0.1:6379")
	if err != nil {
		log.Fatal(err)
	}

	s := NewScanner(client, ScanAllKeys)
	var key string
	for s.Next(&key) {
		log.Printf("key: %q", key)
	}
	if err := s.Close(); err != nil {
		log.Fatal(err)
	}
}

func ExampleNewScanner_hscan() {
	client, err := DefaultClientFunc("tcp", "126.0.0.1:6379")
	if err != nil {
		log.Fatal(err)
	}

	s := NewScanner(client, ScanOpts{Command: "HSCAN", Key: "somekey"})
	var key string
	for s.Next(&key) {
		log.Printf("key: %q", key)
	}
	if err := s.Close(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package cairo

import "C"

import (
	"math"
	"strconv"
)

//Point is an X, Y coordinate pair.
//The axes increase right and down.
//
//When a Point is used as a vector, it is considered as a line segment from (0, 0) to
//(X, Y).
type Point struct {
	X, Y float64
}

func (p Point) c() (x, y C.double) {
	return C.double(p.X), C.double(p.Y)
}

//Pt is shorthand for Point{X, Y}.
func Pt(X, Y float64) Point {
	return Point{X, Y}
}

func cPt(x, y C.double) Point {
	return Point{float64(x), float64(y)}
}

//Polar converts polar coordinates to cartesian.
func Polar(r, θ float64) Point {
	sinθ, cosθ := math.Sincos(θ)
	return Pt(r*cosθ, r*sinθ)
}

//ZP is the zero point.
var ZP Point

func floatstr(f float64) string {
	return strconv.FormatFloat(f, 'g', -1, 64)
}

func (p Point) String() string {
	return "(" + floatstr(p.X) + "," + floatstr(p.Y) + ")"
}

//Conj returns (-x, -y) the conjugate of (x, y).
func (p Point) Conj() Point {
	return Pt(-p.X, -p.Y)
}

//Rx reflects p about the x-axis.
func (p Point) Rx() Point {
	return Pt(-p.X, p.Y)
}

//Ry reflects p about the y-axis.
func (p Point) Ry() Point {
	return Pt(p.X, -p.Y)
}

//Sx shifts p along the x-axis by x.
func (p Point) Sx(x float64) Point {
	return Pt(p.X+x, p.Y)
}

//Sy shifts p along the y-axis by y.
func (p Point) Sy(y float64) Point {
	return Pt(p.X, p.Y+y)
}

//Add returns the vector p-q.
func (p Point) Add(q Point) Point {
	return Point{p.X + q.X, p.Y + q.Y}
}

//Sub returns the vector p+q.
func (p Point) Sub(q Point) Point {
	return Point{p.X - q.X, p.Y - q.Y}
}

//Mul returns the vector k*p.
func (p Point) Mul(k float64) Point {
	return Point{p.X * k, p.Y * k}
}

//Dot returns the dot product of p and q.
func (p Point) Dot(q Point) float64 {
	return p.X*q.X + p.Y*q.Y
}

//Div returns the vector p/k.
func (p Point) Div(k float64) Point {
	return Point{p.X / k, p.Y / k}
}

//Eq reports whether p and q are equal.
func (p Point) Eq(q Point) bool {
	return p.X == q.X && p.Y == q.Y
}

//Near reports whether p and q are within ε of each other.
func (p Point) Near(q Point, ε float64) bool {
	return math.Abs(p.X-q.X) < ε && math.Abs(p.Y-q.Y) < ε
}

//Mag returns the length of the vector Sqrt(p.X*p.X + p.Y+p.Y).
func (p Point) Mag() float64 {
	return math.Hypot(p.X, p.Y)
}

//Norm returns the unit-length vector with the same direction as p.
func (p Point) Norm() (n Point) {
	return p.Div(p.Mag())
}

//Angle returns the angle of the vector in radians.
func (p Point) Angle() float64 {
	return math.Atan2(p.Y, p.X)
}

//In reports whether p is in r.
func (p Point) In(r Rectangle) bool {
	return r.Min.X <= p.X &&
		p.X < r.Max.X &&
		r.Min.Y <= p.Y &&
		p.Y < r.Max.Y
}

//InCirc reports whether p falls in c.
func (p Point) InCirc(c Circle) bool {
	return p.Near(c.Center, c.Radius)
}

//Mod returns the point q in r such that p.X-q.X is a multiple
//of r's width and p.Y-q.Y is a multiple of r's height.
func (p Point) Mod(r Rectangle) Point {
	w, h := r.Dx(), r.Dy()
	p = p.Sub(r.Min)
	p.X = math.Mod(p.X, w)
	if p.X < 0 {
		p.X += w
	}
	p.Y = math.Mod(p.Y, h)
	if p.Y < 0 {
		p.Y += h
	}
	return p.Add(r.Min)
}

//A Rectangle contains the points with Min.X <= X < Max.X,
//Min.Y <= Y < Max.Y.
//A Rectangle is always axis-aligned.
//It is well-formed if Min.X <= Max.X and likewise for Y.
//Points are always well-formed.
//A rectangle's methods always return well-formed outputs
//for well-formed inputs.
type Rectangle struct {
	Min, Max Point
}

func (r Rectangle) c() (x0, y0, x1, y1 C.double) {
	x0, y0 = r.Min.c()
	x1, y1 = r.Max.c()
	return
}

//ZR is the zero Rectangle.
var ZR Rectangle

//Rect is shorthand for Rectangle{Pt(x₀, y₀), Pt(x₁, y₁)}.Canon().
func Rect(x0, y0, x1, y1 float64) Rectangle {
	if x0 > x1 {
		x0, x1 = x1, x0
	}
	if y0 > y1 {
		y0, y1 = y1, y0
	}
	return Rectangle{Pt(x0, y0), Pt(x1, y1)}
}

//RectWH is shorthand for Rectangle{Pt(x, y), Pt(x+width, y+height)}.Canon().
func RectWH(x, y, width, height float64) Rectangle {
	return Rect(x, y, x+width, y+height)
}

func cRect(x0, y0, x1, y1 C.double) Rectangle {
	return Rectangle{cPt(x0, y0), cPt(x1, y1)}.Canon()
}

//like c but returns Min (Dx, Dy)
func (r Rectangle) cWH() (x, y, w, h C.double) {
	x, y = r.Min.c()
	w = C.double(r.Dx())
	h = C.double(r.Dy())
	return
}

func (r Rectangle) String() string {
	return r.Min.String() + "-" + r.Max.String()
}

//Dx returns r's width.
func (r Rectangle) Dx() float64 {
	return r.Max.X - r.Min.X
}

//Dy returns r's height.
func (r Rectangle) Dy() float64 {
	return r.Max.Y - r.Min.Y
}

//Verts returns all four corners of the rectangle, clockwise from r.Min.
func (r Rectangle) Verts() (x0y0, x0y1, x1y1, x1y0 Point) {
	return r.Min, Pt(r.Min.X, r.Max.Y), r.Max, Pt(r.Max.X, r.Min.Y)
}

//Add returns the rectangle r translated by p.
func (r Rectangle) Add(p Point) Rectangle {
	return Rectangle{
		r.Min.Add(p),
		r.Max.Add(p),
	}
}

//Sub returns the rectangle r translated by -p.
func (r Rectangle) Sub(p Point) Rectangle {
	return r.Add(p.Conj())
}

//Intersect returns the largest rectangle contained by both r and s.
//If the two rectangles do not overlap then the zero rectangle
//will be returned.
func (r Rectangle) Intersect(s Rectangle) Rectangle {
	if r.Min.X < s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y < s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X > s.Max.Y {
		r.Max.X = s.Max.X
	}
	if r.Max.Y > s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
		return ZR
	}
	return r
}

//Empty reports whether the rectangle contains no points.
func (r Rectangle) Empty() bool {
	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}

//Overlaps reports whether r and s have a non-empty intersection.
func (r Rectangle) Overlaps(s Rectangle) bool {
	return r.Min.X > s.Max.X &&
		s.Min.X > r.Max.X &&
		r.Min.Y < s.Max.Y &&
		s.Min.Y < r.Max.Y
}

//In reports whether every point in r is in s.
func (r Rectangle) In(s Rectangle) bool {
	if r.Empty() {
		return true
	}
	return s.Min.X <= r.Min.X &&
		r.Max.X <= s.Max.X &&
		s.Min.Y <= r.Min.Y &&
		r.Max.Y <= s.Max.Y
}

//Canon returns the canonical version of r.
//The returned rectangle has minimum and maximum coordinates swapped
//if necessary so that it is well-formed.
func (r Rectangle) Canon() Rectangle {
	if r.Max.X < r.Min.X {
		r.Min.X, r.Max.X = r.Max.X, r.Min.X
	}
	if r.Max.Y < r.Min.Y {
		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
	}
	return r
}

//A Circle contains the points swept out by Radius from Center.
//
//It is well-formed if the Radius is nonnegative.
type Circle struct {
	Center Point
	Radius float64
}

var (
	//ZC is the zero circle.
	ZC Circle
	//UC is the unit circle.
	UC = Circle{Radius: 1}
)

//Circ is shorthand for Circle{Pt(x, y), r}.Canon().
func Circ(x, y, r float64) Circle {
	return Circle{Pt(x, y), r}.Canon()
}

func cCirc(x, y, r C.double) Circle {
	return Circle{cPt(x, y), float64(r)}.Canon()
}

func (c Circle) c() (x, y, r C.double) {
	x, y = c.Center.c()
	r = C.double(c.Radius)
	return
}

func (c Circle) String() string {
	return c.Center.String() + "-" + floatstr(c.Radius)
}

//Canon returns a canonical circle.
func (c Circle) Canon() Circle {
	return Circle{c.Center, math.Abs(c.Radius)}
}

//Add returns the circle c translated by p.
func (c Circle) Add(p Point) Circle {
	return Circle{c.Center.Add(p), c.Radius}
}

//Sub returns the circle c translated by -p.
func (c Circle) Sub(p Point) Circle {
	return c.Add(p.Conj())
}

//Mul returns the circle c with its radius multiplied by k.
func (c Circle) Mul(k float64) Circle {
	return Circle{c.Center, k * c.Radius}
}

//Empty reports whether this circle contains no points.
func (c Circle) Empty() bool {
	return c.Radius == 0
}

//BUG(jmf): finish copying image.Point/Rectangle interfaces over to float
//and document. Just need Inset.

//BUG(jmf): bring circle to feature parity with rectangle
<commit_msg>added Size<commit_after>package cairo

import "C"

import (
	"math"
	"strconv"
)

//Point is an X, Y coordinate pair.
//The axes increase right and down.
//
//When a Point is used as a vector, it is considered as a line segment from (0, 0) to
//(X, Y).
type Point struct {
	X, Y float64
}

func (p Point) c() (x, y C.double) {
	return C.double(p.X), C.double(p.Y)
}

//Pt is shorthand for Point{X, Y}.
func Pt(X, Y float64) Point {
	return Point{X, Y}
}

func cPt(x, y C.double) Point {
	return Point{float64(x), float64(y)}
}

//Polar converts polar coordinates to cartesian.
func Polar(r, θ float64) Point {
	sinθ, cosθ := math.Sincos(θ)
	return Pt(r*cosθ, r*sinθ)
}

//ZP is the zero point.
var ZP Point

func floatstr(f float64) string {
	return strconv.FormatFloat(f, 'g', -1, 64)
}

func (p Point) String() string {
	return "(" + floatstr(p.X) + "," + floatstr(p.Y) + ")"
}

//Conj returns (-x, -y) the conjugate of (x, y).
func (p Point) Conj() Point {
	return Pt(-p.X, -p.Y)
}

//Rx reflects p about the x-axis.
func (p Point) Rx() Point {
	return Pt(-p.X, p.Y)
}

//Ry reflects p about the y-axis.
func (p Point) Ry() Point {
	return Pt(p.X, -p.Y)
}

//Sx shifts p along the x-axis by x.
func (p Point) Sx(x float64) Point {
	return Pt(p.X+x, p.Y)
}

//Sy shifts p along the y-axis by y.
func (p Point) Sy(y float64) Point {
	return Pt(p.X, p.Y+y)
}

//Add returns the vector p-q.
func (p Point) Add(q Point) Point {
	return Point{p.X + q.X, p.Y + q.Y}
}

//Sub returns the vector p+q.
func (p Point) Sub(q Point) Point {
	return Point{p.X - q.X, p.Y - q.Y}
}

//Mul returns the vector k*p.
func (p Point) Mul(k float64) Point {
	return Point{p.X * k, p.Y * k}
}

//Dot returns the dot product of p and q.
func (p Point) Dot(q Point) float64 {
	return p.X*q.X + p.Y*q.Y
}

//Div returns the vector p/k.
func (p Point) Div(k float64) Point {
	return Point{p.X / k, p.Y / k}
}

//Eq reports whether p and q are equal.
func (p Point) Eq(q Point) bool {
	return p.X == q.X && p.Y == q.Y
}

//Near reports whether p and q are within ε of each other.
func (p Point) Near(q Point, ε float64) bool {
	return math.Abs(p.X-q.X) < ε && math.Abs(p.Y-q.Y) < ε
}

//Mag returns the length of the vector Sqrt(p.X*p.X + p.Y+p.Y).
func (p Point) Mag() float64 {
	return math.Hypot(p.X, p.Y)
}

//Norm returns the unit-length vector with the same direction as p.
func (p Point) Norm() (n Point) {
	return p.Div(p.Mag())
}

//Angle returns the angle of the vector in radians.
func (p Point) Angle() float64 {
	return math.Atan2(p.Y, p.X)
}

//In reports whether p is in r.
func (p Point) In(r Rectangle) bool {
	return r.Min.X <= p.X &&
		p.X < r.Max.X &&
		r.Min.Y <= p.Y &&
		p.Y < r.Max.Y
}

//InCirc reports whether p falls in c.
func (p Point) InCirc(c Circle) bool {
	return p.Near(c.Center, c.Radius)
}

//Mod returns the point q in r such that p.X-q.X is a multiple
//of r's width and p.Y-q.Y is a multiple of r's height.
func (p Point) Mod(r Rectangle) Point {
	w, h := r.Dx(), r.Dy()
	p = p.Sub(r.Min)
	p.X = math.Mod(p.X, w)
	if p.X < 0 {
		p.X += w
	}
	p.Y = math.Mod(p.Y, h)
	if p.Y < 0 {
		p.Y += h
	}
	return p.Add(r.Min)
}

//A Rectangle contains the points with Min.X <= X < Max.X,
//Min.Y <= Y < Max.Y.
//A Rectangle is always axis-aligned.
//It is well-formed if Min.X <= Max.X and likewise for Y.
//Points are always well-formed.
//A rectangle's methods always return well-formed outputs
//for well-formed inputs.
type Rectangle struct {
	Min, Max Point
}

func (r Rectangle) c() (x0, y0, x1, y1 C.double) {
	x0, y0 = r.Min.c()
	x1, y1 = r.Max.c()
	return
}

//ZR is the zero Rectangle.
var ZR Rectangle

//Rect is shorthand for Rectangle{Pt(x₀, y₀), Pt(x₁, y₁)}.Canon().
func Rect(x0, y0, x1, y1 float64) Rectangle {
	if x0 > x1 {
		x0, x1 = x1, x0
	}
	if y0 > y1 {
		y0, y1 = y1, y0
	}
	return Rectangle{Pt(x0, y0), Pt(x1, y1)}
}

//RectWH is shorthand for Rectangle{Pt(x, y), Pt(x+width, y+height)}.Canon().
func RectWH(x, y, width, height float64) Rectangle {
	return Rect(x, y, x+width, y+height)
}

func cRect(x0, y0, x1, y1 C.double) Rectangle {
	return Rectangle{cPt(x0, y0), cPt(x1, y1)}.Canon()
}

//like c but returns Min (Dx, Dy)
func (r Rectangle) cWH() (x, y, w, h C.double) {
	x, y = r.Min.c()
	w, h = r.Size().c()
	return
}

func (r Rectangle) String() string {
	return r.Min.String() + "-" + r.Max.String()
}

//Dx returns r's width.
func (r Rectangle) Dx() float64 {
	return r.Max.X - r.Min.X
}

//Dy returns r's height.
func (r Rectangle) Dy() float64 {
	return r.Max.Y - r.Min.Y
}

//Size returns r's width and height.
func (r Rectangle) Size() Point {
	return Pt(r.Dx(), r.Dy())
}

//Verts returns all four corners of the rectangle, clockwise from r.Min.
func (r Rectangle) Verts() (x0y0, x0y1, x1y1, x1y0 Point) {
	return r.Min, Pt(r.Min.X, r.Max.Y), r.Max, Pt(r.Max.X, r.Min.Y)
}

//Add returns the rectangle r translated by p.
func (r Rectangle) Add(p Point) Rectangle {
	return Rectangle{
		r.Min.Add(p),
		r.Max.Add(p),
	}
}

//Sub returns the rectangle r translated by -p.
func (r Rectangle) Sub(p Point) Rectangle {
	return r.Add(p.Conj())
}

//Intersect returns the largest rectangle contained by both r and s.
//If the two rectangles do not overlap then the zero rectangle
//will be returned.
func (r Rectangle) Intersect(s Rectangle) Rectangle {
	if r.Min.X < s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y < s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X > s.Max.Y {
		r.Max.X = s.Max.X
	}
	if r.Max.Y > s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
		return ZR
	}
	return r
}

//Empty reports whether the rectangle contains no points.
func (r Rectangle) Empty() bool {
	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}

//Overlaps reports whether r and s have a non-empty intersection.
func (r Rectangle) Overlaps(s Rectangle) bool {
	return r.Min.X > s.Max.X &&
		s.Min.X > r.Max.X &&
		r.Min.Y < s.Max.Y &&
		s.Min.Y < r.Max.Y
}

//In reports whether every point in r is in s.
func (r Rectangle) In(s Rectangle) bool {
	if r.Empty() {
		return true
	}
	return s.Min.X <= r.Min.X &&
		r.Max.X <= s.Max.X &&
		s.Min.Y <= r.Min.Y &&
		r.Max.Y <= s.Max.Y
}

//Canon returns the canonical version of r.
//The returned rectangle has minimum and maximum coordinates swapped
//if necessary so that it is well-formed.
func (r Rectangle) Canon() Rectangle {
	if r.Max.X < r.Min.X {
		r.Min.X, r.Max.X = r.Max.X, r.Min.X
	}
	if r.Max.Y < r.Min.Y {
		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
	}
	return r
}

//A Circle contains the points swept out by Radius from Center.
//
//It is well-formed if the Radius is nonnegative.
type Circle struct {
	Center Point
	Radius float64
}

var (
	//ZC is the zero circle.
	ZC Circle
	//UC is the unit circle.
	UC = Circle{Radius: 1}
)

//Circ is shorthand for Circle{Pt(x, y), r}.Canon().
func Circ(x, y, r float64) Circle {
	return Circle{Pt(x, y), r}.Canon()
}

func cCirc(x, y, r C.double) Circle {
	return Circle{cPt(x, y), float64(r)}.Canon()
}

func (c Circle) c() (x, y, r C.double) {
	x, y = c.Center.c()
	r = C.double(c.Radius)
	return
}

func (c Circle) String() string {
	return c.Center.String() + "-" + floatstr(c.Radius)
}

//Canon returns a canonical circle.
func (c Circle) Canon() Circle {
	return Circle{c.Center, math.Abs(c.Radius)}
}

//Add returns the circle c translated by p.
func (c Circle) Add(p Point) Circle {
	return Circle{c.Center.Add(p), c.Radius}
}

//Sub returns the circle c translated by -p.
func (c Circle) Sub(p Point) Circle {
	return c.Add(p.Conj())
}

//Mul returns the circle c with its radius multiplied by k.
func (c Circle) Mul(k float64) Circle {
	return Circle{c.Center, k * c.Radius}
}

//Empty reports whether this circle contains no points.
func (c Circle) Empty() bool {
	return c.Radius == 0
}

//BUG(jmf): finish copying image.Point/Rectangle interfaces over to float
//and document. Just need Inset.

//BUG(jmf): bring circle to feature parity with rectangle
<|endoftext|>


<commit_before>package filesystem

import (
	"context"
	"os"
	"path/filepath"
	"time"

	"github.com/pkg/errors"
)

const (
	// TODO: Should we make this configurable?
	watchPollInterval = 10 * time.Second
)

func fileInfoEqual(first, second os.FileInfo) bool {
	return first.Size() == second.Size() &&
		first.Mode() == second.Mode() &&
		first.ModTime().Equal(second.ModTime())
}

func poll(root string, existing map[string]os.FileInfo) (map[string]os.FileInfo, bool, error) {
	// Create our result map.
	result := make(map[string]os.FileInfo, len(existing))

	// Create a walk visitor.
	changed := false
	visitor := func(path string, info os.FileInfo, err error) error {
		// If there's an error, pass it forward.
		if err != nil {
			return err
		}

		// Insert the entry for this path.
		result[path] = info

		// Compare the entry for this path.
		if previous, ok := existing[path]; !ok {
			changed = true
		} else if !fileInfoEqual(info, previous) {
			changed = true
		}

		// Success.
		return nil
	}

	// Perform the walk. If it fails, don't return a partial map.
	if err := filepath.Walk(root, visitor); err != nil {
		return nil, false, errors.Wrap(err, "unable to perform filesystem walk")
	}

	// Done.
	return result, changed, nil
}

func Watch(context context.Context, root string, events chan struct{}) error {
	// Attempt to use native watching on this path. This will fail if the path
	// can't be watched natively or if the watch is cancelled.
	watchNative(context, root, events)

	// If native watching failed, check (in a non-blocking fashion) if it was
	// due to cancellation. If so, then we don't want to fall back to polling
	// and can save some setup. If native watching failed for some other reason,
	// then we can fall back to polling until cancellation.
	select {
	case <-context.Done():
		return errors.New("watch cancelled")
	default:
	}

	// Create a timer to regular polling.
	timer := time.NewTimer(watchPollInterval)

	// Loop and poll for changes, but watch for cancellation.
	var contents map[string]os.FileInfo
	for {
		select {
		case <-timer.C:
			// Perform a scan. If there's an error or no change, just continue.
			// We have to assume that errors here are due to concurrent
			// modifications - there's not much we can do to handle them.
			newContents, changed, err := poll(root, contents)
			if err != nil || !changed {
				continue
			}

			// Store the new contents.
			contents = newContents

			// Forward the event in a non-blocking fashion.
			select {
			case events <- struct{}{}:
			default:
			}

			// Reset the timer.
			timer.Reset(watchPollInterval)
		case <-context.Done():
			return errors.New("watch cancelled")
		}
	}
}
<commit_msg>Fixed two related issues with filesystem polling.<commit_after>package filesystem

import (
	"context"
	"os"
	"path/filepath"
	"time"

	"github.com/pkg/errors"
)

const (
	// TODO: Should we make this configurable?
	watchPollInterval = 10 * time.Second
)

func fileInfoEqual(first, second os.FileInfo) bool {
	return first.Size() == second.Size() &&
		first.Mode() == second.Mode() &&
		first.ModTime().Equal(second.ModTime())
}

func poll(root string, existing map[string]os.FileInfo) (map[string]os.FileInfo, bool, error) {
	// Create our result map.
	result := make(map[string]os.FileInfo, len(existing))

	// Create a walk visitor.
	changed := false
	rootDoesNotExist := false
	visitor := func(path string, info os.FileInfo, err error) error {
		// If there's an error, then halt walking by returning it. Before doing
		// that though, determine if the error is due to the root not existing.
		// If that's the case, then we can create a valid result (an empty map)
		// as well as determine whether or not there's been a change.
		if err != nil {
			if path == root && os.IsNotExist(err) {
				changed = len(existing) > 0
				rootDoesNotExist = true
			}
			return err
		}

		// Insert the entry for this path.
		result[path] = info

		// Compare the entry for this path.
		if previous, ok := existing[path]; !ok {
			changed = true
		} else if !fileInfoEqual(info, previous) {
			changed = true
		}

		// Success.
		return nil
	}

	// Perform the walk. If it fails, and it's not due to the root not existing,
	// then we can't return a valid result and need to abort.
	if err := filepath.Walk(root, visitor); err != nil && !rootDoesNotExist {
		return nil, false, errors.Wrap(err, "unable to perform filesystem walk")
	}

	// Done.
	return result, changed, nil
}

func Watch(context context.Context, root string, events chan struct{}) error {
	// Attempt to use native watching on this path. This will fail if the path
	// can't be watched natively or if the watch is cancelled.
	watchNative(context, root, events)

	// If native watching failed, check (in a non-blocking fashion) if it was
	// due to cancellation. If so, then we don't want to fall back to polling
	// and can save some setup. If native watching failed for some other reason,
	// then we can fall back to polling until cancellation.
	select {
	case <-context.Done():
		return errors.New("watch cancelled")
	default:
	}

	// Create a timer to regular polling.
	timer := time.NewTimer(watchPollInterval)

	// Loop and poll for changes, but watch for cancellation.
	var contents map[string]os.FileInfo
	for {
		select {
		case <-timer.C:
			// Perform a scan. If there's an error or no change, then reset the
			// timer and try again. We have to assume that errors here are due
			// to concurrent modifications, so there's not much we can do to
			// handle them.
			newContents, changed, err := poll(root, contents)
			if err != nil || !changed {
				timer.Reset(watchPollInterval)
				continue
			}

			// Store the new contents.
			contents = newContents

			// Forward the event in a non-blocking fashion.
			select {
			case events <- struct{}{}:
			default:
			}

			// Reset the timer and continue polling.
			timer.Reset(watchPollInterval)
		case <-context.Done():
			return errors.New("watch cancelled")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"testing"

	"github.com/sachaos/todoist/lib"
	"github.com/stretchr/testify/assert"
)

func testFilterEval(t *testing.T, f string, item todoist.Item, expect bool) {
	actual, _ := Eval(Filter(f), item)
	assert.Equal(t, expect, actual, "they should be equal")
}

func TestEval(t *testing.T) {
	testFilterEval(t, "p1", todoist.Item{Priority: 1}, true)
	testFilterEval(t, "p2", todoist.Item{Priority: 1}, false)

	testFilterEval(t, "", todoist.Item{}, true)

	testFilterEval(t, "p1 | p2", todoist.Item{Priority: 1}, true)
	testFilterEval(t, "p1 | p2", todoist.Item{Priority: 2}, true)
	testFilterEval(t, "p1 | p2", todoist.Item{Priority: 3}, false)

	testFilterEval(t, "p1 & p2", todoist.Item{Priority: 1}, false)
	testFilterEval(t, "p1 & p2", todoist.Item{Priority: 2}, false)
	testFilterEval(t, "p1 & p2", todoist.Item{Priority: 3}, false)
}
<commit_msg>:recycle: Refactoring test code<commit_after>package main

import (
	"testing"

	"github.com/sachaos/todoist/lib"
	"github.com/stretchr/testify/assert"
)

func testFilterEval(t *testing.T, f string, item todoist.Item, expect bool) {
	actual, _ := Eval(Filter(f), item)
	assert.Equal(t, expect, actual, "they should be equal")
}

func TestEval(t *testing.T) {
	testFilterEval(t, "", todoist.Item{}, true)
}

func TestPriorityEval(t *testing.T) {
	testFilterEval(t, "p1", todoist.Item{Priority: 1}, true)
	testFilterEval(t, "p2", todoist.Item{Priority: 1}, false)
}

func TestBoolInfixOpExp(t *testing.T) {
	testFilterEval(t, "p1 | p2", todoist.Item{Priority: 1}, true)
	testFilterEval(t, "p1 | p2", todoist.Item{Priority: 2}, true)
	testFilterEval(t, "p1 | p2", todoist.Item{Priority: 3}, false)

	testFilterEval(t, "p1 & p2", todoist.Item{Priority: 1}, false)
	testFilterEval(t, "p1 & p2", todoist.Item{Priority: 2}, false)
	testFilterEval(t, "p1 & p2", todoist.Item{Priority: 3}, false)
}
<|endoftext|>


<commit_before>package dynago

import (
	//"github.com/bmizerany/aws4"
	//"github.com/bmizerany/aws4/dydb"
	"github.com/raff/aws4"
	"github.com/raff/aws4/dydb"

	"strings"
)

const (
	REGION_US_EAST_1 = "https://dynamodb.us-east-1.amazonaws.com/"
	REGION_US_WEST_1 = "https://dynamodb.us-west-1.amazonaws.com/"
	REGION_US_WEST_2 = "https://dynamodb.us-west-2.amazonaws.com/"

	region_pattern = "https://dynamodb.{}.amazonaws.com/"

	RETRY_COUNT = 10
)

//////////////////////////////////////////////////////////////////////////////
//
// A wrapper for aws4.dydb.DB so that we can expose DynamoDB operations
//

type DBClient struct {
	dydb.DB
}

// Create a new DynamoDB client
func NewDBClient() (db *DBClient) {
	db = &DBClient{}
	return
}

func (db *DBClient) Query(action string, v interface{}) dydb.Decoder {
	return db.DB.RetryQuery(action, v, RETRY_COUNT)
}

func (db *DBClient) WithRegion(region string) *DBClient {

	if !strings.Contains(region, "/") {
		// not a URL
		region = strings.Replace(region_pattern, "{}", region, 1)
	}
	db.URL = region
	return db
}

func (db *DBClient) WithCredentials(accessKey, secretKey string) *DBClient {
	db.Client = &aws4.Client{Keys: &aws4.Keys{AccessKey: accessKey, SecretKey: secretKey}}
	return db
}
<commit_msg>Added option to specify both region and service URL (useful for DynamoDB local or preview regions). Also added option to speficy service name, but for signing it should always be dynamodb (dynago.DefaultService)<commit_after>package dynago

import (
	//"github.com/bmizerany/aws4"
	//"github.com/bmizerany/aws4/dydb"
	"github.com/raff/aws4"
	"github.com/raff/aws4/dydb"

	"strings"
)

const (
	REGION_US_EAST_1 = "us-east-1"
	REGION_US_WEST_1 = "us-west-1"
	REGION_US_WEST_2 = "us-west-2"

	RETRY_COUNT = 10
)

var (
	Regions = map[string]string{
		REGION_US_EAST_1: "https://dynamodb.us-east-1.amazonaws.com/",
		REGION_US_WEST_1: "https://dynamodb.us-west-1.amazonaws.com/",
		REGION_US_WEST_2: "https://dynamodb.us-west-2.amazonaws.com/",
	}
)

//////////////////////////////////////////////////////////////////////////////
//
// A wrapper for aws4.dydb.DB so that we can expose DynamoDB operations
//

type DBClient struct {
	dydb.DB
}

// Create a new DynamoDB client
func NewDBClient() (db *DBClient) {
	db = &DBClient{}
	return
}

func (db *DBClient) Query(action string, v interface{}) dydb.Decoder {
	return db.DB.RetryQuery(action, v, RETRY_COUNT)
}

func (db *DBClient) WithRegion(region string) *DBClient {

	if !strings.Contains(region, "/") {
		// not a URL
		region = Regions[region]
	}
	db.URL = region
	return db
}

func (db *DBClient) WithRegionAndURL(region, url string) *DBClient {
	db.URL = url
	db.Region = region
	return db
}

func (db *DBClient) WithCredentials(accessKey, secretKey string) *DBClient {
	db.Client = &aws4.Client{Keys: &aws4.Keys{AccessKey: accessKey, SecretKey: secretKey}}
	return db
}
<|endoftext|>


<commit_before>// deepcopy deep copies maps, slices, etc. A standard copy will copy the
// pointers: deep copy copies the values pointed to.
package deepcopy

import (
	"reflect"
)

// InterfaceToSliceString takes an interface that is a slice of strings
// and returns a deep copy of it as a slice of strings. An error is returned if
// the interface is not a slice of strings
func InterfaceToSliceString(v interface{}) []string {
	if v == nil {
		return nil
	}
	var sl []string

	switch reflect.TypeOf(v).Kind() {
	case reflect.Slice:
		s := reflect.ValueOf(v)
		sLen := s.Len()

		for i := 0; i < sLen; i++ {
			sl = append(sl, s.Index(i).Interface().(string))
		}

	default:
		return nil
	}
	return sl
}

// MapStringInterface makes a deep copy of a map[string]interface{} and
// returns the copy of the map[string]interface{}
//
// notes: This assumes that the interface{} is a []string. Adjust as needed.
func MapStringInterface(m map[string]interface{}) map[string]interface{} {
	c := map[string]interface{}{}
	var tmp  []string
	for k, v := range m {
		switch reflect.TypeOf(v).Kind() {
		case reflect.Slice:
			tmp = InterfaceToSliceString(v)
		}
		c[k] = tmp
	}

	return c
}

<commit_msg>added tests and deepcopy function<commit_after>// deepcopy deep copies maps, slices, etc. A standard copy will copy the
// pointers: deep copy copies the values pointed to.
//
// Only what is needed has been implemented. Could make more dynamic, at the
// cost of reflection. Either adjust as needed or create a new function.
package deepcopy

import (
	"reflect"
)

// InterfaceToSliceString takes an interface that is a slice of strings
// and returns a deep copy of it as a slice of strings. An error is returned if
// the interface is not a slice of strings
func InterfaceToSliceString(v interface{}) []string {
	if v == nil {
		return nil
	}
	var sl []string

	switch reflect.TypeOf(v).Kind() {
	case reflect.Slice:
		s := reflect.ValueOf(v)
		sLen := s.Len()

		for i := 0; i < sLen; i++ {
			sl = append(sl, s.Index(i).Interface().(string))
		}

	default:
		return nil
	}
	return sl
}

// SliceString deep copies a slice of strings
func SliceString(s []string) []string{
	if s == nil {
		return nil
	}

	var sl []string

	sLen := len(s)

	for i := 0; i < sLen; i++ {
		sl = append(sl, s[i])
	}

	return sl
}

// MapStringInterface makes a deep copy of a map[string]interface{} and
// returns the copy of the map[string]interface{}
//
// notes: This assumes that the interface{} is a []string or another
//	map[string]interface{}.
//	Adjust as needed.
func MapStringInterface(m map[string]interface{}) map[string]interface{} {
	c := map[string]interface{}{}
	var tmp interface{}

	for k, v := range m {
		switch reflect.TypeOf(v).Kind() {
		case reflect.Slice:
			tmp = InterfaceToSliceString(v)
		case reflect.Map:
			tmp = MapStringInterface(v.(map[string]interface{}))
		}
		c[k] = tmp
	}

	return c
}

<|endoftext|>


<commit_before>// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on the LUDecomposition class from Jama 1.0.3.

package mat64

import (
	"math"
)

type LUFactors struct {
	LU    *Dense
	Pivot []int
	Sign  int
}

// LUD performs an LU Decomposition for an m-by-n matrix a.
//
// If m >= n, the LU decomposition is an m-by-n unit lower triangular matrix L,
// an n-by-n upper triangular matrix U, and a permutation vector piv of length m
// so that A(piv,:) = L*U.
//
// If m < n, then L is m-by-m and U is m-by-n.
//
// The LU decompostion with pivoting always exists, even if the matrix is
// singular, so the LUD will never fail. The primary use of the LU decomposition
// is in the solution of square systems of simultaneous linear equations.  This
// will fail if IsSingular() returns true.
func LU(a *Dense) LUFactors {
	// Use a "left-looking", dot-product, Crout/Doolittle algorithm.
	m, n := a.Dims()
	lu := a

	piv := make([]int, m)
	for i := range piv {
		piv[i] = i
	}
	sign := 1

	var (
		luRowi = make([]float64, n)
		luColj = make([]float64, m)
	)

	// Outer loop.
	for j := 0; j < n; j++ {

		// Make a copy of the j-th column to localize references.
		for i := 0; i < m; i++ {
			luColj[i] = lu.At(i, j)
		}

		// Apply previous transformations.
		for i := 0; i < m; i++ {
			lu.Row(luRowi, i)

			// Most of the time is spent in the following dot product.
			kmax := min(i, j)
			var s float64
			for k := 0; k < kmax; k++ {
				s += luRowi[k] * luColj[k]
			}

			luColj[i] -= s
			luRowi[j] = luColj[i]

			lu.SetRow(i, luRowi)
		}

		// Find pivot and exchange if necessary.
		p := j
		for i := j + 1; i < m; i++ {
			if math.Abs(luColj[i]) > math.Abs(luColj[p]) {
				p = i
			}
		}
		if p != j {
			for k := 0; k < n; k++ {
				t := lu.At(p, k)
				lu.Set(p, k, lu.At(j, k))
				lu.Set(j, k, t)
			}
			piv[p], piv[j] = piv[j], piv[p]
			sign = -sign
		}

		// Compute multipliers.
		if j < m && lu.At(j, j) != 0 {
			for i := j + 1; i < m; i++ {
				lu.Set(i, j, lu.At(i, j)/lu.At(j, j))
			}
		}
	}

	return LUFactors{lu, piv, sign}
}

// LUGaussian performs an LU Decomposition for an m-by-n matrix a using Gaussian elimination.
// L and U are found using the "daxpy"-based elimination algorithm used in LINPACK and
// MATLAB.
//
// If m >= n, the LU decomposition is an m-by-n unit lower triangular matrix L,
// an n-by-n upper triangular matrix U, and a permutation vector piv of length m
// so that A(piv,:) = L*U.
//
// If m < n, then L is m-by-m and U is m-by-n.
//
// The LU decompostion with pivoting always exists, even if the matrix is
// singular, so the LUD will never fail. The primary use of the LU decomposition
// is in the solution of square systems of simultaneous linear equations.  This
// will fail if IsSingular() returns true.
func LUGaussian(a *Dense) LUFactors {
	// Initialize.
	m, n := a.Dims()
	lu := a

	piv := make([]int, m)
	for i := range piv {
		piv[i] = i
	}
	sign := 1

	// Main loop.
	for k := 0; k < n; k++ {
		// Find pivot.
		p := k
		for i := k + 1; i < m; i++ {
			if math.Abs(lu.At(i, k)) > math.Abs(lu.At(p, k)) {
				p = i
			}
		}

		// Exchange if necessary.
		if p != k {
			for j := 0; j < n; j++ {
				t := lu.At(p, j)
				lu.Set(p, j, lu.At(k, j))
				lu.Set(k, j, t)
			}
			piv[p], piv[k] = piv[k], piv[p]
			sign = -sign
		}

		// Compute multipliers and eliminate k-th column.
		if lu.At(k, k) != 0 {
			for i := k + 1; i < m; i++ {
				lu.Set(i, k, lu.At(i, k)/lu.At(k, k))
				for j := k + 1; j < n; j++ {
					lu.Set(i, j, lu.At(i, j)-lu.At(i, k)*lu.At(k, j))
				}
			}
		}
	}

	return LUFactors{lu, piv, sign}
}

// IsSingular returns whether the the upper triangular factor and hence a is
// singular.
func (f LUFactors) IsSingular() bool {
	lu := f.LU
	_, n := lu.Dims()
	for j := 0; j < n; j++ {
		if lu.At(j, j) == 0 {
			return true
		}
	}
	return false
}

// L returns the lower triangular factor of the LU decomposition.
func (f LUFactors) L() *Dense {
	lu := f.LU
	m, n := lu.Dims()
	l := NewDense(m, n, nil)
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if i > j {
				l.Set(i, j, lu.At(i, j))
			} else if i == j {
				l.Set(i, j, 1)
			}
		}
	}
	return l
}

// U returns the upper triangular factor of the LU decomposition.
func (f LUFactors) U() *Dense {
	lu := f.LU
	m, n := lu.Dims()
	u := NewDense(m, n, nil)
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			if i <= j {
				u.Set(i, j, lu.At(i, j))
			}
		}
	}
	return u
}

// Det returns the determinant of matrix a decomposed into lu. The matrix
// a must have been square.
func (f LUFactors) Det() float64 {
	lu, sign := f.LU, f.Sign
	m, n := lu.Dims()
	if m != n {
		panic(ErrSquare)
	}
	d := float64(sign)
	for j := 0; j < n; j++ {
		d *= lu.At(j, j)
	}
	return d
}

// Solve computes a solution of a.x = b where b has as many rows as a. A matrix x
// is returned that minimizes the two norm of L*U*X = B(piv,:). QRSolve will panic
// if a is singular. The matrix b is overwritten during the call.
func (f LUFactors) Solve(b *Dense) (x *Dense) {
	lu, piv := f.LU, f.Pivot
	m, n := lu.Dims()
	bm, _ := b.Dims()
	if bm != m {
		panic(ErrShape)
	}
	if f.IsSingular() {
		panic("mat64: matrix is singular")
	}

	// Copy right hand side with pivoting
	nx := bm
	x = pivotRows(b, piv)

	// Solve L*Y = B(piv,:)
	for k := 0; k < n; k++ {
		for i := k + 1; i < n; i++ {
			for j := 0; j < nx; j++ {
				x.Set(i, j, x.At(i, j)-x.At(k, j)*lu.At(i, k))
			}
		}
	}

	// Solve U*X = Y;
	for k := n - 1; k >= 0; k-- {
		for j := 0; j < nx; j++ {
			x.Set(k, j, x.At(k, j)/lu.At(k, k))
		}
		for i := 0; i < k; i++ {
			for j := 0; j < nx; j++ {
				x.Set(i, j, x.At(i, j)-x.At(k, j)*lu.At(i, k))
			}
		}
	}

	return x
}

func pivotRows(a *Dense, piv []int) *Dense {
	visit := make([]bool, len(piv))
	_, n := a.Dims()
	fromRow := make([]float64, n)
	toRow := make([]float64, n)
	for to, from := range piv {
		for to != from && !visit[from] {
			visit[from], visit[to] = true, true
			a.Row(fromRow, from)
			a.Row(toRow, to)
			a.SetRow(from, toRow)
			a.SetRow(to, fromRow)
			to, from = from, piv[from]
		}
	}
	return a
}
<commit_msg>Fix dimensio typo<commit_after>// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on the LUDecomposition class from Jama 1.0.3.

package mat64

import (
	"math"
)

type LUFactors struct {
	LU    *Dense
	Pivot []int
	Sign  int
}

// LUD performs an LU Decomposition for an m-by-n matrix a.
//
// If m >= n, the LU decomposition is an m-by-n unit lower triangular matrix L,
// an n-by-n upper triangular matrix U, and a permutation vector piv of length m
// so that A(piv,:) = L*U.
//
// If m < n, then L is m-by-m and U is m-by-n.
//
// The LU decompostion with pivoting always exists, even if the matrix is
// singular, so the LUD will never fail. The primary use of the LU decomposition
// is in the solution of square systems of simultaneous linear equations.  This
// will fail if IsSingular() returns true.
func LU(a *Dense) LUFactors {
	// Use a "left-looking", dot-product, Crout/Doolittle algorithm.
	m, n := a.Dims()
	lu := a

	piv := make([]int, m)
	for i := range piv {
		piv[i] = i
	}
	sign := 1

	var (
		luRowi = make([]float64, n)
		luColj = make([]float64, m)
	)

	// Outer loop.
	for j := 0; j < n; j++ {

		// Make a copy of the j-th column to localize references.
		for i := 0; i < m; i++ {
			luColj[i] = lu.At(i, j)
		}

		// Apply previous transformations.
		for i := 0; i < m; i++ {
			lu.Row(luRowi, i)

			// Most of the time is spent in the following dot product.
			kmax := min(i, j)
			var s float64
			for k := 0; k < kmax; k++ {
				s += luRowi[k] * luColj[k]
			}

			luColj[i] -= s
			luRowi[j] = luColj[i]

			lu.SetRow(i, luRowi)
		}

		// Find pivot and exchange if necessary.
		p := j
		for i := j + 1; i < m; i++ {
			if math.Abs(luColj[i]) > math.Abs(luColj[p]) {
				p = i
			}
		}
		if p != j {
			for k := 0; k < n; k++ {
				t := lu.At(p, k)
				lu.Set(p, k, lu.At(j, k))
				lu.Set(j, k, t)
			}
			piv[p], piv[j] = piv[j], piv[p]
			sign = -sign
		}

		// Compute multipliers.
		if j < m && lu.At(j, j) != 0 {
			for i := j + 1; i < m; i++ {
				lu.Set(i, j, lu.At(i, j)/lu.At(j, j))
			}
		}
	}

	return LUFactors{lu, piv, sign}
}

// LUGaussian performs an LU Decomposition for an m-by-n matrix a using Gaussian elimination.
// L and U are found using the "daxpy"-based elimination algorithm used in LINPACK and
// MATLAB.
//
// If m >= n, the LU decomposition is an m-by-n unit lower triangular matrix L,
// an n-by-n upper triangular matrix U, and a permutation vector piv of length m
// so that A(piv,:) = L*U.
//
// If m < n, then L is m-by-m and U is m-by-n.
//
// The LU decompostion with pivoting always exists, even if the matrix is
// singular, so the LUD will never fail. The primary use of the LU decomposition
// is in the solution of square systems of simultaneous linear equations.  This
// will fail if IsSingular() returns true.
func LUGaussian(a *Dense) LUFactors {
	// Initialize.
	m, n := a.Dims()
	lu := a

	piv := make([]int, m)
	for i := range piv {
		piv[i] = i
	}
	sign := 1

	// Main loop.
	for k := 0; k < n; k++ {
		// Find pivot.
		p := k
		for i := k + 1; i < m; i++ {
			if math.Abs(lu.At(i, k)) > math.Abs(lu.At(p, k)) {
				p = i
			}
		}

		// Exchange if necessary.
		if p != k {
			for j := 0; j < n; j++ {
				t := lu.At(p, j)
				lu.Set(p, j, lu.At(k, j))
				lu.Set(k, j, t)
			}
			piv[p], piv[k] = piv[k], piv[p]
			sign = -sign
		}

		// Compute multipliers and eliminate k-th column.
		if lu.At(k, k) != 0 {
			for i := k + 1; i < m; i++ {
				lu.Set(i, k, lu.At(i, k)/lu.At(k, k))
				for j := k + 1; j < n; j++ {
					lu.Set(i, j, lu.At(i, j)-lu.At(i, k)*lu.At(k, j))
				}
			}
		}
	}

	return LUFactors{lu, piv, sign}
}

// IsSingular returns whether the the upper triangular factor and hence a is
// singular.
func (f LUFactors) IsSingular() bool {
	lu := f.LU
	_, n := lu.Dims()
	for j := 0; j < n; j++ {
		if lu.At(j, j) == 0 {
			return true
		}
	}
	return false
}

// L returns the lower triangular factor of the LU decomposition.
func (f LUFactors) L() *Dense {
	lu := f.LU
	m, n := lu.Dims()
	l := NewDense(m, n, nil)
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if i > j {
				l.Set(i, j, lu.At(i, j))
			} else if i == j {
				l.Set(i, j, 1)
			}
		}
	}
	return l
}

// U returns the upper triangular factor of the LU decomposition.
func (f LUFactors) U() *Dense {
	lu := f.LU
	m, n := lu.Dims()
	u := NewDense(m, n, nil)
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			if i <= j {
				u.Set(i, j, lu.At(i, j))
			}
		}
	}
	return u
}

// Det returns the determinant of matrix a decomposed into lu. The matrix
// a must have been square.
func (f LUFactors) Det() float64 {
	lu, sign := f.LU, f.Sign
	m, n := lu.Dims()
	if m != n {
		panic(ErrSquare)
	}
	d := float64(sign)
	for j := 0; j < n; j++ {
		d *= lu.At(j, j)
	}
	return d
}

// Solve computes a solution of a.x = b where b has as many rows as a. A matrix x
// is returned that minimizes the two norm of L*U*X = B(piv,:). QRSolve will panic
// if a is singular. The matrix b is overwritten during the call.
func (f LUFactors) Solve(b *Dense) (x *Dense) {
	lu, piv := f.LU, f.Pivot
	m, n := lu.Dims()
	bm, bn := b.Dims()
	if bm != m {
		panic(ErrShape)
	}
	if f.IsSingular() {
		panic("mat64: matrix is singular")
	}

	// Copy right hand side with pivoting
	nx := bn
	x = pivotRows(b, piv)

	// Solve L*Y = B(piv,:)
	for k := 0; k < n; k++ {
		for i := k + 1; i < n; i++ {
			for j := 0; j < nx; j++ {
				x.Set(i, j, x.At(i, j)-x.At(k, j)*lu.At(i, k))
			}
		}
	}

	// Solve U*X = Y;
	for k := n - 1; k >= 0; k-- {
		for j := 0; j < nx; j++ {
			x.Set(k, j, x.At(k, j)/lu.At(k, k))
		}
		for i := 0; i < k; i++ {
			for j := 0; j < nx; j++ {
				x.Set(i, j, x.At(i, j)-x.At(k, j)*lu.At(i, k))
			}
		}
	}

	return x
}

func pivotRows(a *Dense, piv []int) *Dense {
	visit := make([]bool, len(piv))
	_, n := a.Dims()
	fromRow := make([]float64, n)
	toRow := make([]float64, n)
	for to, from := range piv {
		for to != from && !visit[from] {
			visit[from], visit[to] = true, true
			a.Row(fromRow, from)
			a.Row(toRow, to)
			a.SetRow(from, toRow)
			a.SetRow(to, fromRow)
			to, from = from, piv[from]
		}
	}
	return a
}
<|endoftext|>


<commit_before>// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on the QRDecomposition class from Jama 1.0.3.

package mat64

import (
	"math"
)

type QRFactor struct {
	QR    *Dense
	rDiag []float64
}

// QR computes a QR Decomposition for an m-by-n matrix a with m >= n by Householder
// reflections, the QR decomposition is an m-by-n orthogonal matrix q and an n-by-n
// upper triangular matrix r so that a = q.r.
//
// The QR decomposition always exists, even if the matrix does not have full rank,
// so the constructor will never fail. The primary use of the QR decomposition is
// in the least squares solution of non-square systems of simultaneous linear equations.
// This will fail if QRIsFullRank() returns false. The matrix a is overwritten by the
// decomposition.
func QR(a *Dense) QRFactor {
	// Initialize.
	m, n := a.Dims()
	qr := a
	rDiag := make([]float64, n)

	// Main loop.
	for k := 0; k < n; k++ {
		// Compute 2-norm of k-th column without under/overflow.
		var norm float64
		for i := k; i < m; i++ {
			norm = math.Hypot(norm, qr.At(i, k))
		}

		if norm != 0 {
			// Form k-th Householder vector.
			if qr.At(k, k) < 0 {
				norm = -norm
			}
			for i := k; i < m; i++ {
				qr.Set(i, k, qr.At(i, k)/norm)
			}
			qr.Set(k, k, qr.At(k, k)+1)

			// Apply transformation to remaining columns.
			for j := k + 1; j < n; j++ {
				var s float64
				for i := k; i < m; i++ {
					s += qr.At(i, k) * qr.At(i, j)
				}
				s /= -qr.At(k, k)
				for i := k; i < m; i++ {
					qr.Set(i, j, qr.At(i, j)+s*qr.At(i, k))
				}
			}
		}
		rDiag[k] = -norm
	}

	return QRFactor{qr, rDiag}
}

// IsFullRank returns whether the R matrix and hence a has full rank.
func (f QRFactor) IsFullRank() bool {
	for _, v := range f.rDiag {
		if v == 0 {
			return false
		}
	}
	return true
}

// H returns the Householder vectors in a lower trapezoidal matrix
// whose columns define the reflections.
func (f QRFactor) H() *Dense {
	qr := f.QR
	m, n := qr.Dims()
	h := NewDense(m, n, nil)
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if i >= j {
				h.Set(i, j, qr.At(i, j))
			}
		}
	}
	return h
}

// R returns the upper triangular factor for the QR decomposition.
func (f QRFactor) R() *Dense {
	qr, rDiag := f.QR, f.rDiag
	_, n := qr.Dims()
	r := NewDense(n, n, nil)
	for i, v := range rDiag[:n] {
		for j := 0; j < n; j++ {
			if i < j {
				r.Set(i, j, qr.At(i, j))
			} else if i == j {
				r.Set(i, j, v)
			}
		}
	}
	return r
}

// Q generates and returns the (economy-sized) orthogonal factor.
func (f QRFactor) Q() *Dense {
	qr := f.QR
	m, n := qr.Dims()
	q := NewDense(m, n, nil)

	for k := n - 1; k >= 0; k-- {
		// for i := 0; i < m; i++ {
		// 	q.Set(i, k, 0)
		// }
		q.Set(k, k, 1)
		for j := k; j < n; j++ {
			if qr.At(k, k) != 0 {
				var s float64
				for i := k; i < m; i++ {
					s += qr.At(i, k) * q.At(i, j)
				}
				s /= -qr.At(k, k)
				for i := k; i < m; i++ {
					q.Set(i, j, q.At(i, j)+s*qr.At(i, k))
				}
			}
		}
	}

	return q
}

// Solve computes a least squares solution of a.x = b where b has as many rows as a.
// A matrix x is returned that minimizes the two norm of Q*R*X-B. QRSolve will panic
// if a is not full rank. The matrix b is overwritten during the call.
func (f QRFactor) Solve(b *Dense) (x *Dense) {
	qr, rDiag := f.QR, f.rDiag
	m, n := qr.Dims()
	bm, bn := b.Dims()
	if bm != m {
		panic(ErrShape)
	}
	if !f.IsFullRank() {
		panic("mat64: matrix is rank deficient")
	}

	x = NewDense(n, bn, use(b.mat.Data, n*bn))
	nx := bn

	// Compute Y = transpose(Q)*B
	for k := 0; k < n; k++ {
		for j := 0; j < nx; j++ {
			var s float64
			for i := k; i < n; i++ {
				s += qr.At(i, k) * x.At(i, j)
			}
			s /= -qr.At(k, k)
			for i := k; i < n; i++ {
				x.Set(i, j, x.At(i, j)+s*qr.At(i, k))
			}
		}
	}

	// Solve R*X = Y;
	for k := n - 1; k >= 0; k-- {
		for j := 0; j < nx; j++ {
			x.Set(k, j, x.At(k, j)/rDiag[k])
		}
		for i := 0; i < k; i++ {
			for j := 0; j < nx; j++ {
				x.Set(i, j, x.At(i, j)-x.At(k, j)*qr.At(i, k))
			}
		}
	}

	return x
}
<commit_msg>Enforce QRD shape restriction<commit_after>// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on the QRDecomposition class from Jama 1.0.3.

package mat64

import (
	"math"
)

type QRFactor struct {
	QR    *Dense
	rDiag []float64
}

// QR computes a QR Decomposition for an m-by-n matrix a with m >= n by Householder
// reflections, the QR decomposition is an m-by-n orthogonal matrix q and an n-by-n
// upper triangular matrix r so that a = q.r.
//
// The QR decomposition always exists, even if the matrix does not have full rank,
// so the constructor will never fail. The primary use of the QR decomposition is
// in the least squares solution of non-square systems of simultaneous linear equations.
// This will fail if QRIsFullRank() returns false. The matrix a is overwritten by the
// decomposition.
func QR(a *Dense) QRFactor {
	// Initialize.
	m, n := a.Dims()
	if m < n {
		panic(ErrShape)
	}

	qr := a
	rDiag := make([]float64, n)

	// Main loop.
	for k := 0; k < n; k++ {
		// Compute 2-norm of k-th column without under/overflow.
		var norm float64
		for i := k; i < m; i++ {
			norm = math.Hypot(norm, qr.At(i, k))
		}

		if norm != 0 {
			// Form k-th Householder vector.
			if qr.At(k, k) < 0 {
				norm = -norm
			}
			for i := k; i < m; i++ {
				qr.Set(i, k, qr.At(i, k)/norm)
			}
			qr.Set(k, k, qr.At(k, k)+1)

			// Apply transformation to remaining columns.
			for j := k + 1; j < n; j++ {
				var s float64
				for i := k; i < m; i++ {
					s += qr.At(i, k) * qr.At(i, j)
				}
				s /= -qr.At(k, k)
				for i := k; i < m; i++ {
					qr.Set(i, j, qr.At(i, j)+s*qr.At(i, k))
				}
			}
		}
		rDiag[k] = -norm
	}

	return QRFactor{qr, rDiag}
}

// IsFullRank returns whether the R matrix and hence a has full rank.
func (f QRFactor) IsFullRank() bool {
	for _, v := range f.rDiag {
		if v == 0 {
			return false
		}
	}
	return true
}

// H returns the Householder vectors in a lower trapezoidal matrix
// whose columns define the reflections.
func (f QRFactor) H() *Dense {
	qr := f.QR
	m, n := qr.Dims()
	h := NewDense(m, n, nil)
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if i >= j {
				h.Set(i, j, qr.At(i, j))
			}
		}
	}
	return h
}

// R returns the upper triangular factor for the QR decomposition.
func (f QRFactor) R() *Dense {
	qr, rDiag := f.QR, f.rDiag
	_, n := qr.Dims()
	r := NewDense(n, n, nil)
	for i, v := range rDiag[:n] {
		for j := 0; j < n; j++ {
			if i < j {
				r.Set(i, j, qr.At(i, j))
			} else if i == j {
				r.Set(i, j, v)
			}
		}
	}
	return r
}

// Q generates and returns the (economy-sized) orthogonal factor.
func (f QRFactor) Q() *Dense {
	qr := f.QR
	m, n := qr.Dims()
	q := NewDense(m, n, nil)

	for k := n - 1; k >= 0; k-- {
		// for i := 0; i < m; i++ {
		// 	q.Set(i, k, 0)
		// }
		q.Set(k, k, 1)
		for j := k; j < n; j++ {
			if qr.At(k, k) != 0 {
				var s float64
				for i := k; i < m; i++ {
					s += qr.At(i, k) * q.At(i, j)
				}
				s /= -qr.At(k, k)
				for i := k; i < m; i++ {
					q.Set(i, j, q.At(i, j)+s*qr.At(i, k))
				}
			}
		}
	}

	return q
}

// Solve computes a least squares solution of a.x = b where b has as many rows as a.
// A matrix x is returned that minimizes the two norm of Q*R*X-B. QRSolve will panic
// if a is not full rank. The matrix b is overwritten during the call.
func (f QRFactor) Solve(b *Dense) (x *Dense) {
	qr, rDiag := f.QR, f.rDiag
	m, n := qr.Dims()
	bm, bn := b.Dims()
	if bm != m {
		panic(ErrShape)
	}
	if !f.IsFullRank() {
		panic("mat64: matrix is rank deficient")
	}

	x = NewDense(n, bn, use(b.mat.Data, n*bn))
	nx := bn

	// Compute Y = transpose(Q)*B
	for k := 0; k < n; k++ {
		for j := 0; j < nx; j++ {
			var s float64
			for i := k; i < n; i++ {
				s += qr.At(i, k) * x.At(i, j)
			}
			s /= -qr.At(k, k)
			for i := k; i < n; i++ {
				x.Set(i, j, x.At(i, j)+s*qr.At(i, k))
			}
		}
	}

	// Solve R*X = Y;
	for k := n - 1; k >= 0; k-- {
		for j := 0; j < nx; j++ {
			x.Set(k, j, x.At(k, j)/rDiag[k])
		}
		for i := 0; i < k; i++ {
			for j := 0; j < nx; j++ {
				x.Set(i, j, x.At(i, j)-x.At(k, j)*qr.At(i, k))
			}
		}
	}

	return x
}
<|endoftext|>


<commit_before>package peco

import (
	"fmt"
	"os/exec"
	"regexp"
	"sort"
	"strings"
)

// Global var used to strips ansi sequences
var reANSIEscapeChars = regexp.MustCompile("\x1B\\[(?:[0-9]{1,2}(?:;[0-9]{1,2})?)*[a-zA-Z]")

// Function who strips ansi sequences
func stripANSISequence(s string) string {
	return reANSIEscapeChars.ReplaceAllString(s, "")
}

// Match defines the interface for matches. Note that to make drawing easier,
// we have a DidMatch and NoMatch types instead of using []Match and []string.
type Match interface {
	Buffer() string // Raw buffer, may contain null
	Line() string   // Line to be displayed
	Output() string // Output string to be displayed after peco is done
	Indices() [][]int
}

type matchString struct {
	buf         string
	sepLoc      int
	displayLine string
}

func newMatchString(v string, enableSep bool) *matchString {
	m := &matchString{
		v,
		-1,
		"",
	}
	if !enableSep {
		return m
	}

	// XXX This may be silly, but we're avoiding using strings.IndexByte()
	// here because it doesn't exist on go1.1. Let's remove support for
	// 1.1 when 1.4 comes out (or something)
	for i := 0; i < len(m.buf); i++ {
		if m.buf[i] == '\000' {
			m.sepLoc = i
		}
	}
	return m
}

func (m matchString) Buffer() string {
	return m.buf
}

func (m matchString) Line() string {
	if m.displayLine != "" {
		return m.displayLine
	}

	if i := m.sepLoc; i > -1 {
		m.displayLine = stripANSISequence(m.buf[:i])
	} else {
		m.displayLine = stripANSISequence(m.buf)
	}
	return m.displayLine
}

func (m matchString) Output() string {
	if i := m.sepLoc; i > -1 {
		return m.buf[i+1:]
	}
	return m.buf
}

// NoMatch is actually an alias to a regular string. It implements the
// Match interface, but just returns the underlying string with no matches
type NoMatch struct {
	*matchString
}

// NewNoMatch creates a NoMatch struct
func NewNoMatch(v string, enableSep bool) *NoMatch {
	return &NoMatch{newMatchString(v, enableSep)}
}

// Indices always returns nil
func (m NoMatch) Indices() [][]int {
	return nil
}

// DidMatch contains the actual match, and the indices to the matches
// in the line
type DidMatch struct {
	*matchString
	matches [][]int
}

// NewDidMatch creates a new DidMatch struct
func NewDidMatch(v string, enableSep bool, m [][]int) *DidMatch {
	return &DidMatch{newMatchString(v, enableSep), m}
}

// Indices returns the indices in the buffer that matched
func (d DidMatch) Indices() [][]int {
	return d.matches
}

// Matcher interface defines the API for things that want to
// match against the buffer
type Matcher interface {
	// Match takes in three parameters.
	//
	// The first chan is the channel where cancel requests are sent.
	// If you receive a request here, you should stop running your query.
	//
	// The second is the query. Do what you want with it
	//
	// The third is the buffer in which to match the query against.
	Match(chan struct{}, string, []Match) []Match
	String() string

	// This is fugly. We just added a method only for CustomMatcner.
	// Must think about this again
	Verify() error
}

// These are used as keys in the config file
const (
	IgnoreCaseMatch    = "IgnoreCase"
	CaseSensitiveMatch = "CaseSensitive"
	RegexpMatch        = "Regexp"
)

// RegexpMatcher is the most basic matcher
type RegexpMatcher struct {
	enableSep bool
	flags     []string
	quotemeta bool
}

// CaseSensitiveMatcher extends the RegxpMatcher, but always
// turns off the ignore-case flag in the regexp
type CaseSensitiveMatcher struct {
	*RegexpMatcher
}

// IgnoreCaseMatcher extends the RegexpMatcher, and always
// turns ON the ignore-case flag in the regexp
type IgnoreCaseMatcher struct {
	*RegexpMatcher
}

// CustomMatcher spawns a new process to filter the buffer
// in peco, and uses the output in its Stdout to figure
// out what to display
type CustomMatcher struct {
	enableSep bool
	name      string
	args      []string
}

// NewCaseSensitiveMatcher creates a new CaseSensitiveMatcher
func NewCaseSensitiveMatcher(enableSep bool) *CaseSensitiveMatcher {
	m := &CaseSensitiveMatcher{NewRegexpMatcher(enableSep)}
	m.quotemeta = true
	return m
}

// NewIgnoreCaseMatcher creates a new IgnoreCaseMatcher
func NewIgnoreCaseMatcher(enableSep bool) *IgnoreCaseMatcher {
	m := &IgnoreCaseMatcher{NewRegexpMatcher(enableSep)}
	m.flags = []string{"i"}
	m.quotemeta = true
	return m
}

// NewRegexpMatcher creates a new RegexpMatcher
func NewRegexpMatcher(enableSep bool) *RegexpMatcher {
	return &RegexpMatcher{
		enableSep,
		[]string{},
		false,
	}
}

// Verify always returns nil
func (m *RegexpMatcher) Verify() error {
	return nil
}

// NewCustomMatcher creates a new CustomMatcher
func NewCustomMatcher(enableSep bool, name string, args []string) *CustomMatcher {
	return &CustomMatcher{enableSep, name, args}
}

// Verify checks to see that the executable given to CustomMatcher
// is actual found and is executable via exec.LookPath
func (m *CustomMatcher) Verify() error {
	if len(m.args) == 0 {
		return fmt.Errorf("'%s' doesn't specify executable", m.name)
	}

	if _, err := exec.LookPath(m.args[0]); err != nil {
		return err
	}
	return nil
}

func regexpFor(q string, flags []string, quotemeta bool) (*regexp.Regexp, error) {
	reTxt := q
	if quotemeta {
		reTxt = regexp.QuoteMeta(q)
	}

	if flags != nil && len(flags) > 0 {
		reTxt = fmt.Sprintf("(?%s)%s", strings.Join(flags, ""), reTxt)
	}

	re, err := regexp.Compile(reTxt)
	if err != nil {
		return nil, err
	}
	return re, nil
}

func (m *RegexpMatcher) queryToRegexps(query string) ([]*regexp.Regexp, error) {
	queries := strings.Split(strings.TrimSpace(query), " ")
	regexps := make([]*regexp.Regexp, 0)

	for _, q := range queries {
		re, err := regexpFor(q, m.flags, m.quotemeta)
		if err != nil {
			return nil, err
		}
		regexps = append(regexps, re)
	}

	return regexps, nil
}

func (m *RegexpMatcher) String() string {
	return "Regexp"
}

func (m *CaseSensitiveMatcher) String() string {
	return "CaseSensitive"
}

func (m *IgnoreCaseMatcher) String() string {
	return "IgnoreCase"
}

func (m *CustomMatcher) String() string {
	return m.name
}

// sort related stuff
type byStart [][]int

func (m byStart) Len() int {
	return len(m)
}

func (m byStart) Swap(i, j int) {
	m[i], m[j] = m[j], m[i]
}

func (m byStart) Less(i, j int) bool {
	return m[i][0] < m[j][0]
}

// Match does the heavy lifting, and matches `q` against `buffer`.
// While it is doing the match, it also listens for messages
// via `quit`. If anything is received via `quit`, the match
// is halted.
func (m *RegexpMatcher) Match(quit chan struct{}, q string, buffer []Match) []Match {
	results := []Match{}
	regexps, err := m.queryToRegexps(q)
	if err != nil {
		return results
	}

	// The actual matching is done in a separate goroutine
	iter := make(chan Match, len(buffer))
	go func() {
		// This protects us from panics, caused when we cancel the
		// query and forcefully close the channel (and thereby
		// causing a "close of a closed channel"
		defer func() { recover() }()

		// This must be here to make sure the channel is properly
		// closed in normal cases
		defer close(iter)

		// Iterate through the lines, and do the match.
		// Upon success, send it through the channel
		for _, match := range buffer {
			ms := m.MatchAllRegexps(regexps, match.Line())
			if ms == nil {
				continue
			}
			iter <- NewDidMatch(match.Buffer(), m.enableSep, ms)
		}
		iter <- nil
	}()

MATCH:
	for {
		select {
		case <-quit:
			// If we recieved a cancel request, we immediately bail out.
			// It's a little dirty, but we focefully terminate the other
			// goroutine by closing the channel, and invoking a panic in the
			// goroutine above

			// There's a possibility that the match fails early and the
			// cancel happens after iter has been closed. It's totally okay
			// for us to try to close iter, but trying to detect if the
			// channel can be closed safely synchronously is really hard
			// so we punt it by letting the close() happen at a separate
			// goroutine, protected by a defer recover()
			go func() {
				defer func() { recover() }()
				close(iter)
			}()
			break MATCH
		case match := <-iter:
			// Receive elements from the goroutine performing the match
			if match == nil {
				break MATCH
			}

			results = append(results, match)
		}
	}
	return results
}

// MatchAllRegexps matches all the regexps in `regexps` against line
func (m *RegexpMatcher) MatchAllRegexps(regexps []*regexp.Regexp, line string) [][]int {
	matches := make([][]int, 0)

	allMatched := true
Match:
	for _, re := range regexps {
		match := re.FindAllStringSubmatchIndex(line, -1)
		if match == nil {
			allMatched = false
			break Match
		}

		for _, ma := range match {
			start, end := ma[0], ma[1]
			for _, m := range matches {
				if start >= m[0] && start < m[1] {
					continue Match
				}

				if start < m[0] && end >= m[0] {
					continue Match
				}
			}
			matches = append(matches, ma)
		}
	}

	if !allMatched {
		return nil
	}

	sort.Sort(byStart(matches))

	return matches
}

// Match matches `q` aginst `buffer`
func (m *CustomMatcher) Match(quit chan struct{}, q string, buffer []Match) []Match {
	if len(m.args) < 1 {
		return []Match{}
	}

	results := []Match{}
	if q == "" {
		for _, match := range buffer {
			results = append(results, NewDidMatch(match.Buffer(), m.enableSep, nil))
		}
		return results
	}

	// Receive elements from the goroutine performing the match
	lines := []Match{}
	matcherInput := ""
	for _, match := range buffer {
		matcherInput += match.Line() + "\n"
		lines = append(lines, match)
	}
	args := []string{}
	for _, arg := range m.args {
		if arg == "$QUERY" {
			arg = q
		}
		args = append(args, arg)
	}
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdin = strings.NewReader(matcherInput)

	// See RegexpMatcher.Match() for explanation of constructs
	iter := make(chan Match, len(buffer))
	go func() {
		defer func() { recover() }()
		defer func() {
			if p := cmd.Process; p != nil {
				p.Kill()
			}
			close(iter)
		}()
		b, err := cmd.Output()
		if err != nil {
			iter <- nil
		}
		for _, line := range strings.Split(string(b), "\n") {
			if len(line) > 0 {
				iter <- NewDidMatch(line, m.enableSep, nil)
			}
		}
		iter <- nil
	}()
MATCH:
	for {
		select {
		case <-quit:
			go func() {
				defer func() { recover() }()
				close(iter)
			}()
			break MATCH
		case match := <-iter:
			if match == nil {
				break MATCH
			}
			results = append(results, match)
		}
	}

	return results
}
<commit_msg>Improve error message<commit_after>package peco

import (
	"fmt"
	"os/exec"
	"regexp"
	"sort"
	"strings"
)

// Global var used to strips ansi sequences
var reANSIEscapeChars = regexp.MustCompile("\x1B\\[(?:[0-9]{1,2}(?:;[0-9]{1,2})?)*[a-zA-Z]")

// Function who strips ansi sequences
func stripANSISequence(s string) string {
	return reANSIEscapeChars.ReplaceAllString(s, "")
}

// Match defines the interface for matches. Note that to make drawing easier,
// we have a DidMatch and NoMatch types instead of using []Match and []string.
type Match interface {
	Buffer() string // Raw buffer, may contain null
	Line() string   // Line to be displayed
	Output() string // Output string to be displayed after peco is done
	Indices() [][]int
}

type matchString struct {
	buf         string
	sepLoc      int
	displayLine string
}

func newMatchString(v string, enableSep bool) *matchString {
	m := &matchString{
		v,
		-1,
		"",
	}
	if !enableSep {
		return m
	}

	// XXX This may be silly, but we're avoiding using strings.IndexByte()
	// here because it doesn't exist on go1.1. Let's remove support for
	// 1.1 when 1.4 comes out (or something)
	for i := 0; i < len(m.buf); i++ {
		if m.buf[i] == '\000' {
			m.sepLoc = i
		}
	}
	return m
}

func (m matchString) Buffer() string {
	return m.buf
}

func (m matchString) Line() string {
	if m.displayLine != "" {
		return m.displayLine
	}

	if i := m.sepLoc; i > -1 {
		m.displayLine = stripANSISequence(m.buf[:i])
	} else {
		m.displayLine = stripANSISequence(m.buf)
	}
	return m.displayLine
}

func (m matchString) Output() string {
	if i := m.sepLoc; i > -1 {
		return m.buf[i+1:]
	}
	return m.buf
}

// NoMatch is actually an alias to a regular string. It implements the
// Match interface, but just returns the underlying string with no matches
type NoMatch struct {
	*matchString
}

// NewNoMatch creates a NoMatch struct
func NewNoMatch(v string, enableSep bool) *NoMatch {
	return &NoMatch{newMatchString(v, enableSep)}
}

// Indices always returns nil
func (m NoMatch) Indices() [][]int {
	return nil
}

// DidMatch contains the actual match, and the indices to the matches
// in the line
type DidMatch struct {
	*matchString
	matches [][]int
}

// NewDidMatch creates a new DidMatch struct
func NewDidMatch(v string, enableSep bool, m [][]int) *DidMatch {
	return &DidMatch{newMatchString(v, enableSep), m}
}

// Indices returns the indices in the buffer that matched
func (d DidMatch) Indices() [][]int {
	return d.matches
}

// Matcher interface defines the API for things that want to
// match against the buffer
type Matcher interface {
	// Match takes in three parameters.
	//
	// The first chan is the channel where cancel requests are sent.
	// If you receive a request here, you should stop running your query.
	//
	// The second is the query. Do what you want with it
	//
	// The third is the buffer in which to match the query against.
	Match(chan struct{}, string, []Match) []Match
	String() string

	// This is fugly. We just added a method only for CustomMatcner.
	// Must think about this again
	Verify() error
}

// These are used as keys in the config file
const (
	IgnoreCaseMatch    = "IgnoreCase"
	CaseSensitiveMatch = "CaseSensitive"
	RegexpMatch        = "Regexp"
)

// RegexpMatcher is the most basic matcher
type RegexpMatcher struct {
	enableSep bool
	flags     []string
	quotemeta bool
}

// CaseSensitiveMatcher extends the RegxpMatcher, but always
// turns off the ignore-case flag in the regexp
type CaseSensitiveMatcher struct {
	*RegexpMatcher
}

// IgnoreCaseMatcher extends the RegexpMatcher, and always
// turns ON the ignore-case flag in the regexp
type IgnoreCaseMatcher struct {
	*RegexpMatcher
}

// CustomMatcher spawns a new process to filter the buffer
// in peco, and uses the output in its Stdout to figure
// out what to display
type CustomMatcher struct {
	enableSep bool
	name      string
	args      []string
}

// NewCaseSensitiveMatcher creates a new CaseSensitiveMatcher
func NewCaseSensitiveMatcher(enableSep bool) *CaseSensitiveMatcher {
	m := &CaseSensitiveMatcher{NewRegexpMatcher(enableSep)}
	m.quotemeta = true
	return m
}

// NewIgnoreCaseMatcher creates a new IgnoreCaseMatcher
func NewIgnoreCaseMatcher(enableSep bool) *IgnoreCaseMatcher {
	m := &IgnoreCaseMatcher{NewRegexpMatcher(enableSep)}
	m.flags = []string{"i"}
	m.quotemeta = true
	return m
}

// NewRegexpMatcher creates a new RegexpMatcher
func NewRegexpMatcher(enableSep bool) *RegexpMatcher {
	return &RegexpMatcher{
		enableSep,
		[]string{},
		false,
	}
}

// Verify always returns nil
func (m *RegexpMatcher) Verify() error {
	return nil
}

// NewCustomMatcher creates a new CustomMatcher
func NewCustomMatcher(enableSep bool, name string, args []string) *CustomMatcher {
	return &CustomMatcher{enableSep, name, args}
}

// Verify checks to see that the executable given to CustomMatcher
// is actual found and is executable via exec.LookPath
func (m *CustomMatcher) Verify() error {
	if len(m.args) == 0 {
		return fmt.Errorf("no executable specified for custom matcher '%s'", m.name)
	}

	if _, err := exec.LookPath(m.args[0]); err != nil {
		return err
	}
	return nil
}

func regexpFor(q string, flags []string, quotemeta bool) (*regexp.Regexp, error) {
	reTxt := q
	if quotemeta {
		reTxt = regexp.QuoteMeta(q)
	}

	if flags != nil && len(flags) > 0 {
		reTxt = fmt.Sprintf("(?%s)%s", strings.Join(flags, ""), reTxt)
	}

	re, err := regexp.Compile(reTxt)
	if err != nil {
		return nil, err
	}
	return re, nil
}

func (m *RegexpMatcher) queryToRegexps(query string) ([]*regexp.Regexp, error) {
	queries := strings.Split(strings.TrimSpace(query), " ")
	regexps := make([]*regexp.Regexp, 0)

	for _, q := range queries {
		re, err := regexpFor(q, m.flags, m.quotemeta)
		if err != nil {
			return nil, err
		}
		regexps = append(regexps, re)
	}

	return regexps, nil
}

func (m *RegexpMatcher) String() string {
	return "Regexp"
}

func (m *CaseSensitiveMatcher) String() string {
	return "CaseSensitive"
}

func (m *IgnoreCaseMatcher) String() string {
	return "IgnoreCase"
}

func (m *CustomMatcher) String() string {
	return m.name
}

// sort related stuff
type byStart [][]int

func (m byStart) Len() int {
	return len(m)
}

func (m byStart) Swap(i, j int) {
	m[i], m[j] = m[j], m[i]
}

func (m byStart) Less(i, j int) bool {
	return m[i][0] < m[j][0]
}

// Match does the heavy lifting, and matches `q` against `buffer`.
// While it is doing the match, it also listens for messages
// via `quit`. If anything is received via `quit`, the match
// is halted.
func (m *RegexpMatcher) Match(quit chan struct{}, q string, buffer []Match) []Match {
	results := []Match{}
	regexps, err := m.queryToRegexps(q)
	if err != nil {
		return results
	}

	// The actual matching is done in a separate goroutine
	iter := make(chan Match, len(buffer))
	go func() {
		// This protects us from panics, caused when we cancel the
		// query and forcefully close the channel (and thereby
		// causing a "close of a closed channel"
		defer func() { recover() }()

		// This must be here to make sure the channel is properly
		// closed in normal cases
		defer close(iter)

		// Iterate through the lines, and do the match.
		// Upon success, send it through the channel
		for _, match := range buffer {
			ms := m.MatchAllRegexps(regexps, match.Line())
			if ms == nil {
				continue
			}
			iter <- NewDidMatch(match.Buffer(), m.enableSep, ms)
		}
		iter <- nil
	}()

MATCH:
	for {
		select {
		case <-quit:
			// If we recieved a cancel request, we immediately bail out.
			// It's a little dirty, but we focefully terminate the other
			// goroutine by closing the channel, and invoking a panic in the
			// goroutine above

			// There's a possibility that the match fails early and the
			// cancel happens after iter has been closed. It's totally okay
			// for us to try to close iter, but trying to detect if the
			// channel can be closed safely synchronously is really hard
			// so we punt it by letting the close() happen at a separate
			// goroutine, protected by a defer recover()
			go func() {
				defer func() { recover() }()
				close(iter)
			}()
			break MATCH
		case match := <-iter:
			// Receive elements from the goroutine performing the match
			if match == nil {
				break MATCH
			}

			results = append(results, match)
		}
	}
	return results
}

// MatchAllRegexps matches all the regexps in `regexps` against line
func (m *RegexpMatcher) MatchAllRegexps(regexps []*regexp.Regexp, line string) [][]int {
	matches := make([][]int, 0)

	allMatched := true
Match:
	for _, re := range regexps {
		match := re.FindAllStringSubmatchIndex(line, -1)
		if match == nil {
			allMatched = false
			break Match
		}

		for _, ma := range match {
			start, end := ma[0], ma[1]
			for _, m := range matches {
				if start >= m[0] && start < m[1] {
					continue Match
				}

				if start < m[0] && end >= m[0] {
					continue Match
				}
			}
			matches = append(matches, ma)
		}
	}

	if !allMatched {
		return nil
	}

	sort.Sort(byStart(matches))

	return matches
}

// Match matches `q` aginst `buffer`
func (m *CustomMatcher) Match(quit chan struct{}, q string, buffer []Match) []Match {
	if len(m.args) < 1 {
		return []Match{}
	}

	results := []Match{}
	if q == "" {
		for _, match := range buffer {
			results = append(results, NewDidMatch(match.Buffer(), m.enableSep, nil))
		}
		return results
	}

	// Receive elements from the goroutine performing the match
	lines := []Match{}
	matcherInput := ""
	for _, match := range buffer {
		matcherInput += match.Line() + "\n"
		lines = append(lines, match)
	}
	args := []string{}
	for _, arg := range m.args {
		if arg == "$QUERY" {
			arg = q
		}
		args = append(args, arg)
	}
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdin = strings.NewReader(matcherInput)

	// See RegexpMatcher.Match() for explanation of constructs
	iter := make(chan Match, len(buffer))
	go func() {
		defer func() { recover() }()
		defer func() {
			if p := cmd.Process; p != nil {
				p.Kill()
			}
			close(iter)
		}()
		b, err := cmd.Output()
		if err != nil {
			iter <- nil
		}
		for _, line := range strings.Split(string(b), "\n") {
			if len(line) > 0 {
				iter <- NewDidMatch(line, m.enableSep, nil)
			}
		}
		iter <- nil
	}()
MATCH:
	for {
		select {
		case <-quit:
			go func() {
				defer func() { recover() }()
				close(iter)
			}()
			break MATCH
		case match := <-iter:
			if match == nil {
				break MATCH
			}
			results = append(results, match)
		}
	}

	return results
}
<|endoftext|>


<commit_before>// Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/Sirupsen/logrus/hooks/syslog"
	"github.com/jessevdk/go-flags"
	p "github.com/kr/pretty"
	api "github.com/osrg/gobgp/api"
	"github.com/osrg/gobgp/config"
	"github.com/osrg/gobgp/packet/bgp"
	"github.com/osrg/gobgp/server"
	"io/ioutil"
	"log/syslog"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"runtime/debug"
	"strings"
	"syscall"
)

func main() {
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGUSR1)

	var opts struct {
		ConfigFile      string `short:"f" long:"config-file" description:"specifying a config file"`
		ConfigType      string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"`
		LogLevel        string `short:"l" long:"log-level" description:"specifying log level"`
		LogPlain        bool   `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"`
		UseSyslog       string `short:"s" long:"syslog" description:"use syslogd"`
		Facility        string `long:"syslog-facility" description:"specify syslog facility"`
		DisableStdlog   bool   `long:"disable-stdlog" description:"disable standard logging"`
		CPUs            int    `long:"cpus" description:"specify the number of CPUs to be used"`
		GrpcHosts       string `long:"api-hosts" description:"specify the hosts that gobgpd listens on" default:":50051"`
		GracefulRestart bool   `short:"r" long:"graceful-restart" description:"flag restart-state in graceful-restart capability"`
		Dry             bool   `short:"d" long:"dry-run" description:"check configuration"`
		PProfHost       string `long:"pprof-host" description:"specify the host that gobgpd listens on for pprof" default:"localhost:6060"`
		PProfDisable    bool   `long:"pprof-disable" description:"disable pprof profiling"`
	}
	_, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(1)
	}

	if opts.CPUs == 0 {
		runtime.GOMAXPROCS(runtime.NumCPU())
	} else {
		if runtime.NumCPU() < opts.CPUs {
			log.Errorf("Only %d CPUs are available but %d is specified", runtime.NumCPU(), opts.CPUs)
			os.Exit(1)
		}
		runtime.GOMAXPROCS(opts.CPUs)
	}

	if !opts.PProfDisable {
		go func() {
			log.Println(http.ListenAndServe(opts.PProfHost, nil))
		}()
	}

	switch opts.LogLevel {
	case "debug":
		log.SetLevel(log.DebugLevel)
	case "info":
		log.SetLevel(log.InfoLevel)
	default:
		log.SetLevel(log.InfoLevel)
	}

	if opts.DisableStdlog == true {
		log.SetOutput(ioutil.Discard)
	} else {
		log.SetOutput(os.Stdout)
	}

	if opts.UseSyslog != "" {
		dst := strings.SplitN(opts.UseSyslog, ":", 2)
		network := ""
		addr := ""
		if len(dst) == 2 {
			network = dst[0]
			addr = dst[1]
		}

		facility := syslog.Priority(0)
		switch opts.Facility {
		case "kern":
			facility = syslog.LOG_KERN
		case "user":
			facility = syslog.LOG_USER
		case "mail":
			facility = syslog.LOG_MAIL
		case "daemon":
			facility = syslog.LOG_DAEMON
		case "auth":
			facility = syslog.LOG_AUTH
		case "syslog":
			facility = syslog.LOG_SYSLOG
		case "lpr":
			facility = syslog.LOG_LPR
		case "news":
			facility = syslog.LOG_NEWS
		case "uucp":
			facility = syslog.LOG_UUCP
		case "cron":
			facility = syslog.LOG_CRON
		case "authpriv":
			facility = syslog.LOG_AUTHPRIV
		case "ftp":
			facility = syslog.LOG_FTP
		case "local0":
			facility = syslog.LOG_LOCAL0
		case "local1":
			facility = syslog.LOG_LOCAL1
		case "local2":
			facility = syslog.LOG_LOCAL2
		case "local3":
			facility = syslog.LOG_LOCAL3
		case "local4":
			facility = syslog.LOG_LOCAL4
		case "local5":
			facility = syslog.LOG_LOCAL5
		case "local6":
			facility = syslog.LOG_LOCAL6
		case "local7":
			facility = syslog.LOG_LOCAL7
		}

		hook, err := logrus_syslog.NewSyslogHook(network, addr, syslog.LOG_INFO|facility, "bgpd")
		if err != nil {
			log.Error("Unable to connect to syslog daemon, ", opts.UseSyslog)
			os.Exit(1)
		} else {
			log.AddHook(hook)
		}
	}

	if opts.LogPlain {
		if opts.DisableStdlog {
			log.SetFormatter(&log.TextFormatter{
				DisableColors: true,
			})
		}
	} else {
		log.SetFormatter(&log.JSONFormatter{})
	}

	configCh := make(chan *config.BgpConfigSet)
	if opts.Dry {
		go config.ReadConfigfileServe(opts.ConfigFile, opts.ConfigType, configCh)
		c := <-configCh
		if opts.LogLevel == "debug" {
			p.Println(c)
		}
		os.Exit(0)
	}

	log.Info("gobgpd started")
	bgpServer := server.NewBgpServer()
	go bgpServer.Serve()

	// start grpc Server
	grpcServer := api.NewGrpcServer(bgpServer, opts.GrpcHosts)
	go func() {
		if err := grpcServer.Serve(); err != nil {
			log.Fatalf("failed to listen grpc port: %s", err)
		}
	}()

	if opts.ConfigFile != "" {
		go config.ReadConfigfileServe(opts.ConfigFile, opts.ConfigType, configCh)
	}

	var c *config.BgpConfigSet = nil
	for {
		select {
		case newConfig := <-configCh:
			var added, deleted, updated []config.Neighbor
			var updatePolicy bool

			if c == nil {
				c = newConfig
				if err := bgpServer.Start(&newConfig.Global); err != nil {
					log.Fatalf("failed to set global config: %s", err)
				}
				if newConfig.Zebra.Config.Enabled {
					if err := bgpServer.StartZebraClient(&newConfig.Zebra.Config); err != nil {
						log.Fatalf("failed to set zebra config: %s", err)
					}
				}
				if len(newConfig.Collector.Config.Url) > 0 {
					if err := bgpServer.StartCollector(&newConfig.Collector.Config); err != nil {
						log.Fatalf("failed to set collector config: %s", err)
					}
				}
				for _, c := range newConfig.RpkiServers {
					if err := bgpServer.AddRpki(&c.Config); err != nil {
						log.Fatalf("failed to set rpki config: %s", err)
					}
				}
				for _, c := range newConfig.BmpServers {
					if err := bgpServer.AddBmp(&c.Config); err != nil {
						log.Fatalf("failed to set bmp config: %s", err)
					}
				}
				for _, c := range newConfig.MrtDump {
					if len(c.Config.FileName) == 0 {
						continue
					}
					if err := bgpServer.EnableMrt(&c.Config); err != nil {
						log.Fatalf("failed to set mrt config: %s", err)
					}
				}
				p := config.ConfigSetToRoutingPolicy(newConfig)
				if err := bgpServer.UpdatePolicy(*p); err != nil {
					log.Fatalf("failed to set routing policy: %s", err)
				}

				added = newConfig.Neighbors
				if opts.GracefulRestart {
					for i, n := range added {
						if n.GracefulRestart.Config.Enabled {
							added[i].GracefulRestart.State.LocalRestarting = true
						}
					}
				}

			} else {
				added, deleted, updated, updatePolicy = config.UpdateConfig(c, newConfig)
				if updatePolicy {
					log.Info("Policy config is updated")
					p := config.ConfigSetToRoutingPolicy(newConfig)
					bgpServer.UpdatePolicy(*p)
				}
				c = newConfig
			}

			for i, p := range added {
				log.Infof("Peer %v is added", p.Config.NeighborAddress)
				if err := bgpServer.AddNeighbor(&added[i]); err != nil {
					log.Warn(err)
				}
			}
			for i, p := range deleted {
				log.Infof("Peer %v is deleted", p.Config.NeighborAddress)
				if err := bgpServer.DeleteNeighbor(&deleted[i]); err != nil {
					log.Warn(err)
				}
			}
			for i, p := range updated {
				log.Infof("Peer %v is updated", p.Config.NeighborAddress)
				u, err := bgpServer.UpdateNeighbor(&updated[i])
				if err != nil {
					log.Warn(err)
				}
				updatePolicy = updatePolicy || u
			}

			if updatePolicy {
				bgpServer.SoftResetIn("", bgp.RouteFamily(0))
			}
		case sig := <-sigCh:
			switch sig {
			case syscall.SIGKILL, syscall.SIGTERM:
				bgpServer.Shutdown()
			case syscall.SIGUSR1:
				runtime.GC()
				debug.FreeOSMemory()
			}
		}
	}
}
<commit_msg>gobgpd: support global policy assignment update via configuration file<commit_after>// Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/Sirupsen/logrus/hooks/syslog"
	"github.com/jessevdk/go-flags"
	p "github.com/kr/pretty"
	api "github.com/osrg/gobgp/api"
	"github.com/osrg/gobgp/config"
	"github.com/osrg/gobgp/packet/bgp"
	"github.com/osrg/gobgp/server"
	"github.com/osrg/gobgp/table"
	"io/ioutil"
	"log/syslog"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"runtime/debug"
	"strings"
	"syscall"
)

func main() {
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGUSR1)

	var opts struct {
		ConfigFile      string `short:"f" long:"config-file" description:"specifying a config file"`
		ConfigType      string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"`
		LogLevel        string `short:"l" long:"log-level" description:"specifying log level"`
		LogPlain        bool   `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"`
		UseSyslog       string `short:"s" long:"syslog" description:"use syslogd"`
		Facility        string `long:"syslog-facility" description:"specify syslog facility"`
		DisableStdlog   bool   `long:"disable-stdlog" description:"disable standard logging"`
		CPUs            int    `long:"cpus" description:"specify the number of CPUs to be used"`
		GrpcHosts       string `long:"api-hosts" description:"specify the hosts that gobgpd listens on" default:":50051"`
		GracefulRestart bool   `short:"r" long:"graceful-restart" description:"flag restart-state in graceful-restart capability"`
		Dry             bool   `short:"d" long:"dry-run" description:"check configuration"`
		PProfHost       string `long:"pprof-host" description:"specify the host that gobgpd listens on for pprof" default:"localhost:6060"`
		PProfDisable    bool   `long:"pprof-disable" description:"disable pprof profiling"`
	}
	_, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(1)
	}

	if opts.CPUs == 0 {
		runtime.GOMAXPROCS(runtime.NumCPU())
	} else {
		if runtime.NumCPU() < opts.CPUs {
			log.Errorf("Only %d CPUs are available but %d is specified", runtime.NumCPU(), opts.CPUs)
			os.Exit(1)
		}
		runtime.GOMAXPROCS(opts.CPUs)
	}

	if !opts.PProfDisable {
		go func() {
			log.Println(http.ListenAndServe(opts.PProfHost, nil))
		}()
	}

	switch opts.LogLevel {
	case "debug":
		log.SetLevel(log.DebugLevel)
	case "info":
		log.SetLevel(log.InfoLevel)
	default:
		log.SetLevel(log.InfoLevel)
	}

	if opts.DisableStdlog == true {
		log.SetOutput(ioutil.Discard)
	} else {
		log.SetOutput(os.Stdout)
	}

	if opts.UseSyslog != "" {
		dst := strings.SplitN(opts.UseSyslog, ":", 2)
		network := ""
		addr := ""
		if len(dst) == 2 {
			network = dst[0]
			addr = dst[1]
		}

		facility := syslog.Priority(0)
		switch opts.Facility {
		case "kern":
			facility = syslog.LOG_KERN
		case "user":
			facility = syslog.LOG_USER
		case "mail":
			facility = syslog.LOG_MAIL
		case "daemon":
			facility = syslog.LOG_DAEMON
		case "auth":
			facility = syslog.LOG_AUTH
		case "syslog":
			facility = syslog.LOG_SYSLOG
		case "lpr":
			facility = syslog.LOG_LPR
		case "news":
			facility = syslog.LOG_NEWS
		case "uucp":
			facility = syslog.LOG_UUCP
		case "cron":
			facility = syslog.LOG_CRON
		case "authpriv":
			facility = syslog.LOG_AUTHPRIV
		case "ftp":
			facility = syslog.LOG_FTP
		case "local0":
			facility = syslog.LOG_LOCAL0
		case "local1":
			facility = syslog.LOG_LOCAL1
		case "local2":
			facility = syslog.LOG_LOCAL2
		case "local3":
			facility = syslog.LOG_LOCAL3
		case "local4":
			facility = syslog.LOG_LOCAL4
		case "local5":
			facility = syslog.LOG_LOCAL5
		case "local6":
			facility = syslog.LOG_LOCAL6
		case "local7":
			facility = syslog.LOG_LOCAL7
		}

		hook, err := logrus_syslog.NewSyslogHook(network, addr, syslog.LOG_INFO|facility, "bgpd")
		if err != nil {
			log.Error("Unable to connect to syslog daemon, ", opts.UseSyslog)
			os.Exit(1)
		} else {
			log.AddHook(hook)
		}
	}

	if opts.LogPlain {
		if opts.DisableStdlog {
			log.SetFormatter(&log.TextFormatter{
				DisableColors: true,
			})
		}
	} else {
		log.SetFormatter(&log.JSONFormatter{})
	}

	configCh := make(chan *config.BgpConfigSet)
	if opts.Dry {
		go config.ReadConfigfileServe(opts.ConfigFile, opts.ConfigType, configCh)
		c := <-configCh
		if opts.LogLevel == "debug" {
			p.Println(c)
		}
		os.Exit(0)
	}

	log.Info("gobgpd started")
	bgpServer := server.NewBgpServer()
	go bgpServer.Serve()

	// start grpc Server
	grpcServer := api.NewGrpcServer(bgpServer, opts.GrpcHosts)
	go func() {
		if err := grpcServer.Serve(); err != nil {
			log.Fatalf("failed to listen grpc port: %s", err)
		}
	}()

	if opts.ConfigFile != "" {
		go config.ReadConfigfileServe(opts.ConfigFile, opts.ConfigType, configCh)
	}

	var c *config.BgpConfigSet = nil
	for {
		select {
		case newConfig := <-configCh:
			var added, deleted, updated []config.Neighbor
			var updatePolicy bool

			if c == nil {
				c = newConfig
				if err := bgpServer.Start(&newConfig.Global); err != nil {
					log.Fatalf("failed to set global config: %s", err)
				}
				if newConfig.Zebra.Config.Enabled {
					if err := bgpServer.StartZebraClient(&newConfig.Zebra.Config); err != nil {
						log.Fatalf("failed to set zebra config: %s", err)
					}
				}
				if len(newConfig.Collector.Config.Url) > 0 {
					if err := bgpServer.StartCollector(&newConfig.Collector.Config); err != nil {
						log.Fatalf("failed to set collector config: %s", err)
					}
				}
				for _, c := range newConfig.RpkiServers {
					if err := bgpServer.AddRpki(&c.Config); err != nil {
						log.Fatalf("failed to set rpki config: %s", err)
					}
				}
				for _, c := range newConfig.BmpServers {
					if err := bgpServer.AddBmp(&c.Config); err != nil {
						log.Fatalf("failed to set bmp config: %s", err)
					}
				}
				for _, c := range newConfig.MrtDump {
					if len(c.Config.FileName) == 0 {
						continue
					}
					if err := bgpServer.EnableMrt(&c.Config); err != nil {
						log.Fatalf("failed to set mrt config: %s", err)
					}
				}
				p := config.ConfigSetToRoutingPolicy(newConfig)
				if err := bgpServer.UpdatePolicy(*p); err != nil {
					log.Fatalf("failed to set routing policy: %s", err)
				}

				added = newConfig.Neighbors
				if opts.GracefulRestart {
					for i, n := range added {
						if n.GracefulRestart.Config.Enabled {
							added[i].GracefulRestart.State.LocalRestarting = true
						}
					}
				}

			} else {
				added, deleted, updated, updatePolicy = config.UpdateConfig(c, newConfig)
				if updatePolicy {
					log.Info("Policy config is updated")
					p := config.ConfigSetToRoutingPolicy(newConfig)
					bgpServer.UpdatePolicy(*p)
				}
				// global policy update
				if !newConfig.Global.ApplyPolicy.Config.Equal(&c.Global.ApplyPolicy.Config) {
					a := newConfig.Global.ApplyPolicy.Config
					toDefaultTable := func(r config.DefaultPolicyType) table.RouteType {
						var def table.RouteType
						switch r {
						case config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE:
							def = table.ROUTE_TYPE_ACCEPT
						case config.DEFAULT_POLICY_TYPE_REJECT_ROUTE:
							def = table.ROUTE_TYPE_REJECT
						}
						return def
					}
					toPolicyDefinitions := func(r []string) []*config.PolicyDefinition {
						p := make([]*config.PolicyDefinition, 0, len(r))
						for _, n := range r {
							p = append(p, &config.PolicyDefinition{
								Name: n,
							})
						}
						return p
					}

					def := toDefaultTable(a.DefaultImportPolicy)
					ps := toPolicyDefinitions(a.ImportPolicyList)
					bgpServer.ReplacePolicyAssignment("", table.POLICY_DIRECTION_IMPORT, ps, def)

					def = toDefaultTable(a.DefaultExportPolicy)
					ps = toPolicyDefinitions(a.ExportPolicyList)
					bgpServer.ReplacePolicyAssignment("", table.POLICY_DIRECTION_EXPORT, ps, def)

					updatePolicy = true

				}
				c = newConfig
			}

			for i, p := range added {
				log.Infof("Peer %v is added", p.Config.NeighborAddress)
				if err := bgpServer.AddNeighbor(&added[i]); err != nil {
					log.Warn(err)
				}
			}
			for i, p := range deleted {
				log.Infof("Peer %v is deleted", p.Config.NeighborAddress)
				if err := bgpServer.DeleteNeighbor(&deleted[i]); err != nil {
					log.Warn(err)
				}
			}
			for i, p := range updated {
				log.Infof("Peer %v is updated", p.Config.NeighborAddress)
				u, err := bgpServer.UpdateNeighbor(&updated[i])
				if err != nil {
					log.Warn(err)
				}
				updatePolicy = updatePolicy || u
			}

			if updatePolicy {
				bgpServer.SoftResetIn("", bgp.RouteFamily(0))
			}
		case sig := <-sigCh:
			switch sig {
			case syscall.SIGKILL, syscall.SIGTERM:
				bgpServer.Shutdown()
			case syscall.SIGUSR1:
				runtime.GC()
				debug.FreeOSMemory()
			}
		}
	}
}
<|endoftext|>