<commit_before>package main

import (
	"log"
	"os"

	"github.com/dynport/urknall"
)

// This small example will build a target with redis and nginx. A pretty
// pointless setup, but good enough to demonstrate features.
//
// In urknall will build a target with a package. The target is the machine
// that should be set up automatically. The package is a specification of what
// should be set up and how. This is a three layer architecture:
// - commands are the atoms, the stuff actually executed on the target (think
//   of it as shell commands).
// - a task is a list of commands with order kept. It has a caching mechanism
//   built in, that will determine for each command whether it has been
//   executed previously (in that case it won't be executed again). This
//   prevents the system from repeatedly doing stuff over and over again. If a
//   command changed it and all following commands of the task will be executed
//   again.
// - a package is a container of tasks and other packages. It is used to
//   give projects structure.
// Neither tasks nor packages are generate by the user, Instead users will
// create Package- and TaskBuilders that are given an respective item for
// adding things.
func main() {
	// First set up some logigng. Stdout is fine in most cases, but could be
	// sent to a file or somewhere else.
	defer urknall.OpenLogger(os.Stdout).Close()

	// Next define what the target is.
	target, e := urknall.NewSshTargetWithPassword("ubuntu@192.168.56.10", "ubuntu")
	if e != nil {
		panic(e.Error())
	}

	// Create some package builder, aka something that implements the
	// PackageBuilder interface.
	pkgBuilder := &Example{Hostname: "example"}

	// Build the package and apply it to the target.
	e = urknall.Run(target, pkgBuilder)
	if e != nil {
		log.Fatal(e)
	}
}

// The example package builder. This one has no configuration, but implements
// the PackageBuilder interface.
type Example struct {
	Hostname string `urknall:"required=true"`
}

// The BuildPackage method of the PackageBuilder interface is given an package
// (from urknall) that can be populated with tasks and subpackages. The names
// are given as first parameter to the package's Add method are concatenated in
// the resulting hierarchy (note the first column of the logged output).
// Tasks can either be created ad hoc, i.e. without configuration using the
// NewTask function, or with configuration as in System task example.
func (ex *Example) BuildPackage(pkg urknall.Package) {
	pkg.Add("update", urknall.NewTask(UpdatePackages()))
	pkg.Add("hostname", &System{Hostname: ex.Hostname})
	pkg.Add("srv", &Services{
		NginxVersion: "1.4.4",
		RedisVersion: "2.8.9",
	})
}

// A simple task builder creating a task that will set system properties (the
// hostname in this example).
type System struct {
	Hostname string `urknall:"required=true"`
}

// Task builders must implement the TaskBuilder interface, i.e. have the
// BuildTask method. It is given a task that can be populated with commands.
func (sys *System) BuildTask(task urknall.Task) {
	task.Add(
		"hostname localhost", // Set hostname to make sudo happy.
		&FileCommand{Path: "/etc/hostname", Content: sys.Hostname},
		&FileCommand{Path: "/etc/hosts", Content: "127.0.0.1 {{ .Hostname }} localhost"},
		"hostname -F /etc/hostname",
	)
}

// Another PackageBuilder that now uses Task- and PackageBuilders predefined in
// urknall packages (see urknall binary for more information).
type Services struct {
	NginxVersion string `urknall:"default='1.4.4'"`
	RedisVersion string `urknall:"default='2.8.8'"`
}

func (srv *Services) BuildPackage(pkg urknall.Package) {
	pkg.Add("nginx", &Nginx{Version: srv.NginxVersion})
	pkg.Add("redis", &Redis{Version: srv.RedisVersion})
}
<commit_msg>minor wording adaptions, please check for correctness<commit_after>package main

import (
	"log"
	"os"

	"github.com/dynport/urknall"
)

// This small example will build a target with redis and nginx. A pretty
// pointless setup, but good enough to demonstrate features.
//
// In urknall we will build a target with a package. The machine
// that is to be set up automatically is called target. The package is a specification of what
// should be set up and how. This is a three layer architecture:
// - commands are the atoms, the stuff actually executed on the target (think
//   of it as shell commands).
// - a task is an ordered list of commands. It has a caching mechanism
//   built in that determines for any command whether it has been
//   executed previously (in that case it won't be executed again). This
//   prevents the system from doing stuff over and over again. If a
//   command changes, all following commands of the ordered list of commands will be executed
//   again.
// - a package is a container of tasks and other packages. It is used to
//   structure projects.
// Neither tasks nor packages are generate by the user. Instead users are encouraged to
// create PackageBuilders and TaskBuilders that add things to given tasks or packages (or targets ?).

func main() {
	// First set up some logging. Stdout is fine in most cases, but it also could be
	// sent to a file or somewhere else.
	defer urknall.OpenLogger(os.Stdout).Close()

	// Next define the target.
	target, e := urknall.NewSshTargetWithPassword("ubuntu@192.168.56.10", "ubuntu")
	if e != nil {
		panic(e.Error())
	}

	// Create an object of a type that implements the
	// PackageBuilder interface.
	pkgBuilder := &Example{Hostname: "example"}

	// Run the PackageBuilder on the target to build the package's content
	e = urknall.Run(target, pkgBuilder)
	if e != nil {
		log.Fatal(e)
	}
}

// The example package builder. It has no configuration, but implements
// the PackageBuilder interface.
type Example struct {
	Hostname string `urknall:"required=true"`
}

// The BuildPackage method of the PackageBuilder interface is given a Package
// (from urknall) that can be populated with Tasks and other Packages. Tasks or Packages
// are added with an identifying name. The names are concatenated in
// the resulting hierarchy (note the first column of the logged output).
// Tasks can either be created without configuration using the
// NewTask function or with configuration as in System-Task example.
func (ex *Example) BuildPackage(pkg urknall.Package) {
	pkg.Add("update", urknall.NewTask(UpdatePackages()))
	pkg.Add("hostname", &System{Hostname: ex.Hostname})
	pkg.Add("srv", &Services{
		NginxVersion: "1.4.4",
		RedisVersion: "2.8.9",
	})
}

// A simple task builder creating a task that will set system properties (the
// hostname in this example).
type System struct {
	Hostname string `urknall:"required=true"`
}

// Task builders must implement the TaskBuilder interface and thereby implement the
// BuildTask method. It is called with a Task to which commands can be added similarly
// as in the case of the Package above.
func (sys *System) BuildTask(task urknall.Task) {
	task.Add(
		"hostname localhost", // Set hostname to make sudo happy.
		&FileCommand{Path: "/etc/hostname", Content: sys.Hostname},
		&FileCommand{Path: "/etc/hosts", Content: "127.0.0.1 {{ .Hostname }} localhost"},
		"hostname -F /etc/hostname",
	)
}

// Another PackageBuilder that now uses Task- and PackageBuilders predefined in
// urknall packages (see urknall binary for more information).
type Services struct {
	NginxVersion string `urknall:"default='1.4.4'"`
	RedisVersion string `urknall:"default='2.8.8'"`
}

func (srv *Services) BuildPackage(pkg urknall.Package) {
	pkg.Add("nginx", &Nginx{Version: srv.NginxVersion})
	pkg.Add("redis", &Redis{Version: srv.RedisVersion})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"runtime/pprof"
	"time"

	"github.com/kavehmz/prime"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var memprofile = flag.String("memprofile", "", "write memory profile to this file")

func main() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	t := time.Now().UnixNano()

	// fmt.Println("number of primes (non-segmented-method):", len(prime.SieveOfEratosthenes(1000000000)))
	fmt.Println("number of primes (segmented-method):", len(prime.Primes(1000000)))
	fmt.Println("seconds it took:", float64(time.Now().UnixNano()-t)/1000000000)

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}

}
<commit_msg>both 1G<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"runtime/pprof"
	"time"

	"github.com/kavehmz/prime"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var memprofile = flag.String("memprofile", "", "write memory profile to this file")

func main() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	t := time.Now().UnixNano()

	fmt.Println("number of primes (non-segmented-method):", len(prime.SieveOfEratosthenes(1000000000)))
	fmt.Println("number of primes (segmented-method):", len(prime.Primes(1000000000)))
	fmt.Println("seconds it took:", float64(time.Now().UnixNano()-t)/1000000000)

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}

}
<|endoftext|>


<commit_before>package main

import (
	"context"

	"os"
	"os/signal"

	"time"

	"net"
	"net/http"

	"fmt"
	"github.com/labstack/echo"
	"github.com/labstack/gommon/log"
)

func hello(c echo.Context) error {
	ip, _ := getMyInterfaceAddr()
	return c.String(http.StatusOK, fmt.Sprintf("Hello World from server with IP=%s! Now is %s",
		ip.String(),
		time.Now().String()))
}

func getMyInterfaceAddr() (net.IP, error) {
    ifaces, err := net.Interfaces()
    if err != nil {
        return nil, err
    }
    addresses := []net.IP{}
    for _, iface := range ifaces {

        if iface.Flags&net.FlagUp == 0 {
            continue // interface down
        }
        if iface.Flags&net.FlagLoopback != 0 {
            continue // loopback interface
        }
        addrs, err := iface.Addrs()
        if err != nil {
            continue
        }

        for _, addr := range addrs {
            var ip net.IP
            switch v := addr.(type) {
            case *net.IPNet:
                ip = v.IP
            case *net.IPAddr:
                ip = v.IP
            }
            if ip == nil || ip.IsLoopback() {
                continue
            }
            ip = ip.To4()
            if ip == nil {
                continue // not an ipv4 address
            }
            addresses = append(addresses, ip)
        }
    }
    if len(addresses) == 0 {
        return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses)
    }
    //only need first
    return addresses[0], nil
}

func main() {
	// Setup
	e := echo.New()
	e.Logger.SetLevel(log.INFO)

	// Routes
	e.GET("/", hello)

	// Start server
	go func() {
		if err := e.Start(":8080"); err != nil {
			e.Logger.Info("shutting down the server")
		}
	}()

	// Wait for interrupt signal to gracefully shutdown the server with
	// a timeout of 10 seconds.
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err := e.Shutdown(ctx); err != nil {
		e.Logger.Fatal(err)
	}
}
<commit_msg>display host name instead of IP<commit_after>package main

import (
	"context"

	"os"
	"os/signal"

	"time"

	"net/http"

	"fmt"
	"github.com/labstack/echo"
	"github.com/labstack/gommon/log"
)

func hello(c echo.Context) error {
	host, _ := os.Hostname()
	return c.String(http.StatusOK, fmt.Sprintf("Hello World from server %s! Now is %s",
		host,
		time.Now().String()))
}

func main() {
	// Setup
	e := echo.New()
	e.Logger.SetLevel(log.INFO)

	// Routes
	e.GET("/", hello)

	// Start server
	go func() {
		if err := e.Start(":8080"); err != nil {
			e.Logger.Info("shutting down the server")
		}
	}()

	// Wait for interrupt signal to gracefully shutdown the server with
	// a timeout of 10 seconds.
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err := e.Shutdown(ctx); err != nil {
		e.Logger.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/DataDog/dd-trace-go/tracer"
	"github.com/Sirupsen/logrus"
	"github.com/flachnetz/dd-zipkin-proxy"
	"github.com/openzipkin/zipkin-go-opentracing/_thrift/gen-go/zipkincore"
	"regexp"
	"strconv"
	"strings"
)

func main() {
	converter := DefaultSpanConverter{}
	zipkinproxy.Main(converter.Convert)
}

var reHash = regexp.MustCompile("\\b(?:[a-f0-9]{32}|[a-f0-9]{24}|[a-f0-9-]{8}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{12})\\b")
var reNumber = regexp.MustCompile("\\b[0-9]{2,}\\b")
var reIwgHash = regexp.MustCompile("iwg\\.[A-Za-z0-9]{12}\\b")

func SimplifyResourceName(value string) string {
	// check if we need to apply the regexp by checking if a match is possible or not
	digitCount := 0
	hashCharCount := 0
	for idx, char := range value {
		isDigit := char >= '0' && char <= '9'
		if isDigit {
			digitCount++
		}

		if isDigit || char >= 'a' && char <= 'f' {
			hashCharCount++
		}
		if char == '?' {
			value = value[:idx]
			break
		}
	}

	// only search for hash, if we have enough chars for it
	if hashCharCount >= 24 {
		value = reHash.ReplaceAllString(value, "_HASH_")
	}

	// only replace numbers, if we have enough digits for a match
	if digitCount >= 2 {
		value = reNumber.ReplaceAllString(value, "_NUMBER_")
	}

	if strings.HasPrefix(value, "iwg.") {
		value = reIwgHash.ReplaceAllString(value, "iwg._HASH_")
	}

	return value
}

func RemoveQueryString(value string) string {
	idx := strings.IndexByte(value, '?')
	if idx >= 0 {
		return value[:idx]
	}
	return value
}

type DefaultSpanConverter struct {
	current  map[uint64]string
	previous map[uint64]string
}

func (converter *DefaultSpanConverter) Convert(span *zipkincore.Span) *tracer.Span {
	// ignore long running consul update tasks.
	if span.Name == "watch-config-key-values" || span.Name == "catalog-services-watch" {
		return nil
	}

	name := SimplifyResourceName(span.Name)

	converted := &tracer.Span{
		SpanID:   uint64(span.ID),
		ParentID: uint64(span.GetParentID()),
		TraceID:  uint64(span.TraceID),
		Name:     name,
		Resource: name,
		Start:    1000 * span.GetTimestamp(),
		Duration: 1000 * span.GetDuration(),
		Sampled:  true,
	}

	// datadog traces use a trace of 0
	if converted.ParentID == converted.SpanID {
		converted.ParentID = 0
	}

	// split "http:/some/url" or "get:/some/url"
	for _, prefix := range []string{"http:/", "get:/", "post:/"} {
		if strings.HasPrefix(converted.Name, prefix) {
			converted.Resource = converted.Name[len(prefix)-1:]
			converted.Name = prefix[:len(prefix)-2]
			break
		}
	}

	// convert binary annotations (like tags)
	if len(span.BinaryAnnotations) > 0 {
		converted.Meta = make(map[string]string, len(span.BinaryAnnotations))
		for _, an := range span.BinaryAnnotations {
			if an.AnnotationType == zipkincore.AnnotationType_STRING {
				key := an.Key

				// rename keys to better match the datadog one.
				switch key {
				case "http.status":
					key = "http.status_code"

				case "client.url":
					key = "http.url"
				}

				converted.Meta[key] = string(an.Value)
			}

			if an.Host != nil && an.Host.ServiceName != "" {
				converted.Service = an.Host.ServiceName
			}
		}

		if url := converted.Meta["http.url"]; url != "" {
			converted.Resource = SimplifyResourceName(url)
			converted.Meta["http.url"] = RemoveQueryString(url)
		}

		if status := converted.Meta["http.status_code"]; status != "" {
			if len(status) > 0 && '3' <= status[0] && status[0] <= '9' {
				if statusValue, err := strconv.Atoi(status); err == nil && statusValue >= 400 {
					converted.Error = int32(statusValue)
				}
			}
		}
	}

	extractInfoFromAnnotations(span, converted)

	// simplify some names
	if strings.HasPrefix(converted.Name, "http:") {
		converted.Service = converted.Name[5:]

	} else if converted.Name == "transaction" {
		converted.Service = "oracle"

	} else if sql := converted.Meta["sql"]; sql != "" {
		delete(converted.Meta, "sql")
		converted.Resource = sql
		converted.Service = "sql"
		converted.Meta["sql.query"] = sql

	} else if strings.HasPrefix(converted.Name, "redis:") {
		converted.Service = "redis"

		if key := converted.Meta["redis.key"]; key != "" {
			converted.Resource = SimplifyResourceName(key)

			// the hash is not really important later on. lets not spam datadog with it.
			delete(converted.Meta, "redis.key")
		}

	} else if converted.Service == "core-services" {
		lc := converted.Meta["lc"]

		switch {
		case strings.Contains(converted.Meta["http.url"], ":6080/"):
			converted.Service = "iwg-restrictor"
			converted.Name = iwgNameFromResource(converted.Resource, converted.Name)
			converted.Resource = dropDomainFromUrl(converted.Resource)

		case strings.Contains(converted.Meta["http.url"], ":2080/"):
			converted.Service = "instant-win-game"
			converted.Name = "iwg-game"
			converted.Resource = dropDomainFromUrl(converted.Resource)

		case lc != "" && lc != "servlet" && lc != "HttpClient":
			// TODO: find proper fix for this service name / name datadog magic
			//delete(converted.Meta, "lc")
			converted.Service = lc
		}
	}

	// If we could not get a service, we'll try to get it from the parent span.
	// Try first in the current map, then in the previous one.
	if converted.Service == "" {
		parentService := converter.current[converted.ParentID]
		if parentService != "" {
			converted.Service = parentService
		} else {
			parentService = converter.previous[converted.ParentID]
			if parentService != "" {
				converted.Service = parentService
			}
		}

		// if we did not get a service, use a fallback
		if converted.Service == "" {
			logrus.Warnf("Could not get a service for this span: %+v", span)
			converted.Service = "unknown"
		}
	}

	if lc := converted.Meta["lc"]; lc != "" {
		// TODO: here as well
		//delete(converted.Meta, "lc")

		if converted.Name == "" {
			converted.Name = lc
		}

		if lc == "consul" {
			converted.Service = "consul"
		}
	}

	if converted.Name == "transaction" || converted.Service == "redis" {
		converted.Type = "db"
	} else {
		converted.Type = "http"
	}

	if converted.Name == "hystrix" {
		converted.Resource = converted.Meta["thread"]
	} else if converted.Name == "" {
		logrus.Warnf("Could not get a name for this span: %+v converted: %+v", span, converted)
	}

	if ddService := converted.Meta["dd.service"]; ddService != "" {
		converted.Service = ddService
	}

	if ddName := converted.Meta["dd.name"]; ddName != "" {
		converted.Name = ddName
	}

	if ddResource := converted.Meta["dd.resource"]; ddResource != "" {
		converted.Resource = SimplifyResourceName(ddResource)
	}

	// if name and service differ than the overview page in datadog will only show the one with
	// most of the time spend. This is why we just rename it to the service here so that we can get a nice
	// overview of all resources belonging to the service. Can be removed in the future when datadog is changing things
	converted.Name = converted.Service

	// initialize history maps for span -> parent assignment
	const parentLookupMapSize = 40000
	if len(converter.current) >= parentLookupMapSize || converter.current == nil {
		converter.previous = converter.current
		converter.current = make(map[uint64]string, parentLookupMapSize)
	}

	// remember the service for a short while
	converter.current[converted.SpanID] = converted.Service

	return converted
}

func extractInfoFromAnnotations(span *zipkincore.Span, converted *tracer.Span) {
	// try to get the service from the cs/cr or sr/ss annotations
	var minTimestamp, maxTimestamp int64
	for _, an := range span.Annotations {
		if an.Value == "sr" && an.Host != nil && an.Host.ServiceName != "" {
			converted.Service = an.Host.ServiceName
		}

		if an.Timestamp < minTimestamp || minTimestamp == 0 {
			minTimestamp = an.Timestamp
		}

		if an.Timestamp > maxTimestamp {
			maxTimestamp = an.Timestamp
		}
	}

	if converted.Start == 0 {
		logrus.Warnf("Span had no start/duration, guessing from annotations: %s", identifySpan(span))
		converted.Start = 1000 * minTimestamp
		converted.Duration = 1000 * (maxTimestamp - minTimestamp)
	}
}

// Tries to get some identification for this span. The method tries
// to include the value of the local-component tag and the value of the tags name.
func identifySpan(span *zipkincore.Span) string {
	var name string
	for _, an := range span.BinaryAnnotations {
		if an.Key == "lc" {
			name = string(an.Value) + ":"
		}
	}

	return name + span.Name
}

func dropDomainFromUrl(url string) string {
	switch {
	case strings.HasPrefix(url, "http://"):
		index := strings.IndexRune(url[7:], '/')
		return url[7+index:]

	case strings.HasPrefix(url, "https://"):
		index := strings.IndexRune(url[8:], '/')
		return url[8+index:]
	}

	return url
}

func iwgNameFromResource(resource string, fallback string) string {
	splittedUrl := strings.Split(strings.Trim(resource, "/"), "/")
	if len(splittedUrl) == 1 && splittedUrl[0] != "" {
		return splittedUrl[0]
	} else if len(splittedUrl) > 1 {
		return splittedUrl[len(splittedUrl)-2] + "/" + splittedUrl[len(splittedUrl)-1]
	}
	return fallback
}
<commit_msg>Improve guessing of times.<commit_after>package main

import (
	"github.com/DataDog/dd-trace-go/tracer"
	"github.com/Sirupsen/logrus"
	"github.com/flachnetz/dd-zipkin-proxy"
	"github.com/openzipkin/zipkin-go-opentracing/_thrift/gen-go/zipkincore"
	"regexp"
	"strconv"
	"strings"
)

func main() {
	converter := DefaultSpanConverter{}
	zipkinproxy.Main(converter.Convert)
}

var reHash = regexp.MustCompile("\\b(?:[a-f0-9]{32}|[a-f0-9]{24}|[a-f0-9-]{8}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{12})\\b")
var reNumber = regexp.MustCompile("\\b[0-9]{2,}\\b")
var reIwgHash = regexp.MustCompile("iwg\\.[A-Za-z0-9]{12}\\b")

func SimplifyResourceName(value string) string {
	// check if we need to apply the regexp by checking if a match is possible or not
	digitCount := 0
	hashCharCount := 0
	for idx, char := range value {
		isDigit := char >= '0' && char <= '9'
		if isDigit {
			digitCount++
		}

		if isDigit || char >= 'a' && char <= 'f' {
			hashCharCount++
		}
		if char == '?' {
			value = value[:idx]
			break
		}
	}

	// only search for hash, if we have enough chars for it
	if hashCharCount >= 24 {
		value = reHash.ReplaceAllString(value, "_HASH_")
	}

	// only replace numbers, if we have enough digits for a match
	if digitCount >= 2 {
		value = reNumber.ReplaceAllString(value, "_NUMBER_")
	}

	if strings.HasPrefix(value, "iwg.") {
		value = reIwgHash.ReplaceAllString(value, "iwg._HASH_")
	}

	return value
}

func RemoveQueryString(value string) string {
	idx := strings.IndexByte(value, '?')
	if idx >= 0 {
		return value[:idx]
	}
	return value
}

type DefaultSpanConverter struct {
	current  map[uint64]string
	previous map[uint64]string
}

func (converter *DefaultSpanConverter) Convert(span *zipkincore.Span) *tracer.Span {
	// ignore long running consul update tasks.
	if span.Name == "watch-config-key-values" || span.Name == "catalog-services-watch" {
		return nil
	}

	name := SimplifyResourceName(span.Name)

	converted := &tracer.Span{
		SpanID:   uint64(span.ID),
		ParentID: uint64(span.GetParentID()),
		TraceID:  uint64(span.TraceID),
		Name:     name,
		Resource: name,
		Start:    1000 * span.GetTimestamp(),
		Duration: 1000 * span.GetDuration(),
		Sampled:  true,
	}

	// datadog traces use a trace of 0
	if converted.ParentID == converted.SpanID {
		converted.ParentID = 0
	}

	// split "http:/some/url" or "get:/some/url"
	for _, prefix := range []string{"http:/", "get:/", "post:/"} {
		if strings.HasPrefix(converted.Name, prefix) {
			converted.Resource = converted.Name[len(prefix)-1:]
			converted.Name = prefix[:len(prefix)-2]
			break
		}
	}

	// convert binary annotations (like tags)
	if len(span.BinaryAnnotations) > 0 {
		converted.Meta = make(map[string]string, len(span.BinaryAnnotations))
		for _, an := range span.BinaryAnnotations {
			if an.AnnotationType == zipkincore.AnnotationType_STRING {
				key := an.Key

				// rename keys to better match the datadog one.
				switch key {
				case "http.status":
					key = "http.status_code"

				case "client.url":
					key = "http.url"
				}

				converted.Meta[key] = string(an.Value)
			}

			if an.Host != nil && an.Host.ServiceName != "" {
				converted.Service = an.Host.ServiceName
			}
		}

		if url := converted.Meta["http.url"]; url != "" {
			converted.Resource = SimplifyResourceName(url)
			converted.Meta["http.url"] = RemoveQueryString(url)
		}

		if status := converted.Meta["http.status_code"]; status != "" {
			if len(status) > 0 && '3' <= status[0] && status[0] <= '9' {
				if statusValue, err := strconv.Atoi(status); err == nil && statusValue >= 400 {
					converted.Error = int32(statusValue)
				}
			}
		}
	}

	updateInfoFromAnnotations(span, converted)

	// simplify some names
	if strings.HasPrefix(converted.Name, "http:") {
		converted.Service = converted.Name[5:]

	} else if converted.Name == "transaction" {
		converted.Service = "oracle"

	} else if sql := converted.Meta["sql"]; sql != "" {
		delete(converted.Meta, "sql")
		converted.Resource = sql
		converted.Service = "sql"
		converted.Meta["sql.query"] = sql

	} else if strings.HasPrefix(converted.Name, "redis:") {
		converted.Service = "redis"

		if key := converted.Meta["redis.key"]; key != "" {
			converted.Resource = SimplifyResourceName(key)

			// the hash is not really important later on. lets not spam datadog with it.
			delete(converted.Meta, "redis.key")
		}

	} else if converted.Service == "core-services" {
		lc := converted.Meta["lc"]

		switch {
		case strings.Contains(converted.Meta["http.url"], ":6080/"):
			converted.Service = "iwg-restrictor"
			converted.Name = iwgNameFromResource(converted.Resource, converted.Name)
			converted.Resource = dropDomainFromUrl(converted.Resource)

		case strings.Contains(converted.Meta["http.url"], ":2080/"):
			converted.Service = "instant-win-game"
			converted.Name = "iwg-game"
			converted.Resource = dropDomainFromUrl(converted.Resource)

		case lc != "" && lc != "servlet" && lc != "HttpClient":
			// TODO: find proper fix for this service name / name datadog magic
			//delete(converted.Meta, "lc")
			converted.Service = lc
		}
	}

	// If we could not get a service, we'll try to get it from the parent span.
	// Try first in the current map, then in the previous one.
	if converted.Service == "" {
		parentService := converter.current[converted.ParentID]
		if parentService != "" {
			converted.Service = parentService
		} else {
			parentService = converter.previous[converted.ParentID]
			if parentService != "" {
				converted.Service = parentService
			}
		}

		// if we did not get a service, use a fallback
		if converted.Service == "" {
			logrus.Warnf("Could not get a service for this span: %+v", span)
			converted.Service = "unknown"
		}
	}

	if lc := converted.Meta["lc"]; lc != "" {
		// TODO: here as well
		//delete(converted.Meta, "lc")

		if converted.Name == "" {
			converted.Name = lc
		}

		if lc == "consul" {
			converted.Service = "consul"
		}
	}

	if converted.Name == "transaction" || converted.Service == "redis" {
		converted.Type = "db"
	} else {
		converted.Type = "http"
	}

	if converted.Name == "hystrix" {
		converted.Resource = converted.Meta["thread"]
	} else if converted.Name == "" {
		logrus.Warnf("Could not get a name for this span: %+v converted: %+v", span, converted)
	}

	if ddService := converted.Meta["dd.service"]; ddService != "" {
		converted.Service = ddService
	}

	if ddName := converted.Meta["dd.name"]; ddName != "" {
		converted.Name = ddName
	}

	if ddResource := converted.Meta["dd.resource"]; ddResource != "" {
		converted.Resource = SimplifyResourceName(ddResource)
	}

	// if name and service differ than the overview page in datadog will only show the one with
	// most of the time spend. This is why we just rename it to the service here so that we can get a nice
	// overview of all resources belonging to the service. Can be removed in the future when datadog is changing things
	converted.Name = converted.Service

	// initialize history maps for span -> parent assignment
	const parentLookupMapSize = 40000
	if len(converter.current) >= parentLookupMapSize || converter.current == nil {
		converter.previous = converter.current
		converter.current = make(map[uint64]string, parentLookupMapSize)
	}

	// remember the service for a short while
	converter.current[converted.SpanID] = converted.Service

	return converted
}

func updateInfoFromAnnotations(span *zipkincore.Span, converted *tracer.Span) {
	// try to get the service from the cs/cr or sr/ss annotations
	var minTimestamp, maxTimestamp int64
	for _, an := range span.Annotations {
		if an.Value == "sr" && an.Host != nil && an.Host.ServiceName != "" {
			converted.Service = an.Host.ServiceName
		}

		if an.Timestamp < minTimestamp || minTimestamp == 0 {
			minTimestamp = an.Timestamp
		}

		if an.Timestamp > maxTimestamp {
			maxTimestamp = an.Timestamp
		}
	}

	if converted.Start == 0 || converted.Duration == 0 {
		logrus.Warnf("Span had no start/duration, guessing from annotations: %s", identifySpan(span))
		converted.Start = 1000 * minTimestamp
		converted.Duration = 1000 * (maxTimestamp - minTimestamp)
	}
}

// Tries to get some identification for this span. The method tries
// to include the value of the local-component tag and the value of the tags name.
func identifySpan(span *zipkincore.Span) string {
	var name string
	for _, an := range span.BinaryAnnotations {
		if an.Key == "lc" {
			name = string(an.Value) + ":"
		}
	}

	return name + span.Name
}

func dropDomainFromUrl(url string) string {
	switch {
	case strings.HasPrefix(url, "http://"):
		index := strings.IndexRune(url[7:], '/')
		return url[7+index:]

	case strings.HasPrefix(url, "https://"):
		index := strings.IndexRune(url[8:], '/')
		return url[8+index:]
	}

	return url
}

func iwgNameFromResource(resource string, fallback string) string {
	splittedUrl := strings.Split(strings.Trim(resource, "/"), "/")
	if len(splittedUrl) == 1 && splittedUrl[0] != "" {
		return splittedUrl[0]
	} else if len(splittedUrl) > 1 {
		return splittedUrl[len(splittedUrl)-2] + "/" + splittedUrl[len(splittedUrl)-1]
	}
	return fallback
}
<|endoftext|>


<commit_before>// Package main is an entry point of the application.
package main

import (
	"net/http"
	"runtime"

	"github.com/anonx/sunplate/log"

	"github.com/julienschmidt/httprouter"
)

// Comments below are used by `go generate`.
// Please, DO NOT EDIT if you do not know what you are doing.
//
//go:generate sunplate generate handlers --path ./controllers/ --output ./assets/ --package handlers

func main() {
	// Set max procs for multi-thread executing.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Include handlers and run the app.
	router := httprouter.New()
	log.Error.Fatal(http.ListenAndServe(":8080", router))
}
<commit_msg>Updated example app's router<commit_after>// Package main is an entry point of the application.
package main

import (
	"net/http"
	"runtime"

	"github.com/anonx/sunplate/log"
	"github.com/anonx/sunplate/routing"
)

// Comments below are used by `go generate`.
// Please, DO NOT EDIT if you do not know what you are doing.
//
//go:generate sunplate generate handlers --path ./controllers/ --output ./assets/ --package handlers

func main() {
	// Set max procs for multi-thread executing.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Include handlers and run the app.
	r := routing.NewRouter()
	err := r.Handle(routing.Routes{
		nil,
	}).Build()
	if err != nil {
		log.Error.Fatal(err)
	}
	log.Error.Fatal(http.ListenAndServe(":8080", r))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/hashrabbit/honeybadger"
)

var hb = honeybadger.New("changeme")

func main() {
	defer reportPanic()

	_, err := hb.Reportf("a %s error: %v", "formatted", []string{"foo", "bar", "baz"})
	if err != nil {
		fmt.Printf("Failed to report message %s\n", err)
	}

	panic("oh no!")
}

func reportPanic() {
	if rec := recover(); rec != nil {
		id, err := hb.Report(rec)
		if err != nil {
			fmt.Printf("Failed to report error %s\n", err)
			panic(err)
		}
		fmt.Printf("Recovered and reported error %s\n", id)
	}
}
<commit_msg>Fix import<commit_after>package main

import (
	"fmt"

	"github.com/hashrabbit/honeybadger-go"
)

var hb = honeybadger.New("changeme")

func main() {
	defer reportPanic()

	_, err := hb.Reportf("a %s error: %v", "formatted", []string{"foo", "bar", "baz"})
	if err != nil {
		fmt.Printf("Failed to report message %s\n", err)
	}

	panic("oh no!")
}

func reportPanic() {
	if rec := recover(); rec != nil {
		id, err := hb.Report(rec)
		if err != nil {
			fmt.Printf("Failed to report error %s\n", err)
			panic(err)
		}
		fmt.Printf("Recovered and reported error %s\n", id)
	}
}
<|endoftext|>


<commit_before>package capacitor

import (
	"fmt"
	"strconv"
	"strings"
)

type Capacitor struct {
	Dspace DeploymentSpace
	Executor
}

type NodesInfo struct {
	matrix   map[string]*NodeInfo
	lenWKL   int
	lenNodes int
}

type NodeInfo struct {
	Node
	WKL       string
	Exec      bool
	Reject    bool
	Candidate bool
	When      int
}

func getMatrixKey(ID string, i int) (key string) {
	key = fmt.Sprintf("%v#%v", ID, i)
	return
}

func splitMatrixKey(key string) (ID string, i int) {
	s := strings.Split(key, "#")
	if len(s) > 1 {
		wkl, _ := strconv.ParseInt(s[1], 0, 64)
		return s[0], int(wkl)
	} else {
		return "", -1
	}
}

func buildMatrix(wkls []string, nodes Nodes) (matrix NodesInfo) {
	iNodes := NodesInfo{make(map[string]*NodeInfo), -1, -1}
	max := -1
	for _, node := range nodes {
		for i, wkl := range wkls {
			n := new(NodeInfo)
			n.Node = *node
			n.WKL = wkl
			n.Exec = false
			n.Reject = false
			n.Candidate = false
			n.When = -1
			iNodes.matrix[getMatrixKey(node.ID, i)] = n
		}
		max = node.Height
	}
	iNodes.lenWKL = len(wkls)
	iNodes.lenNodes = max
	return iNodes
}

func (c *Capacitor) HasMore(nodes *NodesInfo) bool {
	for _, node := range nodes.matrix {
		if node.When == -1 {
			return true
		}
	}
	return false
}

func (c *Capacitor) NodesLeft(nodes *NodesInfo) (count int) {
	for _, node := range nodes.matrix {
		if node.When == -1 {
			count++
		}
	}
	return
}

func (pNodes *NodesInfo) MarkCandidate(n *Node, metslo bool, exec int, cWKL int) {
	if n != nil {
		iNodes := *pNodes
		matrix := iNodes.matrix
		for i := cWKL; i >= 0; i-- {
			key := getMatrixKey(n.ID, i)
			nodeInfo := matrix[key]
			if nodeInfo.When == -1 {
				nodeInfo.Candidate = true
				nodeInfo.When = exec
				//fmt.Println("\tmarcando ", key, " candidato ")
			}
		}
		for _, node := range n.Lower {
			pNodes.MarkCandidate(node, metslo, exec, cWKL)
		}
	}
}

func (pNodes *NodesInfo) MarkReject(n *Node, metslo bool, exec int, cWKL int) {
	if n != nil {
		iNodes := *pNodes
		matrix := iNodes.matrix
		for i := cWKL; i < pNodes.lenWKL; i++ {
			key := getMatrixKey(n.ID, i)
			nodeInfo := matrix[key]
			if nodeInfo.When == -1 {
				nodeInfo.Reject = true
				nodeInfo.When = exec
				//fmt.Println("\tmarcando ", key, " rejeitado ")
			}
		}
		for _, node := range n.Higher {
			pNodes.MarkReject(node, metslo, exec, cWKL)
		}
	}
}

func (pNodes *NodesInfo) Mark(key string, metslo bool, exec int) {
	_, cWKL := splitMatrixKey(key)
	//fmt.Printf("INI MARK\n")
	//fmt.Printf("%v ? %v\n", key, metslo)
	iNodes := *pNodes
	matrix := iNodes.matrix

	matrix[key].When = exec
	matrix[key].Exec = true

	if metslo {
		matrix[key].Candidate = true
		pNodes.MarkCandidate(&matrix[key].Node, metslo, exec, cWKL)
	} else {
		matrix[key].Reject = true
		pNodes.MarkReject(&matrix[key].Node, metslo, exec, cWKL)
	}
	//fmt.Printf("FIM MARK\n")
}
func (node *NodeInfo) Equal(other *NodeInfo) bool {
	return node.Height == other.Height && node.ID == other.ID && node.Exec == other.Exec && node.Reject == other.Reject && node.Candidate == other.Candidate && node.When == other.When
}

func (iNode *NodesInfo) Equal(other *NodesInfo) bool {
	clone := *other
	matrix := *iNode
	for key, n := range matrix.matrix {
		if !n.Equal(clone.matrix[key]) {
			return false
		}
	}
	return true
}

func (matrix NodesInfo) Clone() (clone *NodesInfo) {
	mapa := make(map[string]*NodeInfo)
	for key, node := range matrix.matrix {
		n := new(NodeInfo)
		n.Node = node.Node
		n.WKL = node.WKL
		n.Exec = node.Exec
		n.Reject = node.Reject
		n.Candidate = node.Candidate
		n.When = node.When

		mapa[key] = n
	}
	pClone := new(NodesInfo)
	pClone.matrix = mapa
	pClone.lenWKL = matrix.lenWKL
	pClone.lenNodes = matrix.lenNodes
	return pClone
}

func (node NodeInfo) String() (str string) {
	return fmt.Sprintf("{when:%v, exec:%v, candidate:%v, reject:%v}", node.When, node.Exec, node.Candidate, node.Reject)
}

func (nodes NodesInfo) String() (str string) {
	str = fmt.Sprintf("{wkl:%v, heigh:%v, nodes:[\n\t", nodes.lenWKL, nodes.lenNodes)
	for key, n := range nodes.matrix {
		str = fmt.Sprintf("%v[%v]%v\n\t", str, key, n)
	}
	str = fmt.Sprintf("%v]}", str)
	return
}
<commit_msg>Equal not used<commit_after>package capacitor

import (
	"fmt"
	"strconv"
	"strings"
)

type Capacitor struct {
	Dspace DeploymentSpace
	Executor
}

type NodesInfo struct {
	matrix   map[string]*NodeInfo
	lenWKL   int
	lenNodes int
}

type NodeInfo struct {
	Node
	WKL       string
	Exec      bool
	Reject    bool
	Candidate bool
	When      int
}

func getMatrixKey(ID string, i int) (key string) {
	key = fmt.Sprintf("%v#%v", ID, i)
	return
}

func splitMatrixKey(key string) (ID string, i int) {
	s := strings.Split(key, "#")
	if len(s) > 1 {
		wkl, _ := strconv.ParseInt(s[1], 0, 64)
		return s[0], int(wkl)
	} else {
		return "", -1
	}
}

func buildMatrix(wkls []string, nodes Nodes) (matrix NodesInfo) {
	iNodes := NodesInfo{make(map[string]*NodeInfo), -1, -1}
	max := -1
	for _, node := range nodes {
		for i, wkl := range wkls {
			n := new(NodeInfo)
			n.Node = *node
			n.WKL = wkl
			n.Exec = false
			n.Reject = false
			n.Candidate = false
			n.When = -1
			iNodes.matrix[getMatrixKey(node.ID, i)] = n
		}
		max = node.Height
	}
	iNodes.lenWKL = len(wkls)
	iNodes.lenNodes = max
	return iNodes
}

func (c *Capacitor) HasMore(nodes *NodesInfo) bool {
	for _, node := range nodes.matrix {
		if node.When == -1 {
			return true
		}
	}
	return false
}

func (c *Capacitor) NodesLeft(nodes *NodesInfo) (count int) {
	for _, node := range nodes.matrix {
		if node.When == -1 {
			count++
		}
	}
	return
}

func (pNodes *NodesInfo) MarkCandidate(n *Node, metslo bool, exec int, cWKL int) {
	if n != nil {
		iNodes := *pNodes
		matrix := iNodes.matrix
		for i := cWKL; i >= 0; i-- {
			key := getMatrixKey(n.ID, i)
			nodeInfo := matrix[key]
			if nodeInfo.When == -1 {
				nodeInfo.Candidate = true
				nodeInfo.When = exec
				//fmt.Println("\tmarcando ", key, " candidato ")
			}
		}
		for _, node := range n.Lower {
			pNodes.MarkCandidate(node, metslo, exec, cWKL)
		}
	}
}

func (pNodes *NodesInfo) MarkReject(n *Node, metslo bool, exec int, cWKL int) {
	if n != nil {
		iNodes := *pNodes
		matrix := iNodes.matrix
		for i := cWKL; i < pNodes.lenWKL; i++ {
			key := getMatrixKey(n.ID, i)
			nodeInfo := matrix[key]
			if nodeInfo.When == -1 {
				nodeInfo.Reject = true
				nodeInfo.When = exec
				//fmt.Println("\tmarcando ", key, " rejeitado ")
			}
		}
		for _, node := range n.Higher {
			pNodes.MarkReject(node, metslo, exec, cWKL)
		}
	}
}

func (pNodes *NodesInfo) Mark(key string, metslo bool, exec int) {
	_, cWKL := splitMatrixKey(key)
	//fmt.Printf("INI MARK\n")
	//fmt.Printf("%v ? %v\n", key, metslo)
	iNodes := *pNodes
	matrix := iNodes.matrix

	matrix[key].When = exec
	matrix[key].Exec = true

	if metslo {
		matrix[key].Candidate = true
		pNodes.MarkCandidate(&matrix[key].Node, metslo, exec, cWKL)
	} else {
		matrix[key].Reject = true
		pNodes.MarkReject(&matrix[key].Node, metslo, exec, cWKL)
	}
	//fmt.Printf("FIM MARK\n")
}

func (matrix NodesInfo) Clone() (clone *NodesInfo) {
	mapa := make(map[string]*NodeInfo)
	for key, node := range matrix.matrix {
		n := new(NodeInfo)
		n.Node = node.Node
		n.WKL = node.WKL
		n.Exec = node.Exec
		n.Reject = node.Reject
		n.Candidate = node.Candidate
		n.When = node.When

		mapa[key] = n
	}
	pClone := new(NodesInfo)
	pClone.matrix = mapa
	pClone.lenWKL = matrix.lenWKL
	pClone.lenNodes = matrix.lenNodes
	return pClone
}

func (node NodeInfo) String() (str string) {
	return fmt.Sprintf("{when:%v, exec:%v, candidate:%v, reject:%v}", node.When, node.Exec, node.Candidate, node.Reject)
}

func (nodes NodesInfo) String() (str string) {
	str = fmt.Sprintf("{wkl:%v, heigh:%v, nodes:[\n\t", nodes.lenWKL, nodes.lenNodes)
	for key, n := range nodes.matrix {
		str = fmt.Sprintf("%v[%v]%v\n\t", str, key, n)
	}
	str = fmt.Sprintf("%v]}", str)
	return
}
<|endoftext|>


<commit_before>/* This file is part of VoltDB.
 * Copyright (C) 2008-2018 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

package voltdbclient

import (
	"database/sql/driver"
	"errors"
	"fmt"
	"time"
)

var errTimeoutExecutingQuery = errors.New("voltdbclient: Timed out executing query")

// Exec executes a query that doesn't return rows, such as an INSERT or UPDATE.
// Exec is available on both VoltConn and on VoltStatement.
// Uses DefaultQueryTimeout.
func (c *Conn) Exec(query string, args []driver.Value) (driver.Result, error) {
	return c.ExecTimeout(query, args, DefaultQueryTimeout)
}

// ExecTimeout executes a query that doesn't return rows, such as an INSERT or
// UPDATE. ExecTimeout is available on both VoltConn and on VoltStatement.
// Specifies a duration for timeout.
func (c *Conn) ExecTimeout(query string, args []driver.Value, timeout time.Duration) (driver.Result, error) {
	// Works similar to QueryTimeout but send exec queries instead.
	responseCh := make(chan voltResponse, 1)
	pi := newSyncProcedureInvocation(c.getNextHandle(), false, query, args, responseCh, timeout)
	_, err := c.submit(pi)
	if err != nil {
		return nil, err
	}
	tm := time.NewTimer(pi.timeout)
	defer tm.Stop()
	sec := time.NewTicker(time.Second)
	defer sec.Stop()
	for {
		if pi.conn.isClosed() {
			return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1},
				error: fmt.Errorf("%s: writing on a closed node connection",
					pi.conn.connInfo)}
		}
		select {
		case <-sec.C:
			if err := pi.conn.Ping(); err != nil {
				pi.conn.markClosed()
				return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout,
					clusterRoundTripTime: -1}, error: err}
			}
		case resp := <-pi.responseCh:
			switch resp.(type) {
			case VoltResult:
				return resp.(VoltResult), nil
			case VoltError:
				return nil, resp.(VoltError)
			default:
				panic("unexpected response type")
			}
		case <-tm.C:
			return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1}, error: errors.New("timeout")}
		}
	}
}

// ExecAsync is analogous to Exec but is run asynchronously.  That is, an
// invocation of this method blocks only until a request is sent to the VoltDB
// server.  Uses DefaultQueryTimeout.
func (c *Conn) ExecAsync(resCons AsyncResponseConsumer, query string, args []driver.Value) {
	c.ExecAsyncTimeout(resCons, query, args, DefaultQueryTimeout)
}

// ExecAsyncTimeout is analogous to Exec but is run asynchronously.  That is, an
// invocation of this method blocks only until a request is sent to the VoltDB
// server.  Specifies a duration for timeout.
func (c *Conn) ExecAsyncTimeout(resCons AsyncResponseConsumer, query string, args []driver.Value, timeout time.Duration) error {
	pi := newAsyncProcedureInvocation(c.getNextHandle(), false, query, args, timeout, resCons)
	_, err := c.submit(pi)
	return err
}

// Prepare creates a prepared statement for later queries or executions.
// The Statement returned by Prepare is bound to this VoltConn.
func (c *Conn) Prepare(query string) (driver.Stmt, error) {
	stmt := newVoltStatement(c, query)
	return *stmt, nil
}

// Query executes a query that returns rows, typically a SELECT. The args are
// for any placeholder parameters in the query.
// Uses DefaultQueryTimeout.
func (c *Conn) Query(query string, args []driver.Value) (driver.Rows, error) {
	return c.QueryTimeout(query, args, DefaultQueryTimeout)
}

// QueryTimeout executes a query that returns rows, typically a SELECT. The args
// are for any placeholder parameters in the query.
// Specifies a duration for timeout.
func (c *Conn) QueryTimeout(query string, args []driver.Value, timeout time.Duration) (driver.Rows, error) {
	// This is sync sql query to voltdb. In reality there is no sync implementation
	// of querying voltdb in this client.
	//
	// What happens here is, we invoke the procedure invocation and wait until we
	// receive a response on the procedureInvocation channel.
	// The call to c.submit ensures that the procedure invocation request did hit a
	// voltdb host.
	//
	// To account for the case the current connection that is serving the procedure
	// invocation is lost. We send ping request every 1 second.If we detect the
	// connection is down, we mark the connection as closed so that it will no
	// longer be used(NOTE: This is useful in cluster mode).
	responseCh := make(chan voltResponse, 1)
	pi := newSyncProcedureInvocation(c.getNextHandle(), true, query, args, responseCh, timeout)
	_, err := c.submit(pi)
	if err != nil {
		return nil, err
	}
	tm := time.NewTimer(pi.timeout)
	defer tm.Stop()
	sec := time.NewTicker(time.Second)
	defer sec.Stop()
	for {
		if pi.conn.isClosed() {
			return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1},
				error: fmt.Errorf("%s: writing on a closed node connection",
					pi.conn.connInfo)}
		}
		select {
		case <-sec.C:
			if err := pi.conn.Ping(); err != nil {
				pi.conn.markClosed()
				return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1},
					error: err}
			}
		case resp := <-pi.responseCh:
			switch e := resp.(type) {
			case VoltRows:
				return e, nil
			case VoltError:
				return nil, e
			default:
				panic("unexpected response type")
			}
		case <-tm.C:
			return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1}, error: errTimeoutExecutingQuery}
		}
	}

}

// QueryAsync executes a query asynchronously.  The invoking thread will block
// until the query is sent over the network to the server.  The eventual
// response will be handled by the given AsyncResponseConsumer, this processing
// happens in the 'response' thread.  Uses DefaultQueryTimeout.
func (c *Conn) QueryAsync(rowsCons AsyncResponseConsumer, query string, args []driver.Value) {
	c.QueryAsyncTimeout(rowsCons, query, args, DefaultQueryTimeout)
}

// QueryAsyncTimeout executes a query asynchronously.  The invoking thread will
// block until the query is sent over the network to the server.  The eventual
// response will be handled by the given AsyncResponseConsumer, this processing
// happens in the 'response' thread.  Specifies a duration for timeout.
func (c *Conn) QueryAsyncTimeout(rowsCons AsyncResponseConsumer, query string, args []driver.Value, timeout time.Duration) error {
	pi := newAsyncProcedureInvocation(c.getNextHandle(), true, query, args, timeout, rowsCons)
	_, err := c.submit(pi)
	return err
}
<commit_msg>fix typo<commit_after>/* This file is part of VoltDB.
 * Copyright (C) 2008-2018 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

package voltdbclient

import (
	"database/sql/driver"
	"errors"
	"fmt"
	"time"
)

var errTimeoutExecutingQuery = errors.New("voltdbclient: Timed out executing query")

// Exec executes a query that doesn't return rows, such as an INSERT or UPDATE.
// Exec is available on both VoltConn and on VoltStatement.
// Uses DefaultQueryTimeout.
func (c *Conn) Exec(query string, args []driver.Value) (driver.Result, error) {
	return c.ExecTimeout(query, args, DefaultQueryTimeout)
}

// ExecTimeout executes a query that doesn't return rows, such as an INSERT or
// UPDATE. ExecTimeout is available on both VoltConn and on VoltStatement.
// Specifies a duration for timeout.
func (c *Conn) ExecTimeout(query string, args []driver.Value, timeout time.Duration) (driver.Result, error) {
	// Works similar to QueryTimeout but send exec queries instead.
	responseCh := make(chan voltResponse, 1)
	pi := newSyncProcedureInvocation(c.getNextHandle(), false, query, args, responseCh, timeout)
	_, err := c.submit(pi)
	if err != nil {
		return nil, err
	}
	tm := time.NewTimer(pi.timeout)
	defer tm.Stop()
	sec := time.NewTicker(time.Second)
	defer sec.Stop()
	for {
		if pi.conn.isClosed() {
			return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1},
				error: fmt.Errorf("%s: writing on a closed node connection",
					pi.conn.connInfo)}
		}
		select {
		case <-sec.C:
			if err := pi.conn.Ping(); err != nil {
				pi.conn.markClosed()
				return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout,
					clusterRoundTripTime: -1}, error: err}
			}
		case resp := <-pi.responseCh:
			switch resp.(type) {
			case VoltResult:
				return resp.(VoltResult), nil
			case VoltError:
				return nil, resp.(VoltError)
			default:
				panic("unexpected response type")
			}
		case <-tm.C:
			return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1}, error: errors.New("timeout")}
		}
	}
}

// ExecAsync is analogous to Exec but is run asynchronously.  That is, an
// invocation of this method blocks only until a request is sent to the VoltDB
// server.  Uses DefaultQueryTimeout.
func (c *Conn) ExecAsync(resCons AsyncResponseConsumer, query string, args []driver.Value) {
	c.ExecAsyncTimeout(resCons, query, args, DefaultQueryTimeout)
}

// ExecAsyncTimeout is analogous to Exec but is run asynchronously.  That is, an
// invocation of this method blocks only until a request is sent to the VoltDB
// server.  Specifies a duration for timeout.
func (c *Conn) ExecAsyncTimeout(resCons AsyncResponseConsumer, query string, args []driver.Value, timeout time.Duration) error {
	pi := newAsyncProcedureInvocation(c.getNextHandle(), false, query, args, timeout, resCons)
	_, err := c.submit(pi)
	return err
}

// Prepare creates a prepared statement for later queries or executions.
// The Statement returned by Prepare is bound to this VoltConn.
func (c *Conn) Prepare(query string) (driver.Stmt, error) {
	stmt := newVoltStatement(c, query)
	return *stmt, nil
}

// Query executes a query that returns rows, typically a SELECT. The args are
// for any placeholder parameters in the query.
// Uses DefaultQueryTimeout.
func (c *Conn) Query(query string, args []driver.Value) (driver.Rows, error) {
	return c.QueryTimeout(query, args, DefaultQueryTimeout)
}

// QueryTimeout executes a query that returns rows, typically a SELECT. The args
// are for any placeholder parameters in the query.
// Specifies a duration for timeout.
func (c *Conn) QueryTimeout(query string, args []driver.Value, timeout time.Duration) (driver.Rows, error) {
	// This is sync sql query to voltdb. In reality there is no sync implementation
	// of querying voltdb in this client.
	//
	// What happens here is, we invoke the procedure invocation and wait until we
	// receive a response on the responseCh channel.
	// The call to c.submit ensures that the procedure invocation request did hit a
	// voltdb host.
	//
	// To account for the case the current connection that is serving the procedure
	// invocation is lost. We send ping request every 1 second.If we detect the
	// connection is down, we mark the connection as closed so that it will no
	// longer be used(NOTE: This is useful in cluster mode).
	responseCh := make(chan voltResponse, 1)
	pi := newSyncProcedureInvocation(c.getNextHandle(), true, query, args, responseCh, timeout)
	_, err := c.submit(pi)
	if err != nil {
		return nil, err
	}
	tm := time.NewTimer(pi.timeout)
	defer tm.Stop()
	sec := time.NewTicker(time.Second)
	defer sec.Stop()
	for {
		if pi.conn.isClosed() {
			return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1},
				error: fmt.Errorf("%s: writing on a closed node connection",
					pi.conn.connInfo)}
		}
		select {
		case <-sec.C:
			if err := pi.conn.Ping(); err != nil {
				pi.conn.markClosed()
				return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1},
					error: err}
			}
		case resp := <-pi.responseCh:
			switch e := resp.(type) {
			case VoltRows:
				return e, nil
			case VoltError:
				return nil, e
			default:
				panic("unexpected response type")
			}
		case <-tm.C:
			return nil, VoltError{voltResponse: voltResponseInfo{status: ConnectionTimeout, clusterRoundTripTime: -1}, error: errTimeoutExecutingQuery}
		}
	}

}

// QueryAsync executes a query asynchronously.  The invoking thread will block
// until the query is sent over the network to the server.  The eventual
// response will be handled by the given AsyncResponseConsumer, this processing
// happens in the 'response' thread.  Uses DefaultQueryTimeout.
func (c *Conn) QueryAsync(rowsCons AsyncResponseConsumer, query string, args []driver.Value) {
	c.QueryAsyncTimeout(rowsCons, query, args, DefaultQueryTimeout)
}

// QueryAsyncTimeout executes a query asynchronously.  The invoking thread will
// block until the query is sent over the network to the server.  The eventual
// response will be handled by the given AsyncResponseConsumer, this processing
// happens in the 'response' thread.  Specifies a duration for timeout.
func (c *Conn) QueryAsyncTimeout(rowsCons AsyncResponseConsumer, query string, args []driver.Value, timeout time.Duration) error {
	pi := newAsyncProcedureInvocation(c.getNextHandle(), true, query, args, timeout, rowsCons)
	_, err := c.submit(pi)
	return err
}
<|endoftext|>


<commit_before>package vfs

import (
	"fmt"
	"os"
	"path"
	"strings"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/volume"
	"github.com/pborman/uuid"
	"github.com/portworx/kvdb"
)

const (
	Name       = "vfs"
	Type       = api.DriverType_DRIVER_TYPE_FILE
	volumeBase = "/var/lib/osd/"
)

type driver struct {
	*volume.IoNotSupported
	*volume.DefaultBlockDriver
	*volume.DefaultEnumerator
	*volume.SnapshotNotSupported
}

// Init Driver intialization.
func Init(params volume.DriverParams) (volume.VolumeDriver, error) {
	return &driver{
		IoNotSupported:    &volume.IoNotSupported{},
		DefaultEnumerator: volume.NewDefaultEnumerator(Name, kvdb.Instance()),
	}, nil
}

func (d *driver) String() string {
	return Name
}

func (d *driver) Type() api.DriverType {
	return Type
}

func (d *driver) Create(locator api.VolumeLocator, source *api.Source, spec *api.VolumeSpec) (api.VolumeID, error) {

	volumeID := uuid.New()
	volumeID = strings.TrimSuffix(volumeID, "\n")

	// Create a directory on the Local machine with this UUID.
	err := os.MkdirAll(path.Join(volumeBase, string(volumeID)), 0744)
	if err != nil {
		logrus.Println(err)
		return api.BadVolumeID, err
	}

	v := &api.Volume{
		ID:         api.VolumeID(volumeID),
		Locator:    locator,
		Ctime:      time.Now(),
		Spec:       spec,
		LastScan:   time.Now(),
		Format:     "vfs",
		State:      api.VolumeAvailable,
		Status:     api.Up,
		DevicePath: path.Join(volumeBase, string(volumeID)),
	}

	err = d.CreateVol(v)
	if err != nil {
		return api.BadVolumeID, err
	}

	err = d.UpdateVol(v)
	return v.ID, err

}

func (d *driver) Delete(volumeID api.VolumeID) error {

	// Check if volume exists
	_, err := d.GetVol(volumeID)
	if err != nil {
		logrus.Println("Volume not found ", err)
		return err
	}

	// Delete the directory
	os.RemoveAll(path.Join(volumeBase, string(volumeID)))

	err = d.DeleteVol(volumeID)
	if err != nil {
		logrus.Println(err)
		return err
	}

	return nil

}

// Mount volume at specified path
// Errors ErrEnoEnt, ErrVolDetached may be returned.
func (d *driver) Mount(volumeID api.VolumeID, mountpath string) error {

	v, err := d.GetVol(volumeID)
	if err != nil {
		logrus.Println(err)
		return err
	}
	syscall.Unmount(mountpath, 0)
	err = syscall.Mount(path.Join(volumeBase, string(volumeID)), mountpath, string(v.Spec.Format), syscall.MS_BIND, "")
	if err != nil {
		logrus.Printf("Cannot mount %s at %s because %+v",
			path.Join(volumeBase, string(volumeID)), mountpath, err)
		return err
	}

	v.AttachPath = mountpath
	err = d.UpdateVol(v)

	return nil
}

// Unmount volume at specified path
// Errors ErrEnoEnt, ErrVolDetached may be returned.
func (d *driver) Unmount(volumeID api.VolumeID, mountpath string) error {
	v, err := d.GetVol(volumeID)
	if err != nil {
		return err
	}
	if v.AttachPath == "" {
		return fmt.Errorf("Device %v not mounted", volumeID)
	}
	err = syscall.Unmount(v.AttachPath, 0)
	if err != nil {
		return err
	}

	v.AttachPath = ""
	err = d.UpdateVol(v)
	return nil
}

// Set update volume with specified parameters.
func (d *driver) Set(volumeID api.VolumeID, locator *api.VolumeLocator, spec *api.VolumeSpec) error {
	if spec != nil {
		return volume.ErrNotSupported
	}
	v, err := d.GetVol(volumeID)
	if err != nil {
		return err
	}
	if locator != nil {
		v.Locator = *locator
	}
	err = d.UpdateVol(v)
	return err
}

// Stats Not Supported.
func (d *driver) Stats(volumeID api.VolumeID) (api.Stats, error) {
	return api.Stats{}, volume.ErrNotSupported
}

// Alerts Not Supported.
func (d *driver) Alerts(volumeID api.VolumeID) (api.Alerts, error) {
	return api.Alerts{}, volume.ErrNotSupported
}

// Status returns a set of key-value pairs which give low
// level diagnostic status about this driver.
func (d *driver) Status() [][2]string {
	return [][2]string{}
}

// Shutdown and cleanup.
func (d *driver) Shutdown() {
	logrus.Debugf("%s Shutting down", Name)
}

func init() {
	volume.Register(Name, Init)
}
<commit_msg>volume building<commit_after>package vfs

import (
	"fmt"
	"os"
	"path"
	"strings"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/volume"
	"github.com/libopenstorage/openstorage/volume/drivers/common"
	"github.com/pborman/uuid"
	"github.com/portworx/kvdb"
)

const (
	Name       = "vfs"
	Type       = api.DriverType_DRIVER_TYPE_FILE
	volumeBase = "/var/lib/osd/"
)

func init() {
	volume.Register(Name, Init)
}

type driver struct {
	*volume.IoNotSupported
	*volume.DefaultBlockDriver
	*volume.DefaultEnumerator
	*volume.SnapshotNotSupported
}

// Init Driver intialization.
func Init(params volume.DriverParams) (volume.VolumeDriver, error) {
	return &driver{
		IoNotSupported:    &volume.IoNotSupported{},
		DefaultEnumerator: volume.NewDefaultEnumerator(Name, kvdb.Instance()),
	}, nil
}

func (d *driver) String() string {
	return Name
}

func (d *driver) Type() api.DriverType {
	return Type
}

func (d *driver) Create(locator *api.VolumeLocator, source *api.Source, spec *api.VolumeSpec) (string, error) {
	volumeID := uuid.New()
	volumeID = strings.TrimSuffix(volumeID, "\n")
	// Create a directory on the Local machine with this UUID.
	if err := os.MkdirAll(path.Join(volumeBase, string(volumeID)), 0744); err != nil {
		logrus.Println(err)
		return "", err
	}

	v := common.NewVolume(
		volumeID,
		api.FSType_FS_TYPE_VFS,
		locator,
		source,
		spec,
	)
	v.DevicePath = path.Join(volumeBase, volumeID)

	if err := d.CreateVol(v); err != nil {
		return "", err
	}
	return v.Id, d.UpdateVol(v)
}

func (d *driver) Delete(volumeID string) error {

	// Check if volume exists
	_, err := d.GetVol(volumeID)
	if err != nil {
		logrus.Println("Volume not found ", err)
		return err
	}

	// Delete the directory
	os.RemoveAll(path.Join(volumeBase, string(volumeID)))

	err = d.DeleteVol(volumeID)
	if err != nil {
		logrus.Println(err)
		return err
	}

	return nil

}

// Mount volume at specified path
// Errors ErrEnoEnt, ErrVolDetached may be returned.
func (d *driver) Mount(volumeID string, mountpath string) error {
	v, err := d.GetVol(volumeID)
	if err != nil {
		logrus.Println(err)
		return err
	}
	syscall.Unmount(mountpath, 0)
	if err := syscall.Mount(path.Join(volumeBase, string(volumeID)), mountpath, string(v.Spec.Format), syscall.MS_BIND, ""); err != nil {
		logrus.Printf("Cannot mount %s at %s because %+v", path.Join(volumeBase, string(volumeID)), mountpath, err)
		return err
	}
	v.AttachPath = mountpath
	// TODO(pedge): why ignoring error?
	err = d.UpdateVol(v)
	return nil
}

// Unmount volume at specified path
// Errors ErrEnoEnt, ErrVolDetached may be returned.
func (d *driver) Unmount(volumeID string, mountpath string) error {
	v, err := d.GetVol(volumeID)
	if err != nil {
		return err
	}
	if v.AttachPath == "" {
		return fmt.Errorf("Device %v not mounted", volumeID)
	}
	if err := syscall.Unmount(v.AttachPath, 0); err != nil {
		return err
	}
	v.AttachPath = ""
	// TODO(pedge): why ignoring error?
	err = d.UpdateVol(v)
	return nil
}

// Set update volume with specified parameters.
func (d *driver) Set(volumeID string, locator *api.VolumeLocator, spec *api.VolumeSpec) error {
	if spec != nil {
		return volume.ErrNotSupported
	}
	v, err := d.GetVol(volumeID)
	if err != nil {
		return err
	}
	if locator != nil {
		v.Locator = locator
	}
	return d.UpdateVol(v)
}

// Stats Not Supported.
func (d *driver) Stats(volumeID string) (*api.Stats, error) {
	return nil, volume.ErrNotSupported
}

// Alerts Not Supported.
func (d *driver) Alerts(volumeID string) (*api.Alerts, error) {
	return nil, volume.ErrNotSupported
}

// Status returns a set of key-value pairs which give low
// level diagnostic status about this driver.
func (d *driver) Status() [][2]string {
	return [][2]string{}
}

// Shutdown and cleanup.
func (d *driver) Shutdown() {
	logrus.Debugf("%s Shutting down", Name)
}
<|endoftext|>


<commit_before>package cartogram

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"time"
)

// Cartogram defines a set of accounts and their metadata
type Cartogram struct {
	Version    int        `json:"version"`
	Created    time.Time  `json:"created"`
	AccountSet AccountSet `json:"accounts"`
}

// Lookup finds an account in a Cartogram based on its ID
func (c Cartogram) Lookup(accountID string) (bool, Account) {
	return c.AccountSet.Lookup(accountID)
}

// Search finds accounts based on their tags
func (c Cartogram) Search(tfs TagFilterSet) AccountSet {
	return c.AccountSet.Search(tfs)
}

func (c *Cartogram) loadFromFile(filePath string) error {
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}
	return c.loadFromString(data)
}

func (c *Cartogram) loadFromString(data []byte) error {
	if err := json.Unmarshal(data, &c); err != nil {
		return err
	}
	if c.Version != specVersion {
		return fmt.Errorf("Spec version mismatch: expected %d, got %d", specVersion, c.Version)
	}
	return nil
}

func (c Cartogram) writeToFile(filePath string) error {
	data, err := c.writeToString()
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(filePath, data, 0600)
	return err
}

func (c Cartogram) writeToString() ([]byte, error) {
	buffer, err := json.MarshalIndent(c, "", "  ")
	if err != nil {
		return []byte{}, err
	}
	return buffer, nil
}
<commit_msg>add NewCartogram API<commit_after>package cartogram

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"time"
)

// Cartogram defines a set of accounts and their metadata
type Cartogram struct {
	Version    int        `json:"version"`
	Created    time.Time  `json:"created"`
	AccountSet AccountSet `json:"accounts"`
}

// NewCartogram creates a new cartogram from an account set
func NewCartogram(as AccountSet) Cartogram {
	return Cartogram{
		Version:    specVersion,
		Created:    time.Now(),
		AccountSet: as,
	}
}

// Lookup finds an account in a Cartogram based on its ID
func (c Cartogram) Lookup(accountID string) (bool, Account) {
	return c.AccountSet.Lookup(accountID)
}

// Search finds accounts based on their tags
func (c Cartogram) Search(tfs TagFilterSet) AccountSet {
	return c.AccountSet.Search(tfs)
}

func (c *Cartogram) loadFromFile(filePath string) error {
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}
	return c.loadFromString(data)
}

func (c *Cartogram) loadFromString(data []byte) error {
	if err := json.Unmarshal(data, &c); err != nil {
		return err
	}
	if c.Version != specVersion {
		return fmt.Errorf("Spec version mismatch: expected %d, got %d", specVersion, c.Version)
	}
	return nil
}

func (c Cartogram) writeToFile(filePath string) error {
	data, err := c.writeToString()
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(filePath, data, 0600)
	return err
}

func (c Cartogram) writeToString() ([]byte, error) {
	buffer, err := json.MarshalIndent(c, "", "  ")
	if err != nil {
		return []byte{}, err
	}
	return buffer, nil
}
<|endoftext|>


<commit_before>package builder_test

import (
	"fmt"
	"github.com/lann/builder"
)

// Simple math expression allowing multiple adds/subtracts and a single
// (optional) multiply.
type simpleExpr struct {
	Multiplier int
	Adds       []int
	Subtracts  []int
}

type simpleExprBuilder builder.Builder

func (b simpleExprBuilder) Multiplier(i int) simpleExprBuilder {
	return builder.Set(b, "Multiplier", i).(simpleExprBuilder)
}

func (b simpleExprBuilder) Add(i int) simpleExprBuilder {
	return builder.Append(b, "Adds", i).(simpleExprBuilder)
}

func (b simpleExprBuilder) Subtract(i int) simpleExprBuilder {
	return builder.Append(b, "Subtracts", i).(simpleExprBuilder)
}

func (b simpleExprBuilder) Equals() (total int) {
	e := builder.GetStruct(b).(simpleExpr)
	for _, i := range e.Adds { total += i }
	for _, i := range e.Subtracts { total -= i }
	if e.Multiplier != 0 { total *= e.Multiplier }
	return
}

// SimpleExprBuilder is an "empty" builder
var SimpleExprBuilder = builder.Register(
	simpleExprBuilder{}, simpleExpr{}).(simpleExprBuilder)

func Example_basic() {
	b := SimpleExprBuilder.Add(10).Subtract(3)

	// Intermediate values can be reused
	b2 := b.Multiplier(2)
	b3 := b.Multiplier(3)

	fmt.Println(b.Equals(), b2.Equals(), b3.Equals())

	// Output:
	// 7 14 21
}
<commit_msg>Add comments to example<commit_after>package builder_test

import (
	"fmt"
	"github.com/lann/builder"
)

// Simple math expression allowing multiple adds/subtracts and a single
// (optional) multiply.
type simpleExpr struct {
	Multiplier int
	Adds       []int
	Subtracts  []int
}

// Start builder definition

type simpleExprBuilder builder.Builder

func (b simpleExprBuilder) Multiplier(i int) simpleExprBuilder {
	return builder.Set(b, "Multiplier", i).(simpleExprBuilder)
}

func (b simpleExprBuilder) Add(i int) simpleExprBuilder {
	return builder.Append(b, "Adds", i).(simpleExprBuilder)
}

func (b simpleExprBuilder) Subtract(i int) simpleExprBuilder {
	return builder.Append(b, "Subtracts", i).(simpleExprBuilder)
}

func (b simpleExprBuilder) Equals() (total int) {
	e := builder.GetStruct(b).(simpleExpr)
	for _, i := range e.Adds { total += i }
	for _, i := range e.Subtracts { total -= i }
	if e.Multiplier != 0 { total *= e.Multiplier }
	return
}

// SimpleExprBuilder is an "empty" builder
var SimpleExprBuilder = builder.Register(
	simpleExprBuilder{}, simpleExpr{}).(simpleExprBuilder)

// End builder definition

func Example_basic() {
	b := SimpleExprBuilder.Add(10).Subtract(3)

	// Intermediate values can be reused
	b2 := b.Multiplier(2)
	b3 := b.Multiplier(3)

	fmt.Println(b.Equals(), b2.Equals(), b3.Equals())

	// Output:
	// 7 14 21
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/Kovensky/go-lastfm"
	"github.com/fluffle/goirc/client"
	"github.com/howeyc/fsnotify"
	"log"
	"os"
	"sort"
	"strings"
	"sync"
	"time"
)

var (
	requireAuth = flag.Bool("require-auth", true,
		`Requires that nicknames be authenticated for using the user-nick mapping. `+
			`Disable on networks that don't implement a NickServ, such as EFNet.`)

	saveNicks = flag.Bool("save-nicks", true, `Whether to persist the user-nick mappings.`)
	nickFile  = flag.String("nick-file", "", `JSON file where user-nick map is stored. If blank, {{server}}.nicks.json is used.`)
)

type NickMap struct {
	nickMap    map[string]string
	reverseMap map[string][]string
	beingSaved bool
	sync.Mutex
}

func NewNickMap() *NickMap {
	return &NickMap{
		nickMap:    make(map[string]string),
		reverseMap: make(map[string][]string)}
}

func loadNickMap() {
	if *saveNicks {
		path := *nickFile
		if path == "" {
			path = *server + ".nicks.json"
		}
		log.Println("Watching", path)
		decodeNickMap(path)
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Fatalln(err)
		}
		err = watcher.Watch(path)
		if err != nil {
			log.Println(err)
		}
		go func() {
			var timer <-chan time.Time
			for {
				select {
				case <-watcher.Event:
					timer = time.After(time.Second)
				case err := <-watcher.Error:
					log.Println(err)
				case <-timer:
					if !nickMap.beingSaved {
						log.Println("Nick persistence file changed, reloading...")
						decodeNickMap(path)
					}
					nickMap.beingSaved = false
					timer = nil
				}
			}
		}()
	}
}

func decodeNickMap(path string) {
	fh, err := os.Open(path)
	if err != nil {
		log.Println("Error opening nick persistence file:", err)
	} else {
		nickMap.Lock()
		j := json.NewDecoder(fh)
		err = j.Decode(nickMap)
		nickMap.Unlock()
		if err != nil {
			log.Println("Error reading nick-user map:", err)
		}
		fh.Close()
	}
}

func saveNickMap() {
	if *saveNicks {
		nickMap.beingSaved = true
		path := *nickFile
		if path == "" {
			path = *server + ".nicks.json"
		}
		fh, err := os.Create(path)
		if err != nil {
			log.Println("Error creating nick persistence file:", err)
		} else {
			b, err := json.MarshalIndent(nickMap, "", "\t")
			if err != nil {
				log.Println("Error marshaling nick-user map:", err)
			}
			_, err = fh.Write(b)
			if err != nil {
				log.Println("Error writing persistence file:", err)
			}

			fh.Close()
		}
	}
}

func addNickHandlers(irc *client.Conn) {
	if !flag.Parsed() {
		flag.Parse()
	}

	irc.AddHandler("QUIT", dropIdentifiedCache)
	irc.AddHandler("307", isIdentified)
	irc.AddHandler("330", isIdentified)
	irc.AddHandler("318", isIdentified)
}

func (m *NickMap) MarshalJSON() (j []byte, err error) {
	data := make(map[string][]string)
	for _, rm := range m.reverseMap {
		if len(m.reverseMap) > 0 {
			user := m.nickMap[strings.ToLower(rm[0])]
			data[user] = rm
		}
	}
	return json.Marshal(data)
}

func (m *NickMap) UnmarshalJSON(j []byte) (err error) {
	data := make(map[string][]string)
	err = json.Unmarshal(j, &data)
	if err != nil {
		return
	}
	nickMap.nickMap = make(map[string]string)
	nickMap.reverseMap = make(map[string][]string)
	for user, nicks := range data {
		for _, nick := range nicks {
			m.setUser(nick, user)
		}
	}
	return
}

type NickMapError string

func (err *NickMapError) Error() string {
	return string(*err)
}

func (m *NickMap) IgnoreNick(irc *client.Conn, target, nick string) (err error) {
	log.Println("Adding", nick, "to ignored list")
	identified := checkIdentified(irc, nick)
	if !identified {
		irc.Privmsg(target, fmt.Sprintf("%s: you must be identified with NickServ to use this command", nick))
		log.Println("Nick", nick, "is not identified, and identity verification is enabled")
		e := NickMapError("nick is not identified")
		return &e
	}
	m.Lock()
	m.setUser(nick, "")
	saveNickMap()
	m.Unlock()

	r := fmt.Sprintf("[%s] is now ignored by last.fm commands; use %sdeluser to be unignored", nick, *cmdPrefix)
	log.Println(r)
	irc.Privmsg(target, r)
	return nil
}

func (m *NickMap) AddNick(irc *client.Conn, target, nick, user string) (err error) {
	log.Println("Associating", nick, "with user", user)
	identified := checkIdentified(irc, nick)
	if !identified {
		irc.Privmsg(target, fmt.Sprintf("%s: you must be identified with NickServ to use this command", nick))
		log.Println("Nick", nick, "is not identified, and identity verification is enabled")
		e := NickMapError("nick is not identified")
		return &e
	}
	log.Println("Checking whether", user, "is a valid Last.fm user for associating with", nick)
	// Smallest query we can do (we're only interested in errors)
	_, err = lfm.GetUserTopArtists(user, lastfm.OneWeek, 1)
	if err != nil {
		extra := ""
		lfmerr, ok := err.(*lastfm.LastFMError)
		// lfmerr.Code is unreliable; a lot of things may be code 6...
		if ok && lfmerr.Error() == "No user with that name" {
			// plus their error messages are misleading...
			extra = ", or user never scrobbled anything"
		}

		r := fmt.Sprintf("[%s] %v%s", nick, err, extra)
		log.Println(r)
		irc.Privmsg(target, r)
		return err
	}
	m.Lock()
	m.setUser(nick, user)
	saveNickMap()
	m.Unlock()

	r := fmt.Sprintf("[%s] is now associated with last.fm user %s", nick, user)
	log.Println(r)
	irc.Privmsg(target, r)
	return nil
}

func (m *NickMap) DelNick(irc *client.Conn, target, nick string) (err error) {
	if user, ok := m.GetUser(nick); !ok {
		log.Println("Nick", nick, "asked for dissociation but isn't associated")
		irc.Privmsg(target, fmt.Sprintf("%s: you're not associated with an username", nick))
		e := NickMapError("nick isn't associated")
		return &e
	} else {
		log.Println("Dissociating", nick, "with user", user)
		identified := checkIdentified(irc, nick)
		if !identified {
			irc.Privmsg(target, fmt.Sprintf("%s: you must be identified with NickServ to use this command", nick))
			log.Println("Nick", nick, "is not identified, and identity verification is enabled")
			e := NickMapError("nick is not identified")
			return &e
		}
		m.Lock()
		m.delUser(nick)
		m.Unlock()
		r := fmt.Sprintf("[%s] is no longer associated with last.fm user %s", nick, user)
		log.Println(r)
		irc.Privmsg(target, r)
		return nil
	}
	panic("unreachable")
}

func (m *NickMap) QueryNick(irc *client.Conn, target, asker, nick string) {
	r := ""
	if user, ok := m.GetUser(nick); ok {
		if asker == nick {
			if user == "" {
				r = fmt.Sprintf("%s: you asked to be ignored by last.fm commands", asker)
			} else {
				r = fmt.Sprintf("%s: your ", asker)
			}
		} else {
			if user == "" {
				r = fmt.Sprintf("%s: %s has asked to be ignored by last.fm commands", asker, nick)
			} else {
				r = fmt.Sprintf("%s: %s's ", asker, nick)
			}
		}
		if user != "" {
			r += fmt.Sprintf("last.fm username is %s (http://last.fm/user/%s)", user, user)
		}
	} else {
		if asker == nick {
			r = fmt.Sprintf("%s: you ", asker)
		} else {
			r = fmt.Sprintf("%s: %s ", asker, nick)
		}
		r += fmt.Sprintf("didn't associate an username")
	}
	irc.Privmsg(target, r)
	return
}

func (m *NickMap) ListAllNicks(irc *client.Conn, target, asker, user string) {
	if user == "" {
		return
	}
	log.Println("Listing all nicks for user", user)
	r := ""
	if nicks, ok := m.reverseMap[strings.ToLower(user)]; !ok || len(nicks) == 0 {
		r = fmt.Sprintf("%s: %s has no associated IRC nick", asker, user)
	} else {
		plural := "s are"
		if len(nicks) == 1 {
			plural = " is"
		}
		r = fmt.Sprintf("%s: %s's known IRC nick%s %s",
			asker, user, plural, strings.Join(sort.StringSlice(nicks), ", "))
	}
	log.Println(r)
	irc.Privmsg(target, r)
	return
}

func (m *NickMap) GetUser(nick string) (user string, ok bool) {
	m.Lock()
	defer m.Unlock()
	user, ok = m.nickMap[strings.ToLower(nick)]
	if ok {
		if user == "" {
			log.Println("Nick", nick, "requested to be ignored")
			return user, ok
		}
		log.Println("Nick", nick, "is associated with", user)
		return user, ok
	}
	return nick, ok
}

func (m *NickMap) setUser(nick, user string) {
	if _, ok := m.nickMap[strings.ToLower(nick)]; ok {
		m.delUser(nick)
	}
	m.nickMap[strings.ToLower(nick)] = user
	lcuser := strings.ToLower(user)
	if rm, ok := m.reverseMap[lcuser]; !ok {
		m.reverseMap[lcuser] = []string{nick}
	} else {
		m.reverseMap[lcuser] = append(rm, nick)
	}
	return
}

func (m *NickMap) delUser(nick string) {
	lcuser := ""
	if user, ok := m.nickMap[strings.ToLower(nick)]; ok {
		lcuser = strings.ToLower(user)
	}
	delete(m.nickMap, strings.ToLower(nick))

	if rm, ok := m.reverseMap[lcuser]; ok {
		newRm := []string{}
		for _, n := range rm {
			if n != nick {
				newRm = append(newRm, n)
			}
		}
		m.reverseMap[lcuser] = newRm
	}
}

var (
	isIdentifiedChan  = make(map[string]chan bool)
	isIdentifiedCache = make(map[string]bool)
)

func resetIdentifiedCache() {
	isIdentifiedCache = make(map[string]bool)
	// We also reset the channels, in case there's any verification pending
	for _, c := range isIdentifiedChan {
		close(c)
	}
	isIdentifiedChan = make(map[string]chan bool)
	return
}

func dropIdentifiedCache(irc *client.Conn, line *client.Line) {
	delete(isIdentifiedCache, line.Nick)
	return
}

func checkIdentified(irc *client.Conn, nick string) bool {
	if !*requireAuth {
		return true
	}
	// We don't cache identification failures since the user can always identify later
	if isIdentifiedCache[nick] {
		return true
	}

	log.Println("Checking whether", nick, "is identified")

	isIdentifiedChan[nick] = make(chan bool, 1)
	timeout := time.After(10 * time.Second)
	go irc.Whois(nick)

	r := false
	for is, ok := false, true; ok; {
		select {
		case is, ok = <-isIdentifiedChan[nick]:
			if is {
				r = true
			}
		case <-timeout:
			log.Println("Timeout checking for whether", nick, "is identified")
			return false
		}
	}
	delete(isIdentifiedChan, nick)

	log.Println("Is nick", nick, "identified:", r)
	if r {
		isIdentifiedCache[nick] = true
	}

	return r
}

func isIdentified(irc *client.Conn, line *client.Line) {
	nick := line.Args[1]
	switch line.Cmd {
	case "307", "330": // identified; 330 is the freenode version
		isIdentifiedChan[nick] <- true
	case "318": // end of response
		close(isIdentifiedChan[nick])
	}
	return
}
<commit_msg>Fix data race in isIdentified<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/Kovensky/go-lastfm"
	"github.com/fluffle/goirc/client"
	"github.com/howeyc/fsnotify"
	"log"
	"os"
	"sort"
	"strings"
	"sync"
	"time"
)

var (
	requireAuth = flag.Bool("require-auth", true,
		`Requires that nicknames be authenticated for using the user-nick mapping. `+
			`Disable on networks that don't implement a NickServ, such as EFNet.`)

	saveNicks = flag.Bool("save-nicks", true, `Whether to persist the user-nick mappings.`)
	nickFile  = flag.String("nick-file", "", `JSON file where user-nick map is stored. If blank, {{server}}.nicks.json is used.`)
)

type NickMap struct {
	nickMap    map[string]string
	reverseMap map[string][]string
	beingSaved bool
	sync.Mutex
}

func NewNickMap() *NickMap {
	return &NickMap{
		nickMap:    make(map[string]string),
		reverseMap: make(map[string][]string)}
}

func loadNickMap() {
	if *saveNicks {
		path := *nickFile
		if path == "" {
			path = *server + ".nicks.json"
		}
		log.Println("Watching", path)
		decodeNickMap(path)
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Fatalln(err)
		}
		err = watcher.Watch(path)
		if err != nil {
			log.Println(err)
		}
		go func() {
			var timer <-chan time.Time
			for {
				select {
				case <-watcher.Event:
					timer = time.After(time.Second)
				case err := <-watcher.Error:
					log.Println(err)
				case <-timer:
					if !nickMap.beingSaved {
						log.Println("Nick persistence file changed, reloading...")
						decodeNickMap(path)
					}
					nickMap.beingSaved = false
					timer = nil
				}
			}
		}()
	}
}

func decodeNickMap(path string) {
	fh, err := os.Open(path)
	if err != nil {
		log.Println("Error opening nick persistence file:", err)
	} else {
		nickMap.Lock()
		j := json.NewDecoder(fh)
		err = j.Decode(nickMap)
		nickMap.Unlock()
		if err != nil {
			log.Println("Error reading nick-user map:", err)
		}
		fh.Close()
	}
}

func saveNickMap() {
	if *saveNicks {
		nickMap.beingSaved = true
		path := *nickFile
		if path == "" {
			path = *server + ".nicks.json"
		}
		fh, err := os.Create(path)
		if err != nil {
			log.Println("Error creating nick persistence file:", err)
		} else {
			b, err := json.MarshalIndent(nickMap, "", "\t")
			if err != nil {
				log.Println("Error marshaling nick-user map:", err)
			}
			_, err = fh.Write(b)
			if err != nil {
				log.Println("Error writing persistence file:", err)
			}

			fh.Close()
		}
	}
}

func addNickHandlers(irc *client.Conn) {
	if !flag.Parsed() {
		flag.Parse()
	}

	irc.AddHandler("QUIT", dropIdentifiedCache)
	irc.AddHandler("307", isIdentified)
	irc.AddHandler("330", isIdentified)
	irc.AddHandler("318", isIdentified)
}

func (m *NickMap) MarshalJSON() (j []byte, err error) {
	data := make(map[string][]string)
	for _, rm := range m.reverseMap {
		if len(m.reverseMap) > 0 {
			user := m.nickMap[strings.ToLower(rm[0])]
			data[user] = rm
		}
	}
	return json.Marshal(data)
}

func (m *NickMap) UnmarshalJSON(j []byte) (err error) {
	data := make(map[string][]string)
	err = json.Unmarshal(j, &data)
	if err != nil {
		return
	}
	nickMap.nickMap = make(map[string]string)
	nickMap.reverseMap = make(map[string][]string)
	for user, nicks := range data {
		for _, nick := range nicks {
			m.setUser(nick, user)
		}
	}
	return
}

type NickMapError string

func (err *NickMapError) Error() string {
	return string(*err)
}

func (m *NickMap) IgnoreNick(irc *client.Conn, target, nick string) (err error) {
	log.Println("Adding", nick, "to ignored list")
	identified := checkIdentified(irc, nick)
	if !identified {
		irc.Privmsg(target, fmt.Sprintf("%s: you must be identified with NickServ to use this command", nick))
		log.Println("Nick", nick, "is not identified, and identity verification is enabled")
		e := NickMapError("nick is not identified")
		return &e
	}
	m.Lock()
	m.setUser(nick, "")
	saveNickMap()
	m.Unlock()

	r := fmt.Sprintf("[%s] is now ignored by last.fm commands; use %sdeluser to be unignored", nick, *cmdPrefix)
	log.Println(r)
	irc.Privmsg(target, r)
	return nil
}

func (m *NickMap) AddNick(irc *client.Conn, target, nick, user string) (err error) {
	log.Println("Associating", nick, "with user", user)
	identified := checkIdentified(irc, nick)
	if !identified {
		irc.Privmsg(target, fmt.Sprintf("%s: you must be identified with NickServ to use this command", nick))
		log.Println("Nick", nick, "is not identified, and identity verification is enabled")
		e := NickMapError("nick is not identified")
		return &e
	}
	log.Println("Checking whether", user, "is a valid Last.fm user for associating with", nick)
	// Smallest query we can do (we're only interested in errors)
	_, err = lfm.GetUserTopArtists(user, lastfm.OneWeek, 1)
	if err != nil {
		extra := ""
		lfmerr, ok := err.(*lastfm.LastFMError)
		// lfmerr.Code is unreliable; a lot of things may be code 6...
		if ok && lfmerr.Error() == "No user with that name" {
			// plus their error messages are misleading...
			extra = ", or user never scrobbled anything"
		}

		r := fmt.Sprintf("[%s] %v%s", nick, err, extra)
		log.Println(r)
		irc.Privmsg(target, r)
		return err
	}
	m.Lock()
	m.setUser(nick, user)
	saveNickMap()
	m.Unlock()

	r := fmt.Sprintf("[%s] is now associated with last.fm user %s", nick, user)
	log.Println(r)
	irc.Privmsg(target, r)
	return nil
}

func (m *NickMap) DelNick(irc *client.Conn, target, nick string) (err error) {
	if user, ok := m.GetUser(nick); !ok {
		log.Println("Nick", nick, "asked for dissociation but isn't associated")
		irc.Privmsg(target, fmt.Sprintf("%s: you're not associated with an username", nick))
		e := NickMapError("nick isn't associated")
		return &e
	} else {
		log.Println("Dissociating", nick, "with user", user)
		identified := checkIdentified(irc, nick)
		if !identified {
			irc.Privmsg(target, fmt.Sprintf("%s: you must be identified with NickServ to use this command", nick))
			log.Println("Nick", nick, "is not identified, and identity verification is enabled")
			e := NickMapError("nick is not identified")
			return &e
		}
		m.Lock()
		m.delUser(nick)
		m.Unlock()
		r := fmt.Sprintf("[%s] is no longer associated with last.fm user %s", nick, user)
		log.Println(r)
		irc.Privmsg(target, r)
		return nil
	}
	panic("unreachable")
}

func (m *NickMap) QueryNick(irc *client.Conn, target, asker, nick string) {
	r := ""
	if user, ok := m.GetUser(nick); ok {
		if asker == nick {
			if user == "" {
				r = fmt.Sprintf("%s: you asked to be ignored by last.fm commands", asker)
			} else {
				r = fmt.Sprintf("%s: your ", asker)
			}
		} else {
			if user == "" {
				r = fmt.Sprintf("%s: %s has asked to be ignored by last.fm commands", asker, nick)
			} else {
				r = fmt.Sprintf("%s: %s's ", asker, nick)
			}
		}
		if user != "" {
			r += fmt.Sprintf("last.fm username is %s (http://last.fm/user/%s)", user, user)
		}
	} else {
		if asker == nick {
			r = fmt.Sprintf("%s: you ", asker)
		} else {
			r = fmt.Sprintf("%s: %s ", asker, nick)
		}
		r += fmt.Sprintf("didn't associate an username")
	}
	irc.Privmsg(target, r)
	return
}

func (m *NickMap) ListAllNicks(irc *client.Conn, target, asker, user string) {
	if user == "" {
		return
	}
	log.Println("Listing all nicks for user", user)
	r := ""
	if nicks, ok := m.reverseMap[strings.ToLower(user)]; !ok || len(nicks) == 0 {
		r = fmt.Sprintf("%s: %s has no associated IRC nick", asker, user)
	} else {
		plural := "s are"
		if len(nicks) == 1 {
			plural = " is"
		}
		r = fmt.Sprintf("%s: %s's known IRC nick%s %s",
			asker, user, plural, strings.Join(sort.StringSlice(nicks), ", "))
	}
	log.Println(r)
	irc.Privmsg(target, r)
	return
}

func (m *NickMap) GetUser(nick string) (user string, ok bool) {
	m.Lock()
	defer m.Unlock()
	user, ok = m.nickMap[strings.ToLower(nick)]
	if ok {
		if user == "" {
			log.Println("Nick", nick, "requested to be ignored")
			return user, ok
		}
		log.Println("Nick", nick, "is associated with", user)
		return user, ok
	}
	return nick, ok
}

func (m *NickMap) setUser(nick, user string) {
	if _, ok := m.nickMap[strings.ToLower(nick)]; ok {
		m.delUser(nick)
	}
	m.nickMap[strings.ToLower(nick)] = user
	lcuser := strings.ToLower(user)
	if rm, ok := m.reverseMap[lcuser]; !ok {
		m.reverseMap[lcuser] = []string{nick}
	} else {
		m.reverseMap[lcuser] = append(rm, nick)
	}
	return
}

func (m *NickMap) delUser(nick string) {
	lcuser := ""
	if user, ok := m.nickMap[strings.ToLower(nick)]; ok {
		lcuser = strings.ToLower(user)
	}
	delete(m.nickMap, strings.ToLower(nick))

	if rm, ok := m.reverseMap[lcuser]; ok {
		newRm := []string{}
		for _, n := range rm {
			if n != nick {
				newRm = append(newRm, n)
			}
		}
		m.reverseMap[lcuser] = newRm
	}
}

var (
	isIdentifiedChan  = make(map[string]chan bool)
	isIdentifiedCache = make(map[string]bool)
)

func resetIdentifiedCache() {
	isIdentifiedCache = make(map[string]bool)
	// We also reset the channels, in case there's any verification pending
	for _, c := range isIdentifiedChan {
		close(c)
	}
	isIdentifiedChan = make(map[string]chan bool)
	return
}

func dropIdentifiedCache(irc *client.Conn, line *client.Line) {
	delete(isIdentifiedCache, line.Nick)
	return
}

func checkIdentified(irc *client.Conn, nick string) bool {
	if !*requireAuth {
		return true
	}
	// We don't cache identification failures since the user can always identify later
	if isIdentifiedCache[nick] {
		return true
	}

	log.Println("Checking whether", nick, "is identified")

	isIdentifiedChan[nick] = make(chan bool, 1)
	timeout := time.After(10 * time.Second)
	go irc.Whois(nick)

	r := false
	for is, ok := false, true; ok; {
		select {
		case is, ok = <-isIdentifiedChan[nick]:
			if is {
				r = true
			}
		case <-timeout:
			log.Println("Timeout checking for whether", nick, "is identified")
			return false
		}
	}
	delete(isIdentifiedChan, nick)

	log.Println("Is nick", nick, "identified:", r)
	if r {
		isIdentifiedCache[nick] = true
	}

	return r
}

var isIdentifiedMutex sync.Mutex

func isIdentified(irc *client.Conn, line *client.Line) {
	nick := line.Args[1]
	isIdentifiedMutex.Lock()
	switch line.Cmd {
	case "307", "330": // identified; 330 is the freenode version
		isIdentifiedChan[nick] <- true
	case "318": // end of response
		close(isIdentifiedChan[nick])
	}
	isIdentifiedMutex.Unlock()
	return
}
<|endoftext|>