<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	// "log"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/cors"
	"github.com/martini-contrib/render"
	"os"
	"strings"
)

var session *mgo.Session
var collection *mgo.Collection
var err error

type Torrent struct {
	Btih     string `bson:"_id,omitempty"`
	Title    []string
	Category []string
	Details  []string
	Download []string
}

func main() {
	// Try to connect to the database
	session, err = mgo.Dial("10.0.1.12")
	if err != nil {
		fmt.Println("Couldn't connect to Mongo. Please make sure it is installed and running.")
		return
	}
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	collection = session.DB("bitcannon").C("torrents")
	collection.EnsureIndex(mgo.Index{Key: []string{"$text:title"}, Name: "title"})

	if len(os.Args) > 1 {
		importFile(os.Args[1])
	} else {
		runServer()
	}
}

func runServer() {
	fmt.Println("Starting the API server.")
	m := martini.Classic()
	m.Use(render.Renderer())
	m.Use(cors.Allow(&cors.Options{
		AllowOrigins:  []string{"*"},
		AllowMethods:  []string{"POST", "GET"},
		ExposeHeaders: []string{"Content-Length"},
	}))
	m.Get("/stats", func(r render.Render) {
		count, err := collection.Count()
		if err != nil {
			r.JSON(500, map[string]interface{}{"count": "API Error"})
			return
		}
		r.JSON(200, map[string]interface{}{"count": count})
	})
	m.Get("/browse", func(r render.Render) {
		var result []string
		err := collection.Find(nil).Distinct("category", &result)
		if err != nil {
			r.JSON(500, map[string]interface{}{"error": "API Error"})
			return
		}
		var size int
		for size = range result {
		}
		stats := make([]map[string]interface{}, size+1, size+1)
		for i, cat := range result {
			total, err := collection.Find(bson.M{"category": cat}).Count()
			if err != nil {
				stats[i] = map[string]interface{}{cat: 0}
			} else {
				stats[i] = map[string]interface{}{"name": cat, "count": total}
			}
		}
		r.JSON(200, stats)
	})
	m.Get("/torrent/:btih", func(r render.Render, params martini.Params) {
		result := Torrent{}
		err = collection.Find(bson.M{"_id": params["btih"]}).One(&result)
		if err != nil {
			r.JSON(404, map[string]interface{}{"message": "Torrent not found."})
			return
		}
		r.JSON(200, result)
	})
	m.Get("/search/:query", func(r render.Render, params martini.Params) {
		result := []Torrent{}
		pipe := collection.Pipe([]bson.M{
			{"$match": bson.M{"$text": bson.M{"$search": params["query"]}}},
			{"$sort": bson.M{"score": bson.M{"$meta": "textScore"}}},
		})
		iter := pipe.Iter()
		err = iter.All(&result)
		if err != nil {
			r.JSON(404, map[string]interface{}{"message": err.Error()})
			return
		}
		r.JSON(200, result)
	})
	m.RunOnAddr(":1337")
}

func importFile(filename string) {
	fmt.Print("Attempting to parse ")
	fmt.Println(filename)

	file, err := os.Open(filename)
	if err != nil {
		fmt.Println("Error opening the file. Make sure it exists and is readable.")
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	imported := 0
	skipped := 0
	for scanner.Scan() {
		status, _ := importLine(scanner.Text())
		if status {
			imported++
		} else {
			skipped++
		}
	}

	fmt.Println("File parsing ended.")
	fmt.Print("New: ")
	fmt.Println(imported)
	fmt.Print("Dup: ")
	fmt.Println(skipped)

	if err := scanner.Err(); err != nil {
		fmt.Println("The program encountered an error while reading the file. Ensure that the file isn't corrupted.")
		return
	}
}

func importLine(line string) (bool, error) {
	if strings.Count(line, "|") != 4 {
		return false, errors.New("Something's up with this torrent. Expected 5 values separated by |.")
	}
	data := strings.Split(line, "|")
	return importHash(data[0], data[1], data[2], data[3], data[4])
}

// hash, title, category, details, download /*hash string, title string, category string, details string*/
func importHash(btih string, title string, category string, details string, download string) (bool, error) {
	err := collection.Insert(&Torrent{Btih: btih, Title: []string{title}, Category: []string{category}, Details: []string{details}, Download: []string{download}})
	if err != nil {
		return false, errors.New("Something went wrong when trying to insert.")
	}
	return true, nil
}
<commit_msg>Add category endpoint.<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	// "log"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/cors"
	"github.com/martini-contrib/render"
	"os"
	"strings"
)

var session *mgo.Session
var collection *mgo.Collection
var err error

const resultLimit int = 100

type Torrent struct {
	Btih     string `bson:"_id,omitempty"`
	Title    []string
	Category []string
	Details  []string
	Download []string
}

func main() {
	// Try to connect to the database
	session, err = mgo.Dial("10.0.1.12")
	if err != nil {
		fmt.Println("Couldn't connect to Mongo. Please make sure it is installed and running.")
		return
	}
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	collection = session.DB("bitcannon").C("torrents")
	collection.EnsureIndex(mgo.Index{Key: []string{"$text:title"}, Name: "title"})

	if len(os.Args) > 1 {
		importFile(os.Args[1])
	} else {
		runServer()
	}
}

func runServer() {
	fmt.Println("Starting the API server.")
	m := martini.Classic()
	m.Use(render.Renderer())
	m.Use(cors.Allow(&cors.Options{
		AllowOrigins:  []string{"*"},
		AllowMethods:  []string{"POST", "GET"},
		ExposeHeaders: []string{"Content-Length"},
	}))
	m.Get("/stats", func(r render.Render) {
		count, err := collection.Count()
		if err != nil {
			r.JSON(500, map[string]interface{}{"count": "API Error"})
			return
		}
		r.JSON(200, map[string]interface{}{"count": count})
	})
	m.Get("/browse", func(r render.Render) {
		var result []string
		err := collection.Find(nil).Distinct("category", &result)
		if err != nil {
			r.JSON(500, map[string]interface{}{"error": "API Error"})
			return
		}
		var size int
		for size = range result {
		}
		stats := make([]map[string]interface{}, size+1, size+1)
		for i, cat := range result {
			total, err := collection.Find(bson.M{"category": cat}).Count()
			if err != nil {
				stats[i] = map[string]interface{}{cat: 0}
			} else {
				stats[i] = map[string]interface{}{"name": cat, "count": total}
			}
		}
		r.JSON(200, stats)
	})
	m.Get("/browse/:category", func(r render.Render, params martini.Params) {
		result := []Torrent{}
		err = collection.Find(bson.M{"category": params["category"]}).Limit(resultLimit).All(&result)
		if err != nil {
			r.JSON(404, map[string]interface{}{"message": err.Error()})
			return
		}
		r.JSON(200, result)
	})
	m.Get("/torrent/:btih", func(r render.Render, params martini.Params) {
		result := Torrent{}
		err = collection.Find(bson.M{"_id": params["btih"]}).One(&result)
		if err != nil {
			r.JSON(404, map[string]interface{}{"message": "Torrent not found."})
			return
		}
		r.JSON(200, result)
	})
	m.Get("/search/:query", func(r render.Render, params martini.Params) {
		result := []Torrent{}
		pipe := collection.Pipe([]bson.M{
			{"$match": bson.M{"$text": bson.M{"$search": params["query"]}}},
			{"$sort": bson.M{"score": bson.M{"$meta": "textScore"}}},
		})
		iter := pipe.Iter()
		err = iter.All(&result)
		if err != nil {
			r.JSON(404, map[string]interface{}{"message": err.Error()})
			return
		}
		r.JSON(200, result)
	})
	m.RunOnAddr(":1337")
}

func importFile(filename string) {
	fmt.Print("Attempting to parse ")
	fmt.Println(filename)

	file, err := os.Open(filename)
	if err != nil {
		fmt.Println("Error opening the file. Make sure it exists and is readable.")
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	imported := 0
	skipped := 0
	for scanner.Scan() {
		status, _ := importLine(scanner.Text())
		if status {
			imported++
		} else {
			skipped++
		}
	}

	fmt.Println("File parsing ended.")
	fmt.Print("New: ")
	fmt.Println(imported)
	fmt.Print("Dup: ")
	fmt.Println(skipped)

	if err := scanner.Err(); err != nil {
		fmt.Println("The program encountered an error while reading the file. Ensure that the file isn't corrupted.")
		return
	}
}

func importLine(line string) (bool, error) {
	if strings.Count(line, "|") != 4 {
		return false, errors.New("Something's up with this torrent. Expected 5 values separated by |.")
	}
	data := strings.Split(line, "|")
	return importHash(data[0], data[1], data[2], data[3], data[4])
}

// hash, title, category, details, download /*hash string, title string, category string, details string*/
func importHash(btih string, title string, category string, details string, download string) (bool, error) {
	err := collection.Insert(&Torrent{Btih: btih, Title: []string{title}, Category: []string{category}, Details: []string{details}, Download: []string{download}})
	if err != nil {
		return false, errors.New("Something went wrong when trying to insert.")
	}
	return true, nil
}
<|endoftext|>


<commit_before>/*
Package jaegertracing provides middleware to Opentracing using Jaeger.

Example:
```
package main
import (
    "github.com/labstack/echo-contrib/jaegertracing"
    "github.com/labstack/echo/v4"
)
func main() {
    e := echo.New()
    // Enable tracing middleware
    c := jaegertracing.New(e, nil)
    defer c.Close()

    e.Logger.Fatal(e.Start(":1323"))
}
```
*/
package jaegertracing

import (
	"fmt"
	"io"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"github.com/uber/jaeger-client-go/config"
)

const defaultComponentName = "echo/v4"

type (
	// TraceConfig defines the config for Trace middleware.
	TraceConfig struct {
		// Skipper defines a function to skip middleware.
		Skipper middleware.Skipper

		// OpenTracing Tracer instance which should be got before
		Tracer opentracing.Tracer

		// componentName used for describing the tracing component name
		componentName string
	}
)

var (
	// DefaultTraceConfig is the default Trace middleware config.
	DefaultTraceConfig = TraceConfig{
		Skipper:       middleware.DefaultSkipper,
		componentName: defaultComponentName,
	}
)

// New creates an Opentracing tracer and attaches it to Echo middleware.
// Returns Closer do be added to caller function as `defer closer.Close()`
func New(e *echo.Echo, skipper middleware.Skipper) io.Closer {
	// Add Opentracing instrumentation
	defcfg := config.Configuration{
		ServiceName: "echo-tracer",
		Sampler: &config.SamplerConfig{
			Type:  "const",
			Param: 1,
		},
		Reporter: &config.ReporterConfig{
			LogSpans:            true,
			BufferFlushInterval: 1 * time.Second,
		},
	}
	cfg, err := defcfg.FromEnv()
	if err != nil {
		panic("Could not parse Jaeger env vars: " + err.Error())
	}
	tracer, closer, err := cfg.NewTracer()
	if err != nil {
		panic("Could not initialize jaeger tracer: " + err.Error())
	}

	opentracing.SetGlobalTracer(tracer)
	e.Use(TraceWithConfig(TraceConfig{
		Tracer:  tracer,
		Skipper: skipper,
	}))
	return closer
}

// Trace returns a Trace middleware.
//
// Trace middleware traces http requests and reporting errors.
func Trace(tracer opentracing.Tracer) echo.MiddlewareFunc {
	c := DefaultTraceConfig
	c.Tracer = tracer
	c.componentName = defaultComponentName
	return TraceWithConfig(c)
}

// TraceWithConfig returns a Trace middleware with config.
// See: `Trace()`.
func TraceWithConfig(config TraceConfig) echo.MiddlewareFunc {
	if config.Tracer == nil {
		panic("echo: trace middleware requires opentracing tracer")
	}
	if config.Skipper == nil {
		config.Skipper = middleware.DefaultSkipper
	}
	if config.componentName == "" {
		config.componentName = defaultComponentName
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			req := c.Request()
			opname := "HTTP " + req.Method + " URL: " + c.Path()
			var sp opentracing.Span
			tr := config.Tracer
			if ctx, err := tr.Extract(opentracing.HTTPHeaders,
				opentracing.HTTPHeadersCarrier(req.Header)); err != nil {
				sp = tr.StartSpan(opname)
			} else {
				sp = tr.StartSpan(opname, ext.RPCServerOption(ctx))
			}

			ext.HTTPMethod.Set(sp, req.Method)
			ext.HTTPUrl.Set(sp, req.URL.String())
			ext.Component.Set(sp, config.componentName)

			req = req.WithContext(opentracing.ContextWithSpan(req.Context(), sp))
			c.SetRequest(req)

			defer func() {
				status := c.Response().Status
				committed := c.Response().Committed
				ext.HTTPStatusCode.Set(sp, uint16(status))
				if status >= http.StatusInternalServerError || !committed {
					ext.Error.Set(sp, true)
				}
				sp.Finish()
			}()
			return next(c)
		}
	}
}

// TraceFunction wraps funtion with opentracing span adding tags for the function name and caller details
func TraceFunction(ctx echo.Context, fn interface{}, params ...interface{}) (result []reflect.Value) {
	// Get function name
	name := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
	// Create child span
	parentSpan := opentracing.SpanFromContext(ctx.Request().Context())
	sp := opentracing.StartSpan(
		"Function - "+name,
		opentracing.ChildOf(parentSpan.Context()))
	defer sp.Finish()

	sp.SetTag("function", name)

	// Get caller function name, file and line
	pc := make([]uintptr, 15)
	n := runtime.Callers(2, pc)
	frames := runtime.CallersFrames(pc[:n])
	frame, _ := frames.Next()
	callerDetails := fmt.Sprintf("%s - %s#%d", frame.Function, frame.File, frame.Line)
	sp.SetTag("caller", callerDetails)

	// Check params and call function
	f := reflect.ValueOf(fn)
	if f.Type().NumIn() != len(params) {
		panic("incorrect number of parameters!")
	}
	inputs := make([]reflect.Value, len(params))
	for k, in := range params {
		inputs[k] = reflect.ValueOf(in)
	}
	return f.Call(inputs)
}

// CreateChildSpan creates a new opentracing span adding tags for the span name and caller details.
// User must call defer `sp.Finish()`
func CreateChildSpan(ctx echo.Context, name string) opentracing.Span {
	parentSpan := opentracing.SpanFromContext(ctx.Request().Context())
	sp := opentracing.StartSpan(
		name,
		opentracing.ChildOf(parentSpan.Context()))
	sp.SetTag("name", name)

	// Get caller function name, file and line
	pc := make([]uintptr, 15)
	n := runtime.Callers(2, pc)
	frames := runtime.CallersFrames(pc[:n])
	frame, _ := frames.Next()
	callerDetails := fmt.Sprintf("%s - %s#%d", frame.Function, frame.File, frame.Line)
	sp.SetTag("caller", callerDetails)

	return sp
}

// NewTracedRequest generates a new traced HTTP request with opentracing headers injected into it
func NewTracedRequest(method string, url string, body io.Reader, span opentracing.Span) (*http.Request, error) {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		panic(err.Error())
	}

	ext.SpanKindRPCClient.Set(span)
	ext.HTTPUrl.Set(span, url)
	ext.HTTPMethod.Set(span, method)
	span.Tracer().Inject(span.Context(),
		opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(req.Header))

	return req, err
}
<commit_msg>Improve message on divergent number of params<commit_after>/*
Package jaegertracing provides middleware to Opentracing using Jaeger.

Example:
```
package main
import (
    "github.com/labstack/echo-contrib/jaegertracing"
    "github.com/labstack/echo/v4"
)
func main() {
    e := echo.New()
    // Enable tracing middleware
    c := jaegertracing.New(e, nil)
    defer c.Close()

    e.Logger.Fatal(e.Start(":1323"))
}
```
*/
package jaegertracing

import (
	"fmt"
	"io"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"github.com/uber/jaeger-client-go/config"
)

const defaultComponentName = "echo/v4"

type (
	// TraceConfig defines the config for Trace middleware.
	TraceConfig struct {
		// Skipper defines a function to skip middleware.
		Skipper middleware.Skipper

		// OpenTracing Tracer instance which should be got before
		Tracer opentracing.Tracer

		// componentName used for describing the tracing component name
		componentName string
	}
)

var (
	// DefaultTraceConfig is the default Trace middleware config.
	DefaultTraceConfig = TraceConfig{
		Skipper:       middleware.DefaultSkipper,
		componentName: defaultComponentName,
	}
)

// New creates an Opentracing tracer and attaches it to Echo middleware.
// Returns Closer do be added to caller function as `defer closer.Close()`
func New(e *echo.Echo, skipper middleware.Skipper) io.Closer {
	// Add Opentracing instrumentation
	defcfg := config.Configuration{
		ServiceName: "echo-tracer",
		Sampler: &config.SamplerConfig{
			Type:  "const",
			Param: 1,
		},
		Reporter: &config.ReporterConfig{
			LogSpans:            true,
			BufferFlushInterval: 1 * time.Second,
		},
	}
	cfg, err := defcfg.FromEnv()
	if err != nil {
		panic("Could not parse Jaeger env vars: " + err.Error())
	}
	tracer, closer, err := cfg.NewTracer()
	if err != nil {
		panic("Could not initialize jaeger tracer: " + err.Error())
	}

	opentracing.SetGlobalTracer(tracer)
	e.Use(TraceWithConfig(TraceConfig{
		Tracer:  tracer,
		Skipper: skipper,
	}))
	return closer
}

// Trace returns a Trace middleware.
// Trace middleware traces http requests and reporting errors.
func Trace(tracer opentracing.Tracer) echo.MiddlewareFunc {
	c := DefaultTraceConfig
	c.Tracer = tracer
	c.componentName = defaultComponentName
	return TraceWithConfig(c)
}

// TraceWithConfig returns a Trace middleware with config.
// See: `Trace()`.
func TraceWithConfig(config TraceConfig) echo.MiddlewareFunc {
	if config.Tracer == nil {
		panic("echo: trace middleware requires opentracing tracer")
	}
	if config.Skipper == nil {
		config.Skipper = middleware.DefaultSkipper
	}
	if config.componentName == "" {
		config.componentName = defaultComponentName
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			req := c.Request()
			opname := "HTTP " + req.Method + " URL: " + c.Path()
			var sp opentracing.Span
			tr := config.Tracer
			if ctx, err := tr.Extract(opentracing.HTTPHeaders,
				opentracing.HTTPHeadersCarrier(req.Header)); err != nil {
				sp = tr.StartSpan(opname)
			} else {
				sp = tr.StartSpan(opname, ext.RPCServerOption(ctx))
			}

			ext.HTTPMethod.Set(sp, req.Method)
			ext.HTTPUrl.Set(sp, req.URL.String())
			ext.Component.Set(sp, config.componentName)

			req = req.WithContext(opentracing.ContextWithSpan(req.Context(), sp))
			c.SetRequest(req)

			defer func() {
				status := c.Response().Status
				committed := c.Response().Committed
				ext.HTTPStatusCode.Set(sp, uint16(status))
				if status >= http.StatusInternalServerError || !committed {
					ext.Error.Set(sp, true)
				}
				sp.Finish()
			}()
			return next(c)
		}
	}
}

// TraceFunction wraps funtion with opentracing span adding tags for the function name and caller details
func TraceFunction(ctx echo.Context, fn interface{}, params ...interface{}) (result []reflect.Value) {
	// Get function name
	name := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
	// Create child span
	parentSpan := opentracing.SpanFromContext(ctx.Request().Context())
	sp := opentracing.StartSpan(
		"Function - "+name,
		opentracing.ChildOf(parentSpan.Context()))
	defer sp.Finish()

	sp.SetTag("function", name)

	// Get caller function name, file and line
	pc := make([]uintptr, 15)
	n := runtime.Callers(2, pc)
	frames := runtime.CallersFrames(pc[:n])
	frame, _ := frames.Next()
	callerDetails := fmt.Sprintf("%s - %s#%d", frame.Function, frame.File, frame.Line)
	sp.SetTag("caller", callerDetails)

	// Check params and call function
	f := reflect.ValueOf(fn)
	if f.Type().NumIn() != len(params) {
		e := fmt.Sprintf("Incorrect number of parameters calling wrapped function %s", name)
		panic(e)
	}
	inputs := make([]reflect.Value, len(params))
	for k, in := range params {
		inputs[k] = reflect.ValueOf(in)
	}
	return f.Call(inputs)
}

// CreateChildSpan creates a new opentracing span adding tags for the span name and caller details.
// User must call defer `sp.Finish()`
func CreateChildSpan(ctx echo.Context, name string) opentracing.Span {
	parentSpan := opentracing.SpanFromContext(ctx.Request().Context())
	sp := opentracing.StartSpan(
		name,
		opentracing.ChildOf(parentSpan.Context()))
	sp.SetTag("name", name)

	// Get caller function name, file and line
	pc := make([]uintptr, 15)
	n := runtime.Callers(2, pc)
	frames := runtime.CallersFrames(pc[:n])
	frame, _ := frames.Next()
	callerDetails := fmt.Sprintf("%s - %s#%d", frame.Function, frame.File, frame.Line)
	sp.SetTag("caller", callerDetails)

	return sp
}

// NewTracedRequest generates a new traced HTTP request with opentracing headers injected into it
func NewTracedRequest(method string, url string, body io.Reader, span opentracing.Span) (*http.Request, error) {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		panic(err.Error())
	}

	ext.SpanKindRPCClient.Set(span)
	ext.HTTPUrl.Set(span, url)
	ext.HTTPMethod.Set(span, method)
	span.Tracer().Inject(span.Context(),
		opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(req.Header))

	return req, err
}
<|endoftext|>


<commit_before>package colorstring

import (
	"testing"
)

func TestColor(t *testing.T) {
	cases := []struct {
		Input, Output string
	}{
		{
			Input:  "foo",
			Output: "foo",
		},

		{
			Input:  "[blue]foo",
			Output: "\033[34mfoo\033[0m",
		},

		{
			Input:  "foo[blue]foo",
			Output: "foo\033[34mfoo\033[0m",
		},

		{
			Input:  "foo[what]foo",
			Output: "foo[what]foo",
		},
	}

	for _, tc := range cases {
		actual := Color(tc.Input)
		if actual != tc.Output {
			t.Errorf(
				"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
				tc.Input,
				actual,
				tc.Output)
		}
	}
}

func TestColorizeColor_disable(t *testing.T) {
	c := def
	c.Disable = true

	input := "[blue]foo"
	output := "foo"
	actual := c.Color(input)
	if actual != output {
		t.Errorf(
			"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
			input,
			actual,
			output)
	}
}

func TestColorizeColor_noReset(t *testing.T) {
	c := def
	c.Reset = false

	input := "[blue]foo"
	output := "\033[34mfoo"
	actual := c.Color(input)
	if actual != output {
		t.Errorf(
			"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
			input,
			actual,
			output)
	}
}
<commit_msg>Improve tests for documentation<commit_after>package colorstring

import (
	"testing"
)

func TestColor(t *testing.T) {
	cases := []struct {
		Input, Output string
	}{
		{
			Input:  "foo",
			Output: "foo",
		},

		{
			Input:  "[blue]foo",
			Output: "\033[34mfoo\033[0m",
		},

		{
			Input:  "foo[blue]foo",
			Output: "foo\033[34mfoo\033[0m",
		},

		{
			Input:  "foo[what]foo",
			Output: "foo[what]foo",
		},
		{
			Input: "foo[_blue_]foo",
			Output: "foo\033[44mfoo\033[0m",
		},
		{
			Input: "foo[bold]foo",
			Output: "foo\033[1mfoo\033[0m",
		},
		{
			Input: "[blue]foo[bold]bar",
			Output: "\033[34mfoo\033[1mbar\033[0m",
		},
		{
			Input: "[underline]foo[reset]bar",
			Output: "\033[4mfoo\033[0mbar\033[0m",
		},
	}

	for _, tc := range cases {
		actual := Color(tc.Input)
		if actual != tc.Output {
			t.Errorf(
				"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
				tc.Input,
				actual,
				tc.Output)
		}
	}
}

func TestColorizeColor_disable(t *testing.T) {
	c := def
	c.Disable = true

	input := "[blue]foo"
	output := "foo"
	actual := c.Color(input)
	if actual != output {
		t.Errorf(
			"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
			input,
			actual,
			output)
	}
}

func TestColorizeColor_noReset(t *testing.T) {
	c := def
	c.Reset = false

	input := "[blue]foo"
	output := "\033[34mfoo"
	actual := c.Color(input)
	if actual != output {
		t.Errorf(
			"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
			input,
			actual,
			output)
	}
}
<|endoftext|>


<commit_before>package stardict

import (
	"bufio"
	"errors"
	"io"
	"os"
	"strings"
)

// Info contains dictionary options
type Info struct {
	Version string
	Is64    bool
	Options map[string]string
}

func decodeOption(str string) (key string, value string, err error) {
	a := strings.Split(str, "=")

	if len(a) < 2 {
		return "", "", errors.New("Invalid file format: " + str)
	}

	return a[0], a[1], nil
}

// ReadInfo reads ifo file and collects dictionary options
func ReadInfo(filename string) (info *Info, err error) {
	reader, err := os.Open(filename)
	if err != nil {
		return
	}

	defer reader.Close()

	r := bufio.NewReader(reader)

	_, err = r.ReadString('\n')

	if err != nil {
		return
	}

	version, err := r.ReadString('\n')

	if err != nil {
		return
	}

	kn, kv, err := decodeOption(version[:len(version)-1])

	if err != nil {
		return
	}

	if kn != "version" {
		err = errors.New("Version missing (should be on second line)")
		return
	}

	if kv != "2.4.2" && kv != "3.0.0" {
		err = errors.New("Stardict version should be either 2.4.2 or 3.0.0")
		return
	}

	info = new(Info)

	info.Version = kv

	info.Options = make(map[string]string)

	for {
		option, err := r.ReadString('\n')

		if err != nil && err != io.EOF {
			return info, err
		}

		if err == io.EOF && len(option) == 0 {
			break
		}

		kn, kv, err = decodeOption(option[:len(option)-1])

		if err != nil {
			return info, err
		}

		info.Options[kn] = kv

		if err == io.EOF {
			break
		}
	}

	if val, ok := info.Options["idxoffsetbits"]; ok {
		if val == "64" {
			info.Is64 = true
		}
	} else {
		info.Is64 = false
	}

	return
}
<commit_msg>fix : kv == 2.4.2\r on windows<commit_after>package stardict

import (
	"bufio"
	"errors"
	"io"
	"os"
	"strings"
)

// Info contains dictionary options
type Info struct {
	Version string
	Is64    bool
	Options map[string]string
}

func decodeOption(str string) (key string, value string, err error) {
	a := strings.Split(str, "=")

	if len(a) < 2 {
		return "", "", errors.New("Invalid file format: " + str)
	}

	return a[0], a[1], nil
}

// ReadInfo reads ifo file and collects dictionary options
func ReadInfo(filename string) (info *Info, err error) {
	reader, err := os.Open(filename)
	if err != nil {
		return
	}

	defer reader.Close()

	r := bufio.NewReader(reader)

	_, err = r.ReadString('\n')

	if err != nil {
		return
	}

	version, err := r.ReadString('\n')

	if err != nil {
		return
	}

	kn, kv, err := decodeOption(version[:len(version)-1])

	if err != nil {
		return
	}

	if kn != "version" {
		err = errors.New("Version missing (should be on second line)")
		return
	}

	if kv != "2.4.2" && kv != "3.0.0" && kv != "2.4.2\r" &&kv != "3.0.0\r"{    // \r : fix the problem on windows
		err = errors.New("Stardict version should be either 2.4.2 or 3.0.0")
		return
	}

	info = new(Info)

	info.Version = kv

	info.Options = make(map[string]string)

	for {
		option, err := r.ReadString('\n')

		if err != nil && err != io.EOF {
			return info, err
		}

		if err == io.EOF && len(option) == 0 {
			break
		}

		kn, kv, err = decodeOption(option[:len(option)-1])

		if err != nil {
			return info, err
		}

		info.Options[kn] = kv

		if err == io.EOF {
			break
		}
	}

	if val, ok := info.Options["idxoffsetbits"]; ok {
		if val == "64" {
			info.Is64 = true
		}
	} else {
		info.Is64 = false
	}

	return
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Thomas Lokshall
// Use of this source code is governed by the MIT license.
// See LICENSE.md for details.

// Package gocfg implements a way to easily read and write YAML configuration files.
package gocfg

import (
	"fmt"
	"io/ioutil"
	"reflect"

	yaml "gopkg.in/yaml.v1"
)

// Configuration contains the loaded configuration and functions to manipulate it.
type Configuration struct {
	values map[string]interface{}
}

// NewConfiguration returns a new Configuration.
func NewConfiguration() *Configuration {
	return &Configuration{
		values: make(map[string]interface{}),
	}
}

// Load parses the YAML in data to it's internal map.
func (cfg Configuration) Load(data string) error {
	m := make(map[interface{}]interface{})
	if err := yaml.Unmarshal([]byte(data), &m); err != nil {
		return err
	}
	cfg.loadMap(m, "")
	return nil
}

// loadMap parses a loaded map structure and adds it to the current configuration.
// The prefix will be added before all values.
func (cfg Configuration) loadMap(m map[interface{}]interface{}, prefix string) {
	for k, v := range m {
		if reflect.TypeOf(v).Kind() == reflect.Map {
			p := fmt.Sprintf("%s%s.", prefix, k.(string))
			cfg.loadMap(v.(map[interface{}]interface{}), p)
		} else {
			s := fmt.Sprintf("%s%s", prefix, k.(string))
			cfg.values[s] = v
		}
	}
}

// Save returns the current configuration in YAML format.
func (cfg Configuration) Save() (string, error) {
	b, err := yaml.Marshal(&cfg.values)
	return string(b), err
}

// LoadFile reads a specified file into memory and parses it using Load().
func (cfg Configuration) LoadFile(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	yml := string(b[:])
	return cfg.Load(yml)
}

// SaveFile writes the output from Save() to the specified file.
func (cfg Configuration) SaveFile(path string) error {
	yml, err := cfg.Save()
	if err == nil {
		err = ioutil.WriteFile(path, []byte(yml), 0644)
	}
	return err
}

// Set sets a given value in the configuration to an arbitrary type.
func (cfg Configuration) Set(key string, val interface{}) {
	cfg.values[key] = val
}

// Remove deletes the value with the given key from the configuration.
func (cfg Configuration) Remove(key string) {
	delete(cfg.values, key)
}

// Get returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an interface{}.
func (cfg Configuration) Get(key string, def interface{}) interface{} {
	if val, found := cfg.values[key]; found {
		return val
	}
	return def
}

// GetInt returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int.
func (cfg Configuration) GetInt(key string, def int) int {
	return cfg.Get(key, def).(int)
}

// GetInt8 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int8.
func (cfg Configuration) GetInt8(key string, def int8) int8 {
	return int8(cfg.Get(key, def).(int))
}

// GetInt16 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int16.
func (cfg Configuration) GetInt16(key string, def int16) int16 {
	return int16(cfg.Get(key, def).(int))
}

// GetInt32 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int32.
func (cfg Configuration) GetInt32(key string, def int32) int32 {
	return int32(cfg.Get(key, def).(int))
}

// GetInt64 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int64.
func (cfg Configuration) GetInt64(key string, def int64) int64 {
	return int64(cfg.Get(key, def).(int))
}

// GetUint returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint.
func (cfg Configuration) GetUint(key string, def uint) uint {
	return uint(cfg.Get(key, def).(int))
}

// GetUint8 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint8.
func (cfg Configuration) GetUint8(key string, def uint8) uint8 {
	return uint8(cfg.Get(key, def).(int))
}

// GetUint16 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint16.
func (cfg Configuration) GetUint16(key string, def uint16) uint16 {
	return uint16(cfg.Get(key, def).(int))
}

// GetUint32 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint32.
func (cfg Configuration) GetUint32(key string, def uint32) uint32 {
	return uint32(cfg.Get(key, def).(int))
}

// GetUint64 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint64.
func (cfg Configuration) GetUint64(key string, def uint64) uint64 {
	return uint64(cfg.Get(key, def).(int))
}

// GetFloat32 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as a float32.
func (cfg Configuration) GetFloat32(key string, def float32) float32 {
	return float32(cfg.Get(key, def).(float64))
}

// GetFloat64 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as a float64.
func (cfg Configuration) GetFloat64(key string, def float64) float64 {
	return cfg.Get(key, def).(float64)
}

// GetBool returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as a bool.
func (cfg Configuration) GetBool(key string, def bool) bool {
	return cfg.Get(key, def).(bool)
}

// GetString returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as a string.
func (cfg Configuration) GetString(key string, def string) string {
	return cfg.Get(key, def).(string)
}
<commit_msg>#1 Refactored map types<commit_after>// Copyright (C) 2014 Thomas Lokshall
// Use of this source code is governed by the MIT license.
// See LICENSE.md for details.

// Package gocfg implements a way to easily read and write YAML configuration files.
package gocfg

import (
	"fmt"
	"io/ioutil"
	"reflect"

	yaml "gopkg.in/yaml.v1"
)

// Configuration contains the loaded configuration and functions to manipulate it.
type Configuration struct {
	values map[string]interface{}
}

type interfaceMap map[interface{}]interface{}
type stringMap map[string]interface{}

// NewConfiguration returns a new Configuration.
func NewConfiguration() *Configuration {
	return &Configuration{
		values: make(map[string]interface{}),
	}
}

// Load parses the YAML in data to it's internal map.
func (cfg Configuration) Load(data string) error {
	m := make(interfaceMap)
	if err := yaml.Unmarshal([]byte(data), &m); err != nil {
		return err
	}
	cfg.loadMap(m, "")
	return nil
}

// loadMap parses a loaded map structure and adds it to the current configuration.
// The prefix will be added before all values.
func (cfg Configuration) loadMap(m interfaceMap, prefix string) {
	for k, v := range m {
		if reflect.TypeOf(v).Kind() == reflect.Map {
			p := fmt.Sprintf("%s%s.", prefix, k.(string))
			cfg.loadMap(v.(interfaceMap), p)
		} else {
			s := fmt.Sprintf("%s%s", prefix, k.(string))
			cfg.values[s] = v
		}
	}
}

// Save returns the current configuration in YAML format.
func (cfg Configuration) Save() (string, error) {
	b, err := yaml.Marshal(&cfg.values)
	return string(b), err
}

// LoadFile reads a specified file into memory and parses it using Load().
func (cfg Configuration) LoadFile(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	yml := string(b[:])
	return cfg.Load(yml)
}

// SaveFile writes the output from Save() to the specified file.
func (cfg Configuration) SaveFile(path string) error {
	yml, err := cfg.Save()
	if err == nil {
		err = ioutil.WriteFile(path, []byte(yml), 0644)
	}
	return err
}

// Set sets a given value in the configuration to an arbitrary type.
func (cfg Configuration) Set(key string, val interface{}) {
	cfg.values[key] = val
}

// Remove deletes the value with the given key from the configuration.
func (cfg Configuration) Remove(key string) {
	delete(cfg.values, key)
}

// Get returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an interface{}.
func (cfg Configuration) Get(key string, def interface{}) interface{} {
	if val, found := cfg.values[key]; found {
		return val
	}
	return def
}

// GetInt returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int.
func (cfg Configuration) GetInt(key string, def int) int {
	return cfg.Get(key, def).(int)
}

// GetInt8 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int8.
func (cfg Configuration) GetInt8(key string, def int8) int8 {
	return int8(cfg.Get(key, def).(int))
}

// GetInt16 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int16.
func (cfg Configuration) GetInt16(key string, def int16) int16 {
	return int16(cfg.Get(key, def).(int))
}

// GetInt32 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int32.
func (cfg Configuration) GetInt32(key string, def int32) int32 {
	return int32(cfg.Get(key, def).(int))
}

// GetInt64 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an int64.
func (cfg Configuration) GetInt64(key string, def int64) int64 {
	return int64(cfg.Get(key, def).(int))
}

// GetUint returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint.
func (cfg Configuration) GetUint(key string, def uint) uint {
	return uint(cfg.Get(key, def).(int))
}

// GetUint8 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint8.
func (cfg Configuration) GetUint8(key string, def uint8) uint8 {
	return uint8(cfg.Get(key, def).(int))
}

// GetUint16 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint16.
func (cfg Configuration) GetUint16(key string, def uint16) uint16 {
	return uint16(cfg.Get(key, def).(int))
}

// GetUint32 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint32.
func (cfg Configuration) GetUint32(key string, def uint32) uint32 {
	return uint32(cfg.Get(key, def).(int))
}

// GetUint64 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as an uint64.
func (cfg Configuration) GetUint64(key string, def uint64) uint64 {
	return uint64(cfg.Get(key, def).(int))
}

// GetFloat32 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as a float32.
func (cfg Configuration) GetFloat32(key string, def float32) float32 {
	return float32(cfg.Get(key, def).(float64))
}

// GetFloat64 returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as a float64.
func (cfg Configuration) GetFloat64(key string, def float64) float64 {
	return cfg.Get(key, def).(float64)
}

// GetBool returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as a bool.
func (cfg Configuration) GetBool(key string, def bool) bool {
	return cfg.Get(key, def).(bool)
}

// GetString returns the value of the given key from the current configuration or the value of def if not found.
// The value is returns as a string.
func (cfg Configuration) GetString(key string, def string) string {
	return cfg.Get(key, def).(string)
}
<|endoftext|>


<commit_before>package html

import (
	"fmt"
	"html"
	"io"
	"sort"
	"strings"

	"github.com/alecthomas/chroma"
)

// Option sets an option of the HTML formatter.
type Option func(f *Formatter)

// Standalone configures the HTML formatter for generating a standalone HTML document.
func Standalone() Option { return func(f *Formatter) { f.standalone = true } }

// ClassPrefix sets the CSS class prefix.
func ClassPrefix(prefix string) Option { return func(f *Formatter) { f.prefix = prefix } }

// WithClasses emits HTML using CSS classes, rather than inline styles.
func WithClasses() Option { return func(f *Formatter) { f.classes = true } }

// TabWidth sets the number of characters for a tab. Defaults to 8.
func TabWidth(width int) Option { return func(f *Formatter) { f.tabWidth = width } }

// WithLineNumbers formats output with line numbers.
func WithLineNumbers() Option {
	return func(f *Formatter) {
		f.lineNumbers = true
	}
}

// HighlightLines higlights the given line ranges with the Highlight style.
//
// A range is the beginning and ending of a range as 1-based line numbers, inclusive.
func HighlightLines(ranges [][2]int) Option {
	return func(f *Formatter) {
		f.highlightRanges = ranges
		sort.Sort(f.highlightRanges)
	}
}

// BaseLineNumber sets the initial number to start line numbering at. Defaults to 1.
func BaseLineNumber(n int) Option {
	return func(f *Formatter) {
		f.baseLineNumber = n
	}
}

// New HTML formatter.
func New(options ...Option) *Formatter {
	f := &Formatter{
		baseLineNumber: 1,
	}
	for _, option := range options {
		option(f)
	}
	return f
}

// Formatter that generates HTML.
type Formatter struct {
	standalone      bool
	prefix          string
	classes         bool
	tabWidth        int
	lineNumbers     bool
	highlightRanges highlightRanges
	baseLineNumber  int
}

type highlightRanges [][2]int

func (h highlightRanges) Len() int           { return len(h) }
func (h highlightRanges) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h highlightRanges) Less(i, j int) bool { return h[i][0] < h[j][0] }

func (f *Formatter) Format(w io.Writer, style *chroma.Style, iterator chroma.Iterator) (err error) {
	defer func() {
		if perr := recover(); perr != nil {
			err = perr.(error)
		}
	}()
	return f.writeHTML(w, style, iterator.Tokens())
}

func brightenOrDarken(colour chroma.Colour, factor float64) chroma.Colour {
	if colour.Brightness() < 0.5 {
		return colour.Brighten(factor)
	}
	return colour.Brighten(-factor)
}

// Ensure that style entries exist for highlighting, etc.
func (f *Formatter) restyle(style *chroma.Style) (*chroma.Style, error) {
	builder := style.Builder()
	bg := builder.Get(chroma.Background)
	// If we don't have a line highlight colour, make one that is 10% brighter/darker than the background.
	if !style.Has(chroma.LineHighlight) {
		highlight := chroma.StyleEntry{Background: bg.Background}
		highlight.Background = brightenOrDarken(highlight.Background, 0.1)
		builder.AddEntry(chroma.LineHighlight, highlight)
	}
	// If we don't have line numbers, use the text colour but 20% brighter/darker
	if !style.Has(chroma.LineNumbers) {
		text := chroma.StyleEntry{Colour: bg.Colour}
		text.Colour = brightenOrDarken(text.Colour, 0.5)
		builder.AddEntry(chroma.LineNumbers, text)
	}
	return builder.Build()
}

// We deliberately don't use html/template here because it is two orders of magnitude slower (benchmarked).
//
// OTOH we need to be super careful about correct escaping...
func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []*chroma.Token) (err error) { // nolint: gocyclo
	style, err = f.restyle(style)
	if err != nil {
		return err
	}
	css := f.styleToCSS(style)
	if !f.classes {
		for t, style := range css {
			css[t] = compressStyle(style)
		}
	}
	if f.standalone {
		fmt.Fprint(w, "\n")
		if f.classes {
			fmt.Fprint(w, "")
		}
		fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.Background))
	}

	fmt.Fprintf(w, "
", f.styleAttr(css, chroma.Background))
	lines := splitTokensIntoLines(tokens)
	lineDigits := len(fmt.Sprintf("%d", len(lines)))
	highlightIndex := 0
	for index, tokens := range lines {
		// 1-based line number.
		line := f.baseLineNumber + index
		highlight := false
		for highlightIndex < len(f.highlightRanges) && line > f.highlightRanges[highlightIndex][1] {
			highlightIndex++
		}
		if highlightIndex < len(f.highlightRanges) {
			hrange := f.highlightRanges[highlightIndex]
			if line >= hrange[0] && line <= hrange[1] {
				highlight = true
			}
		}
		if highlight {
			fmt.Fprintf(w, "", f.styleAttr(css, chroma.LineHighlight))
		}
		if f.lineNumbers {
			fmt.Fprintf(w, "%*d", f.styleAttr(css, chroma.LineNumbers), lineDigits, line)
		}

		for _, token := range tokens {
			html := html.EscapeString(token.String())
			attr := f.styleAttr(css, token.Type)
			if attr != "" {
				html = fmt.Sprintf("%s", attr, html)
			}
			fmt.Fprint(w, html)
		}
		if highlight {
			fmt.Fprintf(w, "")
		}
	}

	fmt.Fprint(w, "
\n")
	if f.standalone {
		fmt.Fprint(w, "\n")
		fmt.Fprint(w, "\n")
	}

	return nil
}

func (f *Formatter) class(t chroma.TokenType) string {
	for t != 0 {
		cls, ok := chroma.StandardTypes[t]
		if ok {
			return cls
		}
		t = t.Parent()
	}
	return chroma.StandardTypes[t]
}

func (f *Formatter) styleAttr(styles map[chroma.TokenType]string, tt chroma.TokenType) string {
	if _, ok := styles[tt]; !ok {
		tt = tt.SubCategory()
		if _, ok := styles[tt]; !ok {
			tt = tt.Category()
			if _, ok := styles[tt]; !ok {
				return ""
			}
		}
	}
	if f.classes {
		return string(fmt.Sprintf(` class="%s"`, f.class(tt)))
	}
	return string(fmt.Sprintf(` style="%s"`, styles[tt]))
}

func (f *Formatter) tabWidthStyle() string {
	if f.tabWidth != 0 && f.tabWidth != 8 {
		return fmt.Sprintf("; -moz-tab-size: %[1]d; -o-tab-size: %[1]d; tab-size: %[1]d", f.tabWidth)
	}
	return ""
}

// WriteCSS writes CSS style definitions (without any surrounding HTML).
func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error {
	css := f.styleToCSS(style)
	// Special-case background as it is mapped to the outer ".chroma" class.
	if _, err := fmt.Fprintf(w, "/* %s */ .chroma { %s }\n", chroma.Background, css[chroma.Background]); err != nil {
		return err
	}
	tts := []int{}
	for tt := range css {
		tts = append(tts, int(tt))
	}
	sort.Ints(tts)
	for _, ti := range tts {
		tt := chroma.TokenType(ti)
		if tt == chroma.Background {
			continue
		}
		styles := css[tt]
		if _, err := fmt.Fprintf(w, "/* %s */ .chroma .%s { %s }\n", tt, f.class(tt), styles); err != nil {
			return err
		}
	}
	return nil
}

func (f *Formatter) styleToCSS(style *chroma.Style) map[chroma.TokenType]string {
	classes := map[chroma.TokenType]string{}
	bg := style.Get(chroma.Background)
	// Convert the style.
	for t := range chroma.StandardTypes {
		entry := style.Get(t)
		if t != chroma.Background {
			entry = entry.Sub(bg)
		}
		if entry.IsZero() {
			continue
		}
		classes[t] = StyleEntryToCSS(entry)
	}
	classes[chroma.Background] += f.tabWidthStyle()
	classes[chroma.LineNumbers] += "; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;"
	classes[chroma.LineHighlight] += "; display: block; width: 100%"
	return classes
}

// StyleEntryToCSS converts a chroma.StyleEntry to CSS attributes.
func StyleEntryToCSS(e chroma.StyleEntry) string {
	styles := []string{}
	if e.Colour.IsSet() {
		styles = append(styles, "color: "+e.Colour.String())
	}
	if e.Background.IsSet() {
		styles = append(styles, "background-color: "+e.Background.String())
	}
	if e.Bold == chroma.Yes {
		styles = append(styles, "font-weight: bold")
	}
	if e.Italic == chroma.Yes {
		styles = append(styles, "font-style: italic")
	}
	return strings.Join(styles, "; ")
}

// Compress CSS attributes - remove spaces, transform 6-digit colours to 3.
func compressStyle(s string) string {
	s = strings.Replace(s, " ", "", -1)
	parts := strings.Split(s, ";")
	out := []string{}
	for _, p := range parts {
		if strings.Contains(p, "#") {
			c := p[len(p)-6:]
			if c[0] == c[1] && c[2] == c[3] && c[4] == c[5] {
				p = p[:len(p)-6] + c[0:1] + c[2:3] + c[4:5]
			}
		}
		out = append(out, p)
	}
	return strings.Join(out, ";")
}

func splitTokensIntoLines(tokens []*chroma.Token) (out [][]*chroma.Token) {
	line := []*chroma.Token{}
	for _, token := range tokens {
		for strings.Contains(token.Value, "\n") {
			parts := strings.SplitAfterN(token.Value, "\n", 2)
			// Token becomes the tail.
			token.Value = parts[1]

			// Append the head to the line and flush the line.
			clone := token.Clone()
			clone.Value = parts[0]
			line = append(line, clone)
			out = append(out, line)
			line = nil
		}
		line = append(line, token)
	}
	if len(line) > 0 {
		out = append(out, line)
	}
	return
}
<commit_msg>Always use CSS class from StandardTypes.<commit_after>package html

import (
	"fmt"
	"html"
	"io"
	"sort"
	"strings"

	"github.com/alecthomas/chroma"
)

// Option sets an option of the HTML formatter.
type Option func(f *Formatter)

// Standalone configures the HTML formatter for generating a standalone HTML document.
func Standalone() Option { return func(f *Formatter) { f.standalone = true } }

// ClassPrefix sets the CSS class prefix.
func ClassPrefix(prefix string) Option { return func(f *Formatter) { f.prefix = prefix } }

// WithClasses emits HTML using CSS classes, rather than inline styles.
func WithClasses() Option { return func(f *Formatter) { f.classes = true } }

// TabWidth sets the number of characters for a tab. Defaults to 8.
func TabWidth(width int) Option { return func(f *Formatter) { f.tabWidth = width } }

// WithLineNumbers formats output with line numbers.
func WithLineNumbers() Option {
	return func(f *Formatter) {
		f.lineNumbers = true
	}
}

// HighlightLines higlights the given line ranges with the Highlight style.
//
// A range is the beginning and ending of a range as 1-based line numbers, inclusive.
func HighlightLines(ranges [][2]int) Option {
	return func(f *Formatter) {
		f.highlightRanges = ranges
		sort.Sort(f.highlightRanges)
	}
}

// BaseLineNumber sets the initial number to start line numbering at. Defaults to 1.
func BaseLineNumber(n int) Option {
	return func(f *Formatter) {
		f.baseLineNumber = n
	}
}

// New HTML formatter.
func New(options ...Option) *Formatter {
	f := &Formatter{
		baseLineNumber: 1,
	}
	for _, option := range options {
		option(f)
	}
	return f
}

// Formatter that generates HTML.
type Formatter struct {
	standalone      bool
	prefix          string
	classes         bool
	tabWidth        int
	lineNumbers     bool
	highlightRanges highlightRanges
	baseLineNumber  int
}

type highlightRanges [][2]int

func (h highlightRanges) Len() int           { return len(h) }
func (h highlightRanges) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h highlightRanges) Less(i, j int) bool { return h[i][0] < h[j][0] }

func (f *Formatter) Format(w io.Writer, style *chroma.Style, iterator chroma.Iterator) (err error) {
	defer func() {
		if perr := recover(); perr != nil {
			err = perr.(error)
		}
	}()
	return f.writeHTML(w, style, iterator.Tokens())
}

func brightenOrDarken(colour chroma.Colour, factor float64) chroma.Colour {
	if colour.Brightness() < 0.5 {
		return colour.Brighten(factor)
	}
	return colour.Brighten(-factor)
}

// Ensure that style entries exist for highlighting, etc.
func (f *Formatter) restyle(style *chroma.Style) (*chroma.Style, error) {
	builder := style.Builder()
	bg := builder.Get(chroma.Background)
	// If we don't have a line highlight colour, make one that is 10% brighter/darker than the background.
	if !style.Has(chroma.LineHighlight) {
		highlight := chroma.StyleEntry{Background: bg.Background}
		highlight.Background = brightenOrDarken(highlight.Background, 0.1)
		builder.AddEntry(chroma.LineHighlight, highlight)
	}
	// If we don't have line numbers, use the text colour but 20% brighter/darker
	if !style.Has(chroma.LineNumbers) {
		text := chroma.StyleEntry{Colour: bg.Colour}
		text.Colour = brightenOrDarken(text.Colour, 0.5)
		builder.AddEntry(chroma.LineNumbers, text)
	}
	return builder.Build()
}

// We deliberately don't use html/template here because it is two orders of magnitude slower (benchmarked).
//
// OTOH we need to be super careful about correct escaping...
func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []*chroma.Token) (err error) { // nolint: gocyclo
	style, err = f.restyle(style)
	if err != nil {
		return err
	}
	css := f.styleToCSS(style)
	if !f.classes {
		for t, style := range css {
			css[t] = compressStyle(style)
		}
	}
	if f.standalone {
		fmt.Fprint(w, "\n")
		if f.classes {
			fmt.Fprint(w, "")
		}
		fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.Background))
	}

	fmt.Fprintf(w, "
", f.styleAttr(css, chroma.Background))
	lines := splitTokensIntoLines(tokens)
	lineDigits := len(fmt.Sprintf("%d", len(lines)))
	highlightIndex := 0
	for index, tokens := range lines {
		// 1-based line number.
		line := f.baseLineNumber + index
		highlight := false
		for highlightIndex < len(f.highlightRanges) && line > f.highlightRanges[highlightIndex][1] {
			highlightIndex++
		}
		if highlightIndex < len(f.highlightRanges) {
			hrange := f.highlightRanges[highlightIndex]
			if line >= hrange[0] && line <= hrange[1] {
				highlight = true
			}
		}
		if highlight {
			fmt.Fprintf(w, "", f.styleAttr(css, chroma.LineHighlight))
		}
		if f.lineNumbers {
			fmt.Fprintf(w, "%*d", f.styleAttr(css, chroma.LineNumbers), lineDigits, line)
		}

		for _, token := range tokens {
			html := html.EscapeString(token.String())
			attr := f.styleAttr(css, token.Type)
			if attr != "" {
				html = fmt.Sprintf("%s", attr, html)
			}
			fmt.Fprint(w, html)
		}
		if highlight {
			fmt.Fprintf(w, "")
		}
	}

	fmt.Fprint(w, "
\n")
	if f.standalone {
		fmt.Fprint(w, "\n")
		fmt.Fprint(w, "\n")
	}

	return nil
}

func (f *Formatter) class(t chroma.TokenType) string {
	for t != 0 {
		cls, ok := chroma.StandardTypes[t]
		if ok {
			return cls
		}
		t = t.Parent()
	}
	return chroma.StandardTypes[t]
}

func (f *Formatter) styleAttr(styles map[chroma.TokenType]string, tt chroma.TokenType) string {
	if f.classes {
		return string(fmt.Sprintf(` class="%s"`, f.class(tt)))
	}
	if _, ok := styles[tt]; !ok {
		tt = tt.SubCategory()
		if _, ok := styles[tt]; !ok {
			tt = tt.Category()
			if _, ok := styles[tt]; !ok {
				return ""
			}
		}
	}
	return string(fmt.Sprintf(` style="%s"`, styles[tt]))
}

func (f *Formatter) tabWidthStyle() string {
	if f.tabWidth != 0 && f.tabWidth != 8 {
		return fmt.Sprintf("; -moz-tab-size: %[1]d; -o-tab-size: %[1]d; tab-size: %[1]d", f.tabWidth)
	}
	return ""
}

// WriteCSS writes CSS style definitions (without any surrounding HTML).
func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error {
	css := f.styleToCSS(style)
	// Special-case background as it is mapped to the outer ".chroma" class.
	if _, err := fmt.Fprintf(w, "/* %s */ .chroma { %s }\n", chroma.Background, css[chroma.Background]); err != nil {
		return err
	}
	tts := []int{}
	for tt := range css {
		tts = append(tts, int(tt))
	}
	sort.Ints(tts)
	for _, ti := range tts {
		tt := chroma.TokenType(ti)
		if tt == chroma.Background {
			continue
		}
		styles := css[tt]
		if _, err := fmt.Fprintf(w, "/* %s */ .chroma .%s { %s }\n", tt, f.class(tt), styles); err != nil {
			return err
		}
	}
	return nil
}

func (f *Formatter) styleToCSS(style *chroma.Style) map[chroma.TokenType]string {
	classes := map[chroma.TokenType]string{}
	bg := style.Get(chroma.Background)
	// Convert the style.
	for t := range chroma.StandardTypes {
		entry := style.Get(t)
		if t != chroma.Background {
			entry = entry.Sub(bg)
		}
		if entry.IsZero() {
			continue
		}
		classes[t] = StyleEntryToCSS(entry)
	}
	classes[chroma.Background] += f.tabWidthStyle()
	classes[chroma.LineNumbers] += "; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;"
	classes[chroma.LineHighlight] += "; display: block; width: 100%"
	return classes
}

// StyleEntryToCSS converts a chroma.StyleEntry to CSS attributes.
func StyleEntryToCSS(e chroma.StyleEntry) string {
	styles := []string{}
	if e.Colour.IsSet() {
		styles = append(styles, "color: "+e.Colour.String())
	}
	if e.Background.IsSet() {
		styles = append(styles, "background-color: "+e.Background.String())
	}
	if e.Bold == chroma.Yes {
		styles = append(styles, "font-weight: bold")
	}
	if e.Italic == chroma.Yes {
		styles = append(styles, "font-style: italic")
	}
	return strings.Join(styles, "; ")
}

// Compress CSS attributes - remove spaces, transform 6-digit colours to 3.
func compressStyle(s string) string {
	s = strings.Replace(s, " ", "", -1)
	parts := strings.Split(s, ";")
	out := []string{}
	for _, p := range parts {
		if strings.Contains(p, "#") {
			c := p[len(p)-6:]
			if c[0] == c[1] && c[2] == c[3] && c[4] == c[5] {
				p = p[:len(p)-6] + c[0:1] + c[2:3] + c[4:5]
			}
		}
		out = append(out, p)
	}
	return strings.Join(out, ";")
}

func splitTokensIntoLines(tokens []*chroma.Token) (out [][]*chroma.Token) {
	line := []*chroma.Token{}
	for _, token := range tokens {
		for strings.Contains(token.Value, "\n") {
			parts := strings.SplitAfterN(token.Value, "\n", 2)
			// Token becomes the tail.
			token.Value = parts[1]

			// Append the head to the line and flush the line.
			clone := token.Clone()
			clone.Value = parts[0]
			line = append(line, clone)
			out = append(out, line)
			line = nil
		}
		line = append(line, token)
	}
	if len(line) > 0 {
		out = append(out, line)
	}
	return
}
<|endoftext|>


<commit_before>package fs

import (
	"fmt"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"strings"
	"os"
)

func resolvePath(p string, u *user.User) ([]string, error) {
	p, err := resolveVars(p, u)
	if err != nil {
		return nil, err
	}
	return resolveGlob(p)
}

func resolveVars(p string, u *user.User) (string, error) {
	const pathVar = "${PATH}/"
	const homeVar = "${HOME}"
	const uidVar = "${UID}"
	const userVar = "${USER}"

	switch {
	case strings.HasPrefix(p, pathVar):
		emptyPath := false
		if os.Getenv("PATH") == "" {
			emptyPath = true
			os.Setenv("PATH", "/bin:/usr/bin:/sbin:/usr/sbin")
		}
		resolved, err := exec.LookPath(p[len(pathVar):])
		if emptyPath {
			os.Unsetenv("PATH")
		}
		if err != nil {
			return "", fmt.Errorf("failed to resolve %s", p)
		}
		return resolved, nil

	case strings.HasPrefix(p, homeVar):
		if u == nil {
			return p, nil
		}
		return path.Join(u.HomeDir, p[len(homeVar):]), nil

	case strings.Contains(p, uidVar):
		if u == nil {
			return p, nil
		}
		return strings.Replace(p, uidVar, u.Uid, -1), nil

	case strings.Contains(p, userVar):
		if u == nil {
			return p, nil
		}
		return strings.Replace(p, userVar, u.Username, -1), nil
	}
	return p, nil
}

func isGlobbed(p string) bool {
	return strings.Contains(p, "*")
}

func resolveGlob(p string) ([]string, error) {
	if !isGlobbed(p) {
		return []string{p}, nil
	}
	list, err := filepath.Glob(p)
	if err != nil {
		return nil, fmt.Errorf("failed to glob resolve %s: %v", p, err)
	}
	return list, nil
}
<commit_msg>Unsetenv > Setenv "" as the former is unavailable in golang 1.3<commit_after>package fs

import (
	"fmt"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"strings"
	"os"
)

func resolvePath(p string, u *user.User) ([]string, error) {
	p, err := resolveVars(p, u)
	if err != nil {
		return nil, err
	}
	return resolveGlob(p)
}

func resolveVars(p string, u *user.User) (string, error) {
	const pathVar = "${PATH}/"
	const homeVar = "${HOME}"
	const uidVar = "${UID}"
	const userVar = "${USER}"

	switch {
	case strings.HasPrefix(p, pathVar):
		emptyPath := false
		if os.Getenv("PATH") == "" {
			emptyPath = true
			os.Setenv("PATH", "/bin:/usr/bin:/sbin:/usr/sbin")
		}
		resolved, err := exec.LookPath(p[len(pathVar):])
		if emptyPath {
			os.Setenv("PATH", "") // Do not use Unsetenv, incompatible with golang 1.3
		}
		if err != nil {
			return "", fmt.Errorf("failed to resolve %s", p)
		}
		return resolved, nil

	case strings.HasPrefix(p, homeVar):
		if u == nil {
			return p, nil
		}
		return path.Join(u.HomeDir, p[len(homeVar):]), nil

	case strings.Contains(p, uidVar):
		if u == nil {
			return p, nil
		}
		return strings.Replace(p, uidVar, u.Uid, -1), nil

	case strings.Contains(p, userVar):
		if u == nil {
			return p, nil
		}
		return strings.Replace(p, userVar, u.Username, -1), nil
	}
	return p, nil
}

func isGlobbed(p string) bool {
	return strings.Contains(p, "*")
}

func resolveGlob(p string) ([]string, error) {
	if !isGlobbed(p) {
		return []string{p}, nil
	}
	list, err := filepath.Glob(p)
	if err != nil {
		return nil, fmt.Errorf("failed to glob resolve %s: %v", p, err)
	}
	return list, nil
}
<|endoftext|>


<commit_before>/*
   Copyright 2014 CoreOS, Inc.

   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 raft

import (
	"fmt"
	"log"

	pb "github.com/coreos/etcd/raft/raftpb"
)

type raftLog struct {
	// storage contains all stable entries since the last snapshot.
	storage Storage
	// unstableEnts contains all entries that have not yet been written
	// to storage.
	unstableEnts []pb.Entry
	// unstableEnts[i] has raft log position i+unstable.  Note that
	// unstable may be less than the highest log position in storage;
	// this means that the next write to storage will truncate the log
	// before persisting unstableEnts.
	unstable uint64
	// committed is the highest log position that is known to be in
	// stable storage on a quorum of nodes.
	// Invariant: committed < unstable
	committed uint64
	// applied is the highest log position that the application has
	// been instructed to apply to its state machine.
	// Invariant: applied <= committed
	applied uint64
}

// newLog returns log using the given storage. It recovers the log to the state
// that it just commits and applies the lastest snapshot.
func newLog(storage Storage) *raftLog {
	if storage == nil {
		log.Panic("storage must not be nil")
	}
	log := &raftLog{
		storage: storage,
	}
	firstIndex, err := storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	lastIndex, err := storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	log.unstable = lastIndex + 1
	// Initialize our committed and applied pointers to the time of the last compaction.
	log.committed = firstIndex - 1
	log.applied = firstIndex - 1

	return log
}

func (l *raftLog) String() string {
	return fmt.Sprintf("unstable=%d committed=%d applied=%d len(unstableEntries)=%d", l.unstable, l.committed, l.applied, len(l.unstableEnts))
}

// maybeAppend returns (0, false) if the entries cannot be appended. Otherwise,
// it returns (last index of new entries, true).
func (l *raftLog) maybeAppend(index, logTerm, committed uint64, ents ...pb.Entry) (lastnewi uint64, ok bool) {
	lastnewi = index + uint64(len(ents))
	if l.matchTerm(index, logTerm) {
		from := index + 1
		ci := l.findConflict(from, ents)
		switch {
		case ci == 0:
		case ci <= l.committed:
			log.Panicf("conflict(%d) with committed entry [committed(%d)]", ci, l.committed)
		default:
			l.append(ci-1, ents[ci-from:]...)
		}
		l.commitTo(min(committed, lastnewi))
		return lastnewi, true
	}
	return 0, false
}

func (l *raftLog) append(after uint64, ents ...pb.Entry) uint64 {
	if after < l.committed {
		log.Panicf("after(%d) out of range [committed(%d)]", after, l.committed)
	}
	if after < l.unstable {
		// The log is being truncated to before our current unstable
		// portion, so discard it and reset unstable.
		l.unstableEnts = nil
		l.unstable = after + 1
	}
	// Truncate any unstable entries that are being replaced, then
	// append the new ones.
	l.unstableEnts = append(l.unstableEnts[0:1+after-l.unstable], ents...)
	l.unstable = min(l.unstable, after+1)
	return l.lastIndex()
}

// findConflict finds the index of the conflict.
// It returns the first pair of conflicting entries between the existing
// entries and the given entries, if there are any.
// If there is no conflicting entries, and the existing entries contains
// all the given entries, zero will be returned.
// If there is no conflicting entries, but the given entries contains new
// entries, the index of the first new entry will be returned.
// An entry is considered to be conflicting if it has the same index but
// a different term.
// The first entry MUST have an index equal to the argument 'from'.
// The index of the given entries MUST be continuously increasing.
func (l *raftLog) findConflict(from uint64, ents []pb.Entry) uint64 {
	// TODO(xiangli): validate the index of ents
	for i, ne := range ents {
		if oe := l.at(from + uint64(i)); oe == nil || oe.Term != ne.Term {
			return from + uint64(i)
		}
	}
	return 0
}

func (l *raftLog) unstableEntries() []pb.Entry {
	if len(l.unstableEnts) == 0 {
		return nil
	}
	// copy unstable entries to an empty slice
	return append([]pb.Entry{}, l.unstableEnts...)
}

// nextEnts returns all the available entries for execution.
// If applied is smaller than the index of snapshot, it returns all committed
// entries after the index of snapshot.
func (l *raftLog) nextEnts() (ents []pb.Entry) {
	off := max(l.applied+1, l.firstIndex())
	if l.committed+1 > off {
		return l.slice(off, l.committed+1)
	}
	return nil
}

func (l *raftLog) firstIndex() uint64 {
	index, err := l.storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) lastIndex() uint64 {
	if len(l.unstableEnts) > 0 {
		return l.unstable + uint64(len(l.unstableEnts)) - 1
	}
	index, err := l.storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) commitTo(tocommit uint64) {
	// never decrease commit
	if l.committed < tocommit {
		if l.lastIndex() < tocommit {
			log.Panicf("tocommit(%d) is out of range [lastIndex(%d)]", tocommit, l.lastIndex())
		}
		l.committed = tocommit
	}
}

func (l *raftLog) appliedTo(i uint64) {
	if i == 0 {
		return
	}
	if l.committed < i || i < l.applied {
		log.Panicf("applied(%d) is out of range [prevApplied(%d), committed(%d)]", i, l.applied, l.committed)
	}
	l.applied = i
}

func (l *raftLog) stableTo(i uint64) {
	if i < l.unstable || i+1-l.unstable > uint64(len(l.unstableEnts)) {
		log.Panicf("stableTo(%d) is out of range [unstable(%d), len(unstableEnts)(%d)]",
			i, l.unstable, len(l.unstableEnts))
	}
	l.unstableEnts = l.unstableEnts[i+1-l.unstable:]
	l.unstable = i + 1
}

func (l *raftLog) lastTerm() uint64 {
	return l.term(l.lastIndex())
}

func (l *raftLog) term(i uint64) uint64 {
	if i >= l.unstable+uint64(len(l.unstableEnts)) {
		return 0
	}

	if i < l.unstable {
		t, err := l.storage.Term(i)
		if err == nil {
			return t
		}
		if err == ErrCompacted {
			return 0
		} else {
			panic(err) // TODO(bdarnell)
		}
	}

	return l.unstableEnts[i-l.unstable].Term
}

func (l *raftLog) entries(i uint64) []pb.Entry {
	return l.slice(i, l.lastIndex()+1)
}

// allEntries returns all entries in the log.
func (l *raftLog) allEntries() []pb.Entry {
	return l.entries(l.firstIndex())
}

// isUpToDate determines if the given (lastIndex,term) log is more up-to-date
// by comparing the index and term of the last entries in the existing logs.
// If the logs have last entries with different terms, then the log with the
// later term is more up-to-date. If the logs end with the same term, then
// whichever log has the larger lastIndex is more up-to-date. If the logs are
// the same, the given log is up-to-date.
func (l *raftLog) isUpToDate(lasti, term uint64) bool {
	return term > l.lastTerm() || (term == l.lastTerm() && lasti >= l.lastIndex())
}

func (l *raftLog) matchTerm(i, term uint64) bool {
	return l.term(i) == term
}

func (l *raftLog) maybeCommit(maxIndex, term uint64) bool {
	if maxIndex > l.committed && l.term(maxIndex) == term {
		l.commitTo(maxIndex)
		return true
	}
	return false
}

func (l *raftLog) restore(s pb.Snapshot) {
	err := l.storage.ApplySnapshot(s)
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	l.committed = s.Metadata.Index
	l.applied = s.Metadata.Index
	l.unstable = l.committed + 1
	l.unstableEnts = nil
}

func (l *raftLog) at(i uint64) *pb.Entry {
	ents := l.slice(i, i+1)
	if len(ents) == 0 {
		return nil
	}
	return &ents[0]
}

// slice returns a slice of log entries from lo through hi-1, inclusive.
func (l *raftLog) slice(lo uint64, hi uint64) []pb.Entry {
	if lo >= hi {
		return nil
	}
	if l.isOutOfBounds(lo) || l.isOutOfBounds(hi-1) {
		return nil
	}
	var ents []pb.Entry
	if lo < l.unstable {
		storedEnts, err := l.storage.Entries(lo, min(hi, l.unstable))
		if err == ErrCompacted {
			return nil
		} else if err != nil {
			panic(err) // TODO(bdarnell)
		}
		ents = append(ents, storedEnts...)
	}
	if len(l.unstableEnts) > 0 && hi > l.unstable {
		firstUnstable := max(lo, l.unstable)
		ents = append(ents, l.unstableEnts[firstUnstable-l.unstable:hi-l.unstable]...)
	}
	return ents
}

func (l *raftLog) isOutOfBounds(i uint64) bool {
	if i < l.firstIndex() || i > l.lastIndex() {
		return true
	}
	return false
}

func (l *raftLog) isOutOfAppliedBounds(i uint64) bool {
	if i < l.firstIndex() || i > l.applied {
		return true
	}
	return false
}

func min(a, b uint64) uint64 {
	if a > b {
		return b
	}
	return a
}

func max(a, b uint64) uint64 {
	if a > b {
		return a
	}
	return b
}
<commit_msg>raft: remove useless line in raftLog.append<commit_after>/*
   Copyright 2014 CoreOS, Inc.

   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 raft

import (
	"fmt"
	"log"

	pb "github.com/coreos/etcd/raft/raftpb"
)

type raftLog struct {
	// storage contains all stable entries since the last snapshot.
	storage Storage
	// unstableEnts contains all entries that have not yet been written
	// to storage.
	unstableEnts []pb.Entry
	// unstableEnts[i] has raft log position i+unstable.  Note that
	// unstable may be less than the highest log position in storage;
	// this means that the next write to storage will truncate the log
	// before persisting unstableEnts.
	unstable uint64
	// committed is the highest log position that is known to be in
	// stable storage on a quorum of nodes.
	// Invariant: committed < unstable
	committed uint64
	// applied is the highest log position that the application has
	// been instructed to apply to its state machine.
	// Invariant: applied <= committed
	applied uint64
}

// newLog returns log using the given storage. It recovers the log to the state
// that it just commits and applies the lastest snapshot.
func newLog(storage Storage) *raftLog {
	if storage == nil {
		log.Panic("storage must not be nil")
	}
	log := &raftLog{
		storage: storage,
	}
	firstIndex, err := storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	lastIndex, err := storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	log.unstable = lastIndex + 1
	// Initialize our committed and applied pointers to the time of the last compaction.
	log.committed = firstIndex - 1
	log.applied = firstIndex - 1

	return log
}

func (l *raftLog) String() string {
	return fmt.Sprintf("unstable=%d committed=%d applied=%d len(unstableEntries)=%d", l.unstable, l.committed, l.applied, len(l.unstableEnts))
}

// maybeAppend returns (0, false) if the entries cannot be appended. Otherwise,
// it returns (last index of new entries, true).
func (l *raftLog) maybeAppend(index, logTerm, committed uint64, ents ...pb.Entry) (lastnewi uint64, ok bool) {
	lastnewi = index + uint64(len(ents))
	if l.matchTerm(index, logTerm) {
		from := index + 1
		ci := l.findConflict(from, ents)
		switch {
		case ci == 0:
		case ci <= l.committed:
			log.Panicf("conflict(%d) with committed entry [committed(%d)]", ci, l.committed)
		default:
			l.append(ci-1, ents[ci-from:]...)
		}
		l.commitTo(min(committed, lastnewi))
		return lastnewi, true
	}
	return 0, false
}

func (l *raftLog) append(after uint64, ents ...pb.Entry) uint64 {
	if after < l.committed {
		log.Panicf("after(%d) out of range [committed(%d)]", after, l.committed)
	}
	if after < l.unstable {
		// The log is being truncated to before our current unstable
		// portion, so discard it and reset unstable.
		l.unstableEnts = nil
		l.unstable = after + 1
	}
	// Truncate any unstable entries that are being replaced, then
	// append the new ones.
	l.unstableEnts = append(l.unstableEnts[:after+1-l.unstable], ents...)
	return l.lastIndex()
}

// findConflict finds the index of the conflict.
// It returns the first pair of conflicting entries between the existing
// entries and the given entries, if there are any.
// If there is no conflicting entries, and the existing entries contains
// all the given entries, zero will be returned.
// If there is no conflicting entries, but the given entries contains new
// entries, the index of the first new entry will be returned.
// An entry is considered to be conflicting if it has the same index but
// a different term.
// The first entry MUST have an index equal to the argument 'from'.
// The index of the given entries MUST be continuously increasing.
func (l *raftLog) findConflict(from uint64, ents []pb.Entry) uint64 {
	// TODO(xiangli): validate the index of ents
	for i, ne := range ents {
		if oe := l.at(from + uint64(i)); oe == nil || oe.Term != ne.Term {
			return from + uint64(i)
		}
	}
	return 0
}

func (l *raftLog) unstableEntries() []pb.Entry {
	if len(l.unstableEnts) == 0 {
		return nil
	}
	// copy unstable entries to an empty slice
	return append([]pb.Entry{}, l.unstableEnts...)
}

// nextEnts returns all the available entries for execution.
// If applied is smaller than the index of snapshot, it returns all committed
// entries after the index of snapshot.
func (l *raftLog) nextEnts() (ents []pb.Entry) {
	off := max(l.applied+1, l.firstIndex())
	if l.committed+1 > off {
		return l.slice(off, l.committed+1)
	}
	return nil
}

func (l *raftLog) firstIndex() uint64 {
	index, err := l.storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) lastIndex() uint64 {
	if len(l.unstableEnts) > 0 {
		return l.unstable + uint64(len(l.unstableEnts)) - 1
	}
	index, err := l.storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) commitTo(tocommit uint64) {
	// never decrease commit
	if l.committed < tocommit {
		if l.lastIndex() < tocommit {
			log.Panicf("tocommit(%d) is out of range [lastIndex(%d)]", tocommit, l.lastIndex())
		}
		l.committed = tocommit
	}
}

func (l *raftLog) appliedTo(i uint64) {
	if i == 0 {
		return
	}
	if l.committed < i || i < l.applied {
		log.Panicf("applied(%d) is out of range [prevApplied(%d), committed(%d)]", i, l.applied, l.committed)
	}
	l.applied = i
}

func (l *raftLog) stableTo(i uint64) {
	if i < l.unstable || i+1-l.unstable > uint64(len(l.unstableEnts)) {
		log.Panicf("stableTo(%d) is out of range [unstable(%d), len(unstableEnts)(%d)]",
			i, l.unstable, len(l.unstableEnts))
	}
	l.unstableEnts = l.unstableEnts[i+1-l.unstable:]
	l.unstable = i + 1
}

func (l *raftLog) lastTerm() uint64 {
	return l.term(l.lastIndex())
}

func (l *raftLog) term(i uint64) uint64 {
	if i >= l.unstable+uint64(len(l.unstableEnts)) {
		return 0
	}

	if i < l.unstable {
		t, err := l.storage.Term(i)
		if err == nil {
			return t
		}
		if err == ErrCompacted {
			return 0
		} else {
			panic(err) // TODO(bdarnell)
		}
	}

	return l.unstableEnts[i-l.unstable].Term
}

func (l *raftLog) entries(i uint64) []pb.Entry {
	return l.slice(i, l.lastIndex()+1)
}

// allEntries returns all entries in the log.
func (l *raftLog) allEntries() []pb.Entry {
	return l.entries(l.firstIndex())
}

// isUpToDate determines if the given (lastIndex,term) log is more up-to-date
// by comparing the index and term of the last entries in the existing logs.
// If the logs have last entries with different terms, then the log with the
// later term is more up-to-date. If the logs end with the same term, then
// whichever log has the larger lastIndex is more up-to-date. If the logs are
// the same, the given log is up-to-date.
func (l *raftLog) isUpToDate(lasti, term uint64) bool {
	return term > l.lastTerm() || (term == l.lastTerm() && lasti >= l.lastIndex())
}

func (l *raftLog) matchTerm(i, term uint64) bool {
	return l.term(i) == term
}

func (l *raftLog) maybeCommit(maxIndex, term uint64) bool {
	if maxIndex > l.committed && l.term(maxIndex) == term {
		l.commitTo(maxIndex)
		return true
	}
	return false
}

func (l *raftLog) restore(s pb.Snapshot) {
	err := l.storage.ApplySnapshot(s)
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	l.committed = s.Metadata.Index
	l.applied = s.Metadata.Index
	l.unstable = l.committed + 1
	l.unstableEnts = nil
}

func (l *raftLog) at(i uint64) *pb.Entry {
	ents := l.slice(i, i+1)
	if len(ents) == 0 {
		return nil
	}
	return &ents[0]
}

// slice returns a slice of log entries from lo through hi-1, inclusive.
func (l *raftLog) slice(lo uint64, hi uint64) []pb.Entry {
	if lo >= hi {
		return nil
	}
	if l.isOutOfBounds(lo) || l.isOutOfBounds(hi-1) {
		return nil
	}
	var ents []pb.Entry
	if lo < l.unstable {
		storedEnts, err := l.storage.Entries(lo, min(hi, l.unstable))
		if err == ErrCompacted {
			return nil
		} else if err != nil {
			panic(err) // TODO(bdarnell)
		}
		ents = append(ents, storedEnts...)
	}
	if len(l.unstableEnts) > 0 && hi > l.unstable {
		firstUnstable := max(lo, l.unstable)
		ents = append(ents, l.unstableEnts[firstUnstable-l.unstable:hi-l.unstable]...)
	}
	return ents
}

func (l *raftLog) isOutOfBounds(i uint64) bool {
	if i < l.firstIndex() || i > l.lastIndex() {
		return true
	}
	return false
}

func (l *raftLog) isOutOfAppliedBounds(i uint64) bool {
	if i < l.firstIndex() || i > l.applied {
		return true
	}
	return false
}

func min(a, b uint64) uint64 {
	if a > b {
		return b
	}
	return a
}

func max(a, b uint64) uint64 {
	if a > b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>package enterprise_test

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"golang.org/x/net/context"

	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/enterprise"
	"github.com/influxdata/chronograf/log"
)

func Test_Enterprise_FetchesDataNodes(t *testing.T) {
	t.Parallel()

	ctrl := &ControlClient{
		Cluster: &enterprise.Cluster{},
	}
	cl := &enterprise.Client{
		Ctrl: ctrl,
	}

	bg := context.Background()
	err := cl.Connect(bg, &chronograf.Source{})

	if err != nil {
		t.Fatal("Unexpected error while creating enterprise client. err:", err)
	}

	if ctrl.ShowClustersCalled != true {
		t.Fatal("Expected request to meta node but none was issued")
	}
}

func Test_Enterprise_IssuesQueries(t *testing.T) {
	t.Parallel()

	called := false
	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		called = true
		if r.URL.Path != "/query" {
			t.Fatal("Expected request to '/query' but was", r.URL.Path)
		}
		rw.Write([]byte(`{}`))
	}))
	defer ts.Close()

	cl := &enterprise.Client{
		Ctrl:   NewMockControlClient(ts.URL),
		Logger: log.New(log.DebugLevel),
	}

	err := cl.Connect(context.Background(), &chronograf.Source{})
	if err != nil {
		t.Fatal("Unexpected error initializing client: err:", err)
	}

	_, err = cl.Query(context.Background(), chronograf.Query{Command: "show shards", DB: "_internal", RP: "autogen"})

	if err != nil {
		t.Fatal("Unexpected error while querying data node: err:", err)
	}

	if called == false {
		t.Fatal("Expected request to data node but none was received")
	}
}

func Test_Enterprise_AdvancesDataNodes(t *testing.T) {
	m1 := NewMockTimeSeries("http://host-1.example.com:8086")
	m2 := NewMockTimeSeries("http://host-2.example.com:8086")
	cl := enterprise.NewClientWithTimeSeries(log.New(log.DebugLevel), chronograf.TimeSeries(m1), chronograf.TimeSeries(m2))

	err := cl.Connect(context.Background(), &chronograf.Source{})
	if err != nil {
		t.Error("Unexpected error while initializing client: err:", err)
	}

	_, err = cl.Query(context.Background(), chronograf.Query{Command: "show shards", DB: "_internal", RP: "autogen"})
	if err != nil {
		t.Fatal("Unexpected error while issuing query: err:", err)
	}

	_, err = cl.Query(context.Background(), chronograf.Query{Command: "show shards", DB: "_internal", RP: "autogen"})
	if err != nil {
		t.Fatal("Unexpected error while issuing query: err:", err)
	}

	if m1.QueryCtr != 1 || m2.QueryCtr != 1 {
		t.Fatalf("Expected m1.Query to be called once but was %d. Expected m2.Query to be called once but was %d\n", m1.QueryCtr, m2.QueryCtr)
	}
}

func Test_Enterprise_NewClientWithURL(t *testing.T) {
	t.Parallel()

	urls := []struct {
		url       string
		username  string
		password  string
		tls       bool
		shouldErr bool
	}{
		{"http://localhost:8086", "", "", false, false},
		{"https://localhost:8086", "", "", false, false},
		{"http://localhost:8086", "username", "password", false, false},

		{"http://localhost:8086", "", "", true, false},
		{"https://localhost:8086", "", "", true, false},

		{"localhost:8086", "", "", false, false},
		{"localhost:8086", "", "", true, false},

		{":http", "", "", false, true},
	}

	for _, testURL := range urls {
		_, err := enterprise.NewClientWithURL(testURL.url, testURL.username, testURL.password, testURL.tls, log.New(log.DebugLevel))
		if err != nil && !testURL.shouldErr {
			t.Errorf("Unexpected error creating Client with URL %s and TLS preference %t. err: %s", testURL.url, testURL.tls, err.Error())
		} else if err == nil && testURL.shouldErr {
			t.Errorf("Expected error creating Client with URL %s and TLS preference %t", testURL.url, testURL.tls)
		}
	}
}

func Test_Enterprise_ComplainsIfNotOpened(t *testing.T) {
	m1 := NewMockTimeSeries("http://host-1.example.com:8086")
	cl := enterprise.NewClientWithTimeSeries(log.New(log.DebugLevel), chronograf.TimeSeries(m1))
	_, err := cl.Query(context.Background(), chronograf.Query{Command: "show shards", DB: "_internal", RP: "autogen"})
	if err != chronograf.ErrUninitialized {
		t.Error("Expected ErrUnitialized, but was this err:", err)
	}
}
<commit_msg>Add enterprise allowance test<commit_after>package enterprise_test

import (
	"context"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"

	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/enterprise"
	"github.com/influxdata/chronograf/log"
)

func Test_Enterprise_FetchesDataNodes(t *testing.T) {
	t.Parallel()

	ctrl := &ControlClient{
		Cluster: &enterprise.Cluster{},
	}
	cl := &enterprise.Client{
		Ctrl: ctrl,
	}

	bg := context.Background()
	err := cl.Connect(bg, &chronograf.Source{})

	if err != nil {
		t.Fatal("Unexpected error while creating enterprise client. err:", err)
	}

	if ctrl.ShowClustersCalled != true {
		t.Fatal("Expected request to meta node but none was issued")
	}
}

func Test_Enterprise_IssuesQueries(t *testing.T) {
	t.Parallel()

	called := false
	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		called = true
		if r.URL.Path != "/query" {
			t.Fatal("Expected request to '/query' but was", r.URL.Path)
		}
		rw.Write([]byte(`{}`))
	}))
	defer ts.Close()

	cl := &enterprise.Client{
		Ctrl:   NewMockControlClient(ts.URL),
		Logger: log.New(log.DebugLevel),
	}

	err := cl.Connect(context.Background(), &chronograf.Source{})
	if err != nil {
		t.Fatal("Unexpected error initializing client: err:", err)
	}

	_, err = cl.Query(context.Background(), chronograf.Query{Command: "show shards", DB: "_internal", RP: "autogen"})

	if err != nil {
		t.Fatal("Unexpected error while querying data node: err:", err)
	}

	if called == false {
		t.Fatal("Expected request to data node but none was received")
	}
}

func Test_Enterprise_AdvancesDataNodes(t *testing.T) {
	m1 := NewMockTimeSeries("http://host-1.example.com:8086")
	m2 := NewMockTimeSeries("http://host-2.example.com:8086")
	cl := enterprise.NewClientWithTimeSeries(log.New(log.DebugLevel), chronograf.TimeSeries(m1), chronograf.TimeSeries(m2))

	err := cl.Connect(context.Background(), &chronograf.Source{})
	if err != nil {
		t.Error("Unexpected error while initializing client: err:", err)
	}

	_, err = cl.Query(context.Background(), chronograf.Query{Command: "show shards", DB: "_internal", RP: "autogen"})
	if err != nil {
		t.Fatal("Unexpected error while issuing query: err:", err)
	}

	_, err = cl.Query(context.Background(), chronograf.Query{Command: "show shards", DB: "_internal", RP: "autogen"})
	if err != nil {
		t.Fatal("Unexpected error while issuing query: err:", err)
	}

	if m1.QueryCtr != 1 || m2.QueryCtr != 1 {
		t.Fatalf("Expected m1.Query to be called once but was %d. Expected m2.Query to be called once but was %d\n", m1.QueryCtr, m2.QueryCtr)
	}
}

func Test_Enterprise_NewClientWithURL(t *testing.T) {
	t.Parallel()

	urls := []struct {
		url       string
		username  string
		password  string
		tls       bool
		shouldErr bool
	}{
		{"http://localhost:8086", "", "", false, false},
		{"https://localhost:8086", "", "", false, false},
		{"http://localhost:8086", "username", "password", false, false},

		{"http://localhost:8086", "", "", true, false},
		{"https://localhost:8086", "", "", true, false},

		{"localhost:8086", "", "", false, false},
		{"localhost:8086", "", "", true, false},

		{":http", "", "", false, true},
	}

	for _, testURL := range urls {
		_, err := enterprise.NewClientWithURL(testURL.url, testURL.username, testURL.password, testURL.tls, log.New(log.DebugLevel))
		if err != nil && !testURL.shouldErr {
			t.Errorf("Unexpected error creating Client with URL %s and TLS preference %t. err: %s", testURL.url, testURL.tls, err.Error())
		} else if err == nil && testURL.shouldErr {
			t.Errorf("Expected error creating Client with URL %s and TLS preference %t", testURL.url, testURL.tls)
		}
	}
}

func Test_Enterprise_ComplainsIfNotOpened(t *testing.T) {
	m1 := NewMockTimeSeries("http://host-1.example.com:8086")
	cl := enterprise.NewClientWithTimeSeries(log.New(log.DebugLevel), chronograf.TimeSeries(m1))
	_, err := cl.Query(context.Background(), chronograf.Query{Command: "show shards", DB: "_internal", RP: "autogen"})
	if err != chronograf.ErrUninitialized {
		t.Error("Expected ErrUnitialized, but was this err:", err)
	}
}

func TestClient_Allowances(t *testing.T) {
	tests := []struct {
		name string

		want chronograf.Allowances
	}{
		{
			name: "All possible enterprise permissions",
			want: chronograf.Allowances{
				"NoPermissions",
				"ViewAdmin",
				"ViewChronograf",
				"CreateDatabase",
				"CreateUserAndRole",
				"AddRemoveNode",
				"DropDatabase",
				"DropData",
				"ReadData",
				"WriteData",
				"Rebalance",
				"ManageShard",
				"ManageContinuousQuery",
				"ManageQuery",
				"ManageSubscription",
				"Monitor",
				"CopyShard",
				"KapacitorAPI",
				"KapacitorConfigAPI",
			},
		},
	}
	for _, tt := range tests {
		c := &enterprise.Client{}
		if got := c.Allowances(context.Background()); !reflect.DeepEqual(got, tt.want) {
			t.Errorf("%q. Client.Allowances() = %v, want %v", tt.name, got, tt.want)
		}
	}
}
<|endoftext|>


<commit_before>package attached

import (
	"errors"
	"fmt"
	"syscall"

	"github.com/cam72cam/delve/proctl"
)

func Attach(pid int) (*Process, error) {
	dbp, err := proctl.Attach(pid)
	if err != nil {
		return nil, err
	}
	return &Process{dbp: dbp}, nil
}

func Launch(cmd []string) (*Process, error) {
	dbp, err := proctl.Launch(cmd)
	if err != nil {
		return nil, err
	}
	return &Process{dbp: dbp}, nil
}

type Process struct {
	dbp *proctl.DebuggedProcess
}

func (p *Process) PID() int {
	return p.dbp.Pid
}

func (p *Process) Kill() error {
	return p.dbp.Process.Kill()
}
func (p *Process) CurrentThreadPoints() (map[int]Point, error) {
	pts := make(map[int]Point)
	for i, t := range p.dbp.Threads {
		pc, err := t.CurrentPC()
		if err != nil && pc != 0 {
			return nil, err
		}
		pt := Point{Addr: pc}
		pt.fromAddr(p)
		pts[i] = pt
	}
	return pts, nil
}

func (p *Process) Funcs() []string {
	res := make([]string, 0)
	for _, f := range p.dbp.GoSymTable.Funcs {
		res = append(res, f.Name)
	}
	return res
}
func (p *Process) HasFunc(name string) bool {
	for _, f := range p.dbp.GoSymTable.Funcs {
		if f.Name == name {
			return true
		}
	}
	return false
}

func (p *Process) BreakPoints() map[uint64]Point {
	res := make(map[uint64]Point)
	for addr, _ := range p.dbp.BreakPoints {
		pt := Point{Addr: addr}
		pt.fromAddr(p)
		res[addr] = pt
	}

	return res
}

func (p *Process) Clear(pt Point) (Point, error) {
	if pt.InFile() {
		if err := pt.fromFile(p); err != nil {
			return Point{}, err
		}
	}
	_, err := p.dbp.Clear(pt.Addr)
	return pt, err
}

func (p *Process) Break(pt Point) (Point, error) {
	if pt.InFile() {
		if err := pt.fromFile(p); err != nil {
			return Point{}, err
		}
	} else if pt.Func != "" {
		if err := pt.fromFunc(p); err != nil {
			return Point{}, err
		}
	}
	_, err := p.dbp.Break(uintptr(pt.Addr))
	return pt, err
}

type Point struct {
	Func string
	File string
	Line int
	Addr uint64
}

func (pt *Point) String() string {
	return fmt.Sprintf("0x%x %s (%s:%d)", pt.Addr, pt.Func, pt.File, pt.Line)
}

var ErrAddrNotFound = errors.New("Error Address not found!")
var ErrFuncNotFound = errors.New("Error Func not found!")

func (pt *Point) fromAddr(p *Process) error {
	f, l, fn := p.dbp.GoSymTable.PCToLine(pt.Addr)
	if fn != nil {
		pt.File = f
		pt.Line = l
		pt.Func = fn.Name
		return nil
	}
	return ErrAddrNotFound
}

func (pt *Point) fromFunc(p *Process) error {
	fn := p.dbp.GoSymTable.LookupFunc(pt.Func)
	if fn != nil {
		pt.Addr = fn.Entry
		return pt.fromAddr(p)
	}
	return ErrFuncNotFound
}

func (pt *Point) fromFile(p *Process) error {
	pc, fn, err := p.dbp.GoSymTable.LineToPC(pt.File, pt.Line)
	if err != nil {
		return err
	}
	pt.Addr = pc
	pt.Func = fn.Name
	return nil
}

func (pos Point) InFile() bool {
	return pos.File != ""
}

func (p *Process) CurrentPoint() (pt Point, err error) {
	regs, err := p.dbp.Registers()
	if err != nil {
		return pt, err
	}
	pt = Point{Addr: regs.PC()}
	return pt, pt.fromAddr(p)
}

func (p *Process) Continue() error {
	return p.dbp.Continue()
}

func (p *Process) StepAll() error {
	for _, t := range p.dbp.Threads {
		if err := t.Step(); err != nil {
			return err
		}
	}
	return p.dbp.Step()
}
func (p *Process) StepCurrent() error {
	return p.dbp.CurrentThread.Step()
}
func (p *Process) Step(id int) error {
	if t, ok := p.dbp.Threads[id]; ok {
		return t.Step()
	}
	return fmt.Errorf("%d is not a thread", id)
}
func (p *Process) NextAll() error {
	for _, t := range p.dbp.Threads {
		if err := t.Step(); err != nil {
			if _, ok := err.(proctl.TimeoutError); !ok && err != syscall.ESRCH {
				return err
			}
		}
	}
	return p.dbp.Step()
}
func (p *Process) NextCurrent() error {
	return p.dbp.CurrentThread.Step()
}
func (p *Process) Next(id int) error {
	if t, ok := p.dbp.Threads[id]; ok {
		return t.Step()
	}
	return fmt.Errorf("%d is not a thread", id)
}
<commit_msg>Fix Next wrapper<commit_after>package attached

import (
	"errors"
	"fmt"
	"syscall"

	"github.com/cam72cam/delve/proctl"
)

func Attach(pid int) (*Process, error) {
	dbp, err := proctl.Attach(pid)
	if err != nil {
		return nil, err
	}
	return &Process{dbp: dbp}, nil
}

func Launch(cmd []string) (*Process, error) {
	dbp, err := proctl.Launch(cmd)
	if err != nil {
		return nil, err
	}
	return &Process{dbp: dbp}, nil
}

type Process struct {
	dbp *proctl.DebuggedProcess
}

func (p *Process) PID() int {
	return p.dbp.Pid
}

func (p *Process) Kill() error {
	return p.dbp.Process.Kill()
}
func (p *Process) CurrentThreadPoints() (map[int]Point, error) {
	pts := make(map[int]Point)
	for i, t := range p.dbp.Threads {
		pc, err := t.CurrentPC()
		if err != nil && pc != 0 {
			return nil, err
		}
		pt := Point{Addr: pc}
		pt.fromAddr(p)
		pts[i] = pt
	}
	return pts, nil
}

func (p *Process) Funcs() []string {
	res := make([]string, 0)
	for _, f := range p.dbp.GoSymTable.Funcs {
		res = append(res, f.Name)
	}
	return res
}
func (p *Process) HasFunc(name string) bool {
	for _, f := range p.dbp.GoSymTable.Funcs {
		if f.Name == name {
			return true
		}
	}
	return false
}

func (p *Process) BreakPoints() map[uint64]Point {
	res := make(map[uint64]Point)
	for addr, _ := range p.dbp.BreakPoints {
		pt := Point{Addr: addr}
		pt.fromAddr(p)
		res[addr] = pt
	}

	return res
}

func (p *Process) Clear(pt Point) (Point, error) {
	if pt.InFile() {
		if err := pt.fromFile(p); err != nil {
			return Point{}, err
		}
	}
	_, err := p.dbp.Clear(pt.Addr)
	return pt, err
}

func (p *Process) Break(pt Point) (Point, error) {
	if pt.InFile() {
		if err := pt.fromFile(p); err != nil {
			return Point{}, err
		}
	} else if pt.Func != "" {
		if err := pt.fromFunc(p); err != nil {
			return Point{}, err
		}
	}
	_, err := p.dbp.Break(uintptr(pt.Addr))
	return pt, err
}

type Point struct {
	Func string
	File string
	Line int
	Addr uint64
}

func (pt *Point) String() string {
	return fmt.Sprintf("0x%x %s (%s:%d)", pt.Addr, pt.Func, pt.File, pt.Line)
}

var ErrAddrNotFound = errors.New("Error Address not found!")
var ErrFuncNotFound = errors.New("Error Func not found!")

func (pt *Point) fromAddr(p *Process) error {
	f, l, fn := p.dbp.GoSymTable.PCToLine(pt.Addr)
	if fn != nil {
		pt.File = f
		pt.Line = l
		pt.Func = fn.Name
		return nil
	}
	return ErrAddrNotFound
}

func (pt *Point) fromFunc(p *Process) error {
	fn := p.dbp.GoSymTable.LookupFunc(pt.Func)
	if fn != nil {
		pt.Addr = fn.Entry
		return pt.fromAddr(p)
	}
	return ErrFuncNotFound
}

func (pt *Point) fromFile(p *Process) error {
	pc, fn, err := p.dbp.GoSymTable.LineToPC(pt.File, pt.Line)
	if err != nil {
		return err
	}
	pt.Addr = pc
	pt.Func = fn.Name
	return nil
}

func (pos Point) InFile() bool {
	return pos.File != ""
}

func (p *Process) CurrentPoint() (pt Point, err error) {
	regs, err := p.dbp.Registers()
	if err != nil {
		return pt, err
	}
	pt = Point{Addr: regs.PC()}
	return pt, pt.fromAddr(p)
}

func (p *Process) Continue() error {
	return p.dbp.Continue()
}

func (p *Process) StepAll() error {
	for _, t := range p.dbp.Threads {
		if err := t.Step(); err != nil {
			return err
		}
	}
	return nil
}
func (p *Process) StepCurrent() error {
	return p.dbp.CurrentThread.Step()
}
func (p *Process) Step(id int) error {
	if t, ok := p.dbp.Threads[id]; ok {
		return t.Step()
	}
	return fmt.Errorf("%d is not a thread", id)
}
func (p *Process) NextAll() error {
	for _, t := range p.dbp.Threads {
		if err := t.Next(); err != nil {
			if _, ok := err.(proctl.TimeoutError); !ok && err != syscall.ESRCH {
				return err
			}
		}
	}
	return nil
}
func (p *Process) NextCurrent() error {
	return p.dbp.CurrentThread.Next()
}
func (p *Process) Next(id int) error {
	if t, ok := p.dbp.Threads[id]; ok {
		return t.Next()
	}
	return fmt.Errorf("%d is not a thread", id)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	//"image"
	"github.com/nsf/termbox-go"
	"image/gif"
	"os"
	"time"
)

func exitOnError(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func renderFrame(g *gif.GIF, framenum int) error {

	return nil
}

func main() {
	if len(os.Args) == 1 {
		fmt.Fprintln(os.Stderr, "Usage: gogif <filename>")
		os.Exit(1)
	}

	f, err := os.Open(os.Args[1])
	exitOnError(err)

	g, err := gif.DecodeAll(f)
	exitOnError(err)

	gc := GameCore{}
	gc.TickTime = time.Millisecond * 40

	gc.OnEvent = func(gc *GameCore, ev *termbox.Event) error {
		if ev.Type == termbox.EventKey {
			if ev.Ch == 'q' {
				gc.DoQuit = true
			}
		}
		return nil
	}

	frameNumber := 0

	gc.OnTick = func(gc *GameCore) error {
		err := renderFrame(g, frameNumber)
		frameNumber++
		return err
	}

	gc.Run()
}
<commit_msg>initial animation<commit_after>package main

import (
	"fmt"
	//"image"
	"github.com/nsf/termbox-go"
	"image/gif"
	"os"
	"time"
)

func exitOnError(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

type ColourMapFunc func(idx uint8) (termbox.Attribute, termbox.Attribute)

func test(idx uint8) (termbox.Attribute, termbox.Attribute) {
	return termbox.Attribute(idx), termbox.Attribute(idx)
}

func renderFrame(g *gif.GIF, framenum int, cmap ColourMapFunc) error {

	width, height := termbox.Size()

	for y := 0; y < height; y++ {
		lineOffset := g.Image[framenum].Stride * y
		for x := 0; x < width; x++ {
			fg, bg := cmap(g.Image[framenum].Pix[x+lineOffset])
			termbox.SetCell(x, y, ' ', fg, bg)
		}
	}

	return nil
}

func main() {
	if len(os.Args) == 1 {
		fmt.Fprintln(os.Stderr, "Usage: gogif <filename>")
		os.Exit(1)
	}

	f, err := os.Open(os.Args[1])
	exitOnError(err)

	g, err := gif.DecodeAll(f)
	exitOnError(err)

	gc := GameCore{}
	gc.TickTime = time.Millisecond * 40

	gc.OnEvent = func(gc *GameCore, ev *termbox.Event) error {
		if ev.Type == termbox.EventKey {
			if ev.Ch == 'q' {
				gc.DoQuit = true
			}
		}
		return nil
	}

	frameNumber := 0

	gc.OnTick = func(gc *GameCore) error {
		err := renderFrame(g, frameNumber, test)
		frameNumber++
		if len(g.Image) == frameNumber {
			frameNumber = 0
		}
		return err
	}

	gc.Run()
}
<|endoftext|>