<commit_before>package tmo

import (
	"image"
	"math"

	colorful "github.com/lucasb-eyer/go-colorful"
	"github.com/mdouchement/hdr"
	"github.com/mdouchement/hdr/hdrcolor"
)

const (
	maxLum      = 20000
	iCAM06Gamma = 1
)

// A ICam06 is a TMO implementation based on
// Mark D. Fairchild, Jiangtao Kuang and Garrett M. Johnson's 2006 white paper.
//
// Reference:
// iCAM for high-dynamic-range image rendering.
// Mark D. Fairchild, Jiangtao Kuang and Garrett M. Johnson.
// In SIGGRAPH '06 ACM SIGGRAPH 2006 Research posters. Article No. 185
type ICam06 struct {
	HDRImage    hdr.Image
	Contrast    float64
	MinClipping float64
	MaxClipping float64
}

// NewICam06 instanciates a new ICam06 TMO.
func NewICam06(m hdr.Image, contrast, minClipping, maxClipping float64) *ICam06 {
	return &ICam06{
		HDRImage:    m,
		Contrast:    contrast,
		MinClipping: minClipping,
		MaxClipping: maxClipping,
	}
}

// Perform runs the TMO mapping.
func (t *ICam06) Perform() image.Image {
	imgRect := image.Rect(0, 0, t.HDRImage.Bounds().Dx(), t.HDRImage.Bounds().Dy())
	img := image.NewRGBA64(imgRect)

	tmp := hdr.NewXYZ(imgRect)
	t.normalize(tmp)
	t.bilateralFilter(tmp)

	return img
}

//================================//
// Step 1: Normalization          //
//================================//

func (t *ICam06) normalize(img *hdr.XYZ) {
	max := math.Inf(-1)
	maxCh := make(chan float64)

	// Find max luminance
	completed := parallel(t.HDRImage.Bounds().Dx(), t.HDRImage.Bounds().Dy(), func(x1, y1, x2, y2 int) {
		max := math.Inf(-1)

		for y := y1; y < y2; y++ {
			for x := x1; x < x2; x++ {
				pixel := t.HDRImage.HDRAt(x, y)
				r, g, b, _ := pixel.HDRRGBA()

				xx, yy, zz := colorful.Color{R: r, G: g, B: b}.Xyz() // Convert to CIE XYZ-space, Y is the luminance value.

				max = math.Max(max, yy)

				img.SetXYZ(x, y, hdrcolor.XYZ{X: xx, Y: yy, Z: zz}) // Provision the XYZ temporary image.
			}
		}
	})

	for {
		select {
		case <-completed:
			return
		case m := <-maxCh:
			max = math.Max(max, m)
		}
	}

	// Normalisation
	completed = parallel(t.HDRImage.Bounds().Dx(), t.HDRImage.Bounds().Dy(), func(x1, y1, x2, y2 int) {
		for y := y1; y < y2; y++ {
			for x := x1; x < x2; x++ {
				pixel := img.XYZAt(x, y)

				img.SetXYZ(x, y, hdrcolor.XYZ{
					X: icam06Normalization(pixel.X, max),
					Y: icam06Normalization(pixel.Y, max),
					Z: icam06Normalization(pixel.Z, max),
				})
			}
		}
	})

	<-completed
	return
}

//================================//
// Step 2: Bilateral filte        //
//================================//
//
// The image is splited in two layers:
// - The base layer
// - The details layer

func (t *ICam06) bilateralFilter(img *hdr.XYZ) {
}

//================================//

func icam06Normalization(channel, max float64) float64 {
	channel = maxLum * channel / max

	if channel < 0.00000001 {
		channel = 0.00000001
	}

	return channel
}

// TODO should not be efficient to use it.
func maxtab(sl []float64) float64 {
	max := math.Inf(-1)
	for _, v := range sl {
		max = math.Max(max, v)
	}
	return max
}
<commit_msg>Rebased from commit Increase TMOs speed<commit_after>package tmo

import (
	"image"
	"math"

	colorful "github.com/lucasb-eyer/go-colorful"
	"github.com/mdouchement/hdr"
	"github.com/mdouchement/hdr/hdrcolor"
)

const (
	maxLum      = 20000
	iCAM06Gamma = 1
)

// A ICam06 is a TMO implementation based on
// Mark D. Fairchild, Jiangtao Kuang and Garrett M. Johnson's 2006 white paper.
//
// Reference:
// iCAM for high-dynamic-range image rendering.
// Mark D. Fairchild, Jiangtao Kuang and Garrett M. Johnson.
// In SIGGRAPH '06 ACM SIGGRAPH 2006 Research posters. Article No. 185
type ICam06 struct {
	HDRImage    hdr.Image
	Contrast    float64
	MinClipping float64
	MaxClipping float64
}

// NewICam06 instanciates a new ICam06 TMO.
func NewICam06(m hdr.Image, contrast, minClipping, maxClipping float64) *ICam06 {
	return &ICam06{
		HDRImage:    m,
		Contrast:    contrast,
		MinClipping: minClipping,
		MaxClipping: maxClipping,
	}
}

// Perform runs the TMO mapping.
func (t *ICam06) Perform() image.Image {
	imgRect := image.Rect(0, 0, t.HDRImage.Bounds().Dx(), t.HDRImage.Bounds().Dy())
	img := image.NewRGBA64(imgRect)

	tmp := hdr.NewXYZ(imgRect)
	t.normalize(tmp)
	t.bilateralFilter(tmp)

	return img
}

//================================//
// Step 1: Normalization          //
//================================//

func (t *ICam06) normalize(img *hdr.XYZ) {
	max := math.Inf(-1)
	maxCh := make(chan float64)

	// Find max luminance
	completed := parallelR(t.HDRImage.Bounds(), func(x1, y1, x2, y2 int) {
		max := math.Inf(-1)

		for y := y1; y < y2; y++ {
			for x := x1; x < x2; x++ {
				pixel := t.HDRImage.HDRAt(x, y)
				r, g, b, _ := pixel.HDRRGBA()

				xx, yy, zz := colorful.Color{R: r, G: g, B: b}.Xyz() // Convert to CIE XYZ-space, Y is the luminance value.

				max = math.Max(max, yy)

				img.SetXYZ(x, y, hdrcolor.XYZ{X: xx, Y: yy, Z: zz}) // Provision the XYZ temporary image.
			}
		}
	})

	for {
		select {
		case <-completed:
			return
		case m := <-maxCh:
			max = math.Max(max, m)
		}
	}

	// Normalisation
	completed = parallelR(t.HDRImage.Bounds(), func(x1, y1, x2, y2 int) {
		for y := y1; y < y2; y++ {
			for x := x1; x < x2; x++ {
				pixel := img.XYZAt(x, y)

				img.SetXYZ(x, y, hdrcolor.XYZ{
					X: icam06Normalization(pixel.X, max),
					Y: icam06Normalization(pixel.Y, max),
					Z: icam06Normalization(pixel.Z, max),
				})
			}
		}
	})

	<-completed
}

//================================//
// Step 2: Bilateral filte        //
//================================//
//
// The image is splited in two layers:
// - The base layer
// - The details layer

func (t *ICam06) bilateralFilter(img *hdr.XYZ) {
}

//================================//

func icam06Normalization(channel, max float64) float64 {
	channel = maxLum * channel / max

	if channel < 0.00000001 {
		channel = 0.00000001
	}

	return channel
}

// TODO should not be efficient to use it.
func maxtab(sl []float64) float64 {
	max := math.Inf(-1)
	for _, v := range sl {
		max = math.Max(max, v)
	}
	return max
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"

	"github.com/golang/protobuf/proto"
	"github.com/pachyderm/pachyderm/src/client/pkg/grpcutil"
	uuid "github.com/satori/go.uuid"
)

const configEnvVar = "PACH_CONFIG"
const contextEnvVar = "PACH_CONTEXT"

var defaultConfigDir = filepath.Join(os.Getenv("HOME"), ".pachyderm")
var defaultConfigPath = filepath.Join(defaultConfigDir, "config.json")

var configMu sync.Mutex
var value *Config
var readErr error

func configPath() string {
	if env, ok := os.LookupEnv(configEnvVar); ok {
		return env
	}
	return defaultConfigPath
}

// ActiveContext gets the active context in the config
func (c *Config) ActiveContext() (string, *Context, error) {
	if c.V2 == nil {
		return "", nil, fmt.Errorf("cannot get active context from non-v2 config")
	}
	if envContext, ok := os.LookupEnv(contextEnvVar); ok {
		context := c.V2.Contexts[envContext]
		if context == nil {
			return "", nil, fmt.Errorf("`%s` refers to a context (%q) that does not exist", contextEnvVar, envContext)
		}
		return envContext, context, nil
	}
	context := c.V2.Contexts[c.V2.ActiveContext]
	if context == nil {
		return "", nil, fmt.Errorf("pachctl config error: pachctl's active "+
			"context is %q, but no context named %q has been configured.\n\nYou can fix "+
			"your config by setting the active context like so: pachctl config set "+
			"active-context <context>",
			c.V2.ActiveContext, c.V2.ActiveContext)
	}
	return c.V2.ActiveContext, context, nil
}

// Read loads the Pachyderm config on this machine.
// If an existing configuration cannot be found, it sets up the defaults. Read
// returns a nil Config if and only if it returns a non-nil error.
func Read() (*Config, error) {
	configMu.Lock()
	defer configMu.Unlock()

	if value == nil {
		// Read json file
		p := configPath()
		if raw, err := ioutil.ReadFile(p); err == nil {
			err = json.Unmarshal(raw, &value)
			if err != nil {
				return nil, err
			}
		} else if os.IsNotExist(err) {
			// File doesn't exist, so create a new config
			fmt.Fprintf(os.Stderr, "No config detected at %q. Generating new config...\n", p)
			value = &Config{}
		} else {
			return nil, fmt.Errorf("fatal: could not read config at %q: %v", p, err)
		}

		updated := false

		if value.UserID == "" {
			updated = true
			fmt.Fprintln(os.Stderr, "No UserID present in config - generating new one.")
			uuid := uuid.NewV4()
			value.UserID = uuid.String()
		}

		if value.V2 == nil {
			updated = true
			fmt.Fprintln(os.Stderr, "No config V2 present in config - generating a new one.")
			if err := value.initV2(); err != nil {
				return nil, err
			}
		}

		if updated {
			fmt.Fprintf(os.Stderr, "Rewriting config at %q.\n", p)

			if err := value.write(); err != nil {
				return nil, fmt.Errorf("could not rewrite config at %q: %v", p, err)
			}
		}
	}

	return proto.Clone(value).(*Config), nil
}

func (c *Config) initV2() error {
	c.V2 = &ConfigV2{
		ActiveContext: "default",
		Contexts:      map[string]*Context{},
		Metrics:       true,
	}

	pachdAddressStr := ""
	pachdAddress, err := grpcutil.ParsePachdAddress(c.V1.PachdAddress)
	if err != nil {
		if err != grpcutil.ErrNoPachdAddress {
			return err
		}
	} else {
		pachdAddressStr = pachdAddress.Qualified()
	}

	if c.V1 != nil {
		c.V2.Contexts["default"] = &Context{
			Source:            ContextSource_CONFIG_V1,
			PachdAddress:      pachdAddressStr,
			ServerCAs:         c.V1.ServerCAs,
			SessionToken:      c.V1.SessionToken,
			ActiveTransaction: c.V1.ActiveTransaction,
		}

		c.V1 = nil
	} else {
		c.V2.Contexts["default"] = &Context{
			Source: ContextSource_NONE,
		}
	}
	return nil
}

// Write writes the configuration in 'c' to this machine's Pachyderm config
// file.
func (c *Config) Write() error {
	configMu.Lock()
	defer configMu.Unlock()
	return c.write()
}

// write() is a helper for Write() that assumes the caller has already locked
// configMu. Because Go mutexes are not reentrant, this is safe to call from
// inside Read()
func (c *Config) write() error {
	if c.V1 != nil {
		panic("config V1 included (this is a bug)")
	}

	rawConfig, err := json.MarshalIndent(c, "", "  ")
	if err != nil {
		return err
	}

	p := configPath()
	// Because we're writing the config back to disk, we'll also need to make sure
	// that the directory we're writing the config into exists. The approach we
	// use for doing this depends on whether PACH_CONFIG is set.
	if _, ok := os.LookupEnv(configEnvVar); ok {
		// using overridden config path: check that the parent dir exists, but don't
		// create any new directories
		d := filepath.Dir(p)
		if _, err := os.Stat(d); err != nil {
			return fmt.Errorf("cannot use config at %s: could not stat parent directory (%v)", p, err)
		}
	} else {
		// using the default config path, create the config directory
		err = os.MkdirAll(defaultConfigDir, 0755)
		if err != nil {
			return err
		}
	}
	err = ioutil.WriteFile(p, rawConfig, 0644)
	if err == nil {
		// essentially short-cuts reading the new config back from disk
		value = proto.Clone(c).(*Config)
	}
	return err
}
<commit_msg>Fixed bug<commit_after>package config

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"

	"github.com/golang/protobuf/proto"
	"github.com/pachyderm/pachyderm/src/client/pkg/grpcutil"
	uuid "github.com/satori/go.uuid"
)

const configEnvVar = "PACH_CONFIG"
const contextEnvVar = "PACH_CONTEXT"

var defaultConfigDir = filepath.Join(os.Getenv("HOME"), ".pachyderm")
var defaultConfigPath = filepath.Join(defaultConfigDir, "config.json")

var configMu sync.Mutex
var value *Config
var readErr error

func configPath() string {
	if env, ok := os.LookupEnv(configEnvVar); ok {
		return env
	}
	return defaultConfigPath
}

// ActiveContext gets the active context in the config
func (c *Config) ActiveContext() (string, *Context, error) {
	if c.V2 == nil {
		return "", nil, fmt.Errorf("cannot get active context from non-v2 config")
	}
	if envContext, ok := os.LookupEnv(contextEnvVar); ok {
		context := c.V2.Contexts[envContext]
		if context == nil {
			return "", nil, fmt.Errorf("`%s` refers to a context (%q) that does not exist", contextEnvVar, envContext)
		}
		return envContext, context, nil
	}
	context := c.V2.Contexts[c.V2.ActiveContext]
	if context == nil {
		return "", nil, fmt.Errorf("pachctl config error: pachctl's active "+
			"context is %q, but no context named %q has been configured.\n\nYou can fix "+
			"your config by setting the active context like so: pachctl config set "+
			"active-context <context>",
			c.V2.ActiveContext, c.V2.ActiveContext)
	}
	return c.V2.ActiveContext, context, nil
}

// Read loads the Pachyderm config on this machine.
// If an existing configuration cannot be found, it sets up the defaults. Read
// returns a nil Config if and only if it returns a non-nil error.
func Read() (*Config, error) {
	configMu.Lock()
	defer configMu.Unlock()

	if value == nil {
		// Read json file
		p := configPath()
		if raw, err := ioutil.ReadFile(p); err == nil {
			err = json.Unmarshal(raw, &value)
			if err != nil {
				return nil, err
			}
		} else if os.IsNotExist(err) {
			// File doesn't exist, so create a new config
			fmt.Fprintf(os.Stderr, "No config detected at %q. Generating new config...\n", p)
			value = &Config{}
		} else {
			return nil, fmt.Errorf("fatal: could not read config at %q: %v", p, err)
		}

		updated := false

		if value.UserID == "" {
			updated = true
			fmt.Fprintln(os.Stderr, "No UserID present in config - generating new one.")
			uuid := uuid.NewV4()
			value.UserID = uuid.String()
		}

		if value.V2 == nil {
			updated = true
			fmt.Fprintln(os.Stderr, "No config V2 present in config - generating a new one.")
			if err := value.initV2(); err != nil {
				return nil, err
			}
		}

		if updated {
			fmt.Fprintf(os.Stderr, "Rewriting config at %q.\n", p)

			if err := value.write(); err != nil {
				return nil, fmt.Errorf("could not rewrite config at %q: %v", p, err)
			}
		}
	}

	return proto.Clone(value).(*Config), nil
}

func (c *Config) initV2() error {
	c.V2 = &ConfigV2{
		ActiveContext: "default",
		Contexts:      map[string]*Context{},
		Metrics:       true,
	}

	if c.V1 != nil {
		pachdAddressStr := ""
		pachdAddress, err := grpcutil.ParsePachdAddress(c.V1.PachdAddress)
		if err != nil {
			if err != grpcutil.ErrNoPachdAddress {
				return err
			}
		} else {
			pachdAddressStr = pachdAddress.Qualified()
		}

		c.V2.Contexts["default"] = &Context{
			Source:            ContextSource_CONFIG_V1,
			PachdAddress:      pachdAddressStr,
			ServerCAs:         c.V1.ServerCAs,
			SessionToken:      c.V1.SessionToken,
			ActiveTransaction: c.V1.ActiveTransaction,
		}

		c.V1 = nil
	} else {
		c.V2.Contexts["default"] = &Context{
			Source: ContextSource_NONE,
		}
	}
	return nil
}

// Write writes the configuration in 'c' to this machine's Pachyderm config
// file.
func (c *Config) Write() error {
	configMu.Lock()
	defer configMu.Unlock()
	return c.write()
}

// write() is a helper for Write() that assumes the caller has already locked
// configMu. Because Go mutexes are not reentrant, this is safe to call from
// inside Read()
func (c *Config) write() error {
	if c.V1 != nil {
		panic("config V1 included (this is a bug)")
	}

	rawConfig, err := json.MarshalIndent(c, "", "  ")
	if err != nil {
		return err
	}

	p := configPath()
	// Because we're writing the config back to disk, we'll also need to make sure
	// that the directory we're writing the config into exists. The approach we
	// use for doing this depends on whether PACH_CONFIG is set.
	if _, ok := os.LookupEnv(configEnvVar); ok {
		// using overridden config path: check that the parent dir exists, but don't
		// create any new directories
		d := filepath.Dir(p)
		if _, err := os.Stat(d); err != nil {
			return fmt.Errorf("cannot use config at %s: could not stat parent directory (%v)", p, err)
		}
	} else {
		// using the default config path, create the config directory
		err = os.MkdirAll(defaultConfigDir, 0755)
		if err != nil {
			return err
		}
	}
	err = ioutil.WriteFile(p, rawConfig, 0644)
	if err == nil {
		// essentially short-cuts reading the new config back from disk
		value = proto.Clone(c).(*Config)
	}
	return err
}
<|endoftext|>


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

// App Engine godoc Playground functionality.

// +build appengine

package main

import (
	"io"
	"net/http"

	"appengine"
	"appengine/urlfetch"
)

func bounceToPlayground(w http.ResponseWriter, req *http.Request) {
	c := appengine.NewContext(req)
	client := urlfetch.Client(c)
	url := playgroundBaseURL + req.URL.Path
	defer req.Body.Close()
	resp, err := client.Post(url, req.Header.Get("Content-type"), req.Body)
	if err != nil {
		http.Error(w, "Internal Server Error", 500)
		c.Errorf("making POST request:", err)
		return
	}
	defer resp.Body.Close()
	if _, err := io.Copy(w, resp.Body); err != nil {
		http.Error(w, "Internal Server Error", 500)
		c.Errorf("making POST request:", err)
	}
}
<commit_msg>cmd/godoc: fix format strings.<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// App Engine godoc Playground functionality.

// +build appengine

package main

import (
	"io"
	"net/http"

	"appengine"
	"appengine/urlfetch"
)

func bounceToPlayground(w http.ResponseWriter, req *http.Request) {
	c := appengine.NewContext(req)
	client := urlfetch.Client(c)
	url := playgroundBaseURL + req.URL.Path
	defer req.Body.Close()
	resp, err := client.Post(url, req.Header.Get("Content-type"), req.Body)
	if err != nil {
		http.Error(w, "Internal Server Error", 500)
		c.Errorf("making POST request: %v", err)
		return
	}
	defer resp.Body.Close()
	if _, err := io.Copy(w, resp.Body); err != nil {
		http.Error(w, "Internal Server Error", 500)
		c.Errorf("making POST request: %v", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Pilosa Corp.
//
// 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 pilosa_test

import (
	"reflect"
	"testing"
	"time"

	"github.com/pilosa/pilosa"
)

// Ensure string can be parsed into time quantum.
func TestParseTimeQuantum(t *testing.T) {
	t.Run("OK", func(t *testing.T) {
		if q, err := pilosa.ParseTimeQuantum("YMDH"); err != nil {
			t.Fatalf("unexpected error: %s", err)
		} else if q != pilosa.TimeQuantum("YMDH") {
			t.Fatalf("unexpected quantum: %#v", q)
		}
	})

	t.Run("ErrInvalidTimeQuantum", func(t *testing.T) {
		if _, err := pilosa.ParseTimeQuantum("BADQUANTUM"); err != pilosa.ErrInvalidTimeQuantum {
			t.Fatalf("unexpected error: %s", err)
		}
	})
}

// Ensure generated view name can be returned for a given time unit.
func TestViewByTimeUnit(t *testing.T) {
	ts := time.Date(2000, time.January, 2, 3, 4, 5, 6, time.UTC)

	t.Run("Y", func(t *testing.T) {
		if s := pilosa.ViewByTimeUnit("F", ts, 'Y'); s != "F_2000" {
			t.Fatalf("unexpected name: %s", s)
		}
	})
	t.Run("M", func(t *testing.T) {
		if s := pilosa.ViewByTimeUnit("F", ts, 'M'); s != "F_200001" {
			t.Fatalf("unexpected name: %s", s)
		}
	})
	t.Run("D", func(t *testing.T) {
		if s := pilosa.ViewByTimeUnit("F", ts, 'D'); s != "F_20000102" {
			t.Fatalf("unexpected name: %s", s)
		}
	})
	t.Run("H", func(t *testing.T) {
		if s := pilosa.ViewByTimeUnit("F", ts, 'H'); s != "F_2000010203" {
			t.Fatalf("unexpected name: %s", s)
		}
	})
}

// Ensure all applicable frame names can be generated when mutating a time bit.
func TestViewsByTime(t *testing.T) {
	ts := time.Date(2000, time.January, 2, 3, 4, 5, 6, time.UTC)

	t.Run("YMDH", func(t *testing.T) {
		a := pilosa.ViewsByTime("F", ts, MustParseTimeQuantum("YMDH"))
		if !reflect.DeepEqual(a, []string{"F_2000", "F_200001", "F_20000102", "F_2000010203"}) {
			t.Fatalf("unexpected names: %+v", a)
		}
	})

	t.Run("D", func(t *testing.T) {
		a := pilosa.ViewsByTime("F", ts, MustParseTimeQuantum("D"))
		if !reflect.DeepEqual(a, []string{"F_20000102"}) {
			t.Fatalf("unexpected names: %+v", a)
		}
	})
}

// Ensure sets of frames can be returned for a given time range.
func TestViewsByTimeRange(t *testing.T) {
	t.Run("Y", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 00:00"), MustParseTime("2002-01-01 00:00"), MustParseTimeQuantum("Y"))
		if !reflect.DeepEqual(a, []string{"F_2000", "F_2001"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("YM", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-01 00:00"), MustParseTime("2003-03-01 00:00"), MustParseTimeQuantum("YM"))
		if !reflect.DeepEqual(a, []string{"F_200011", "F_200012", "F_2001", "F_2002", "F_200301", "F_200302"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("YMD", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-28 00:00"), MustParseTime("2003-03-02 00:00"), MustParseTimeQuantum("YMD"))
		if !reflect.DeepEqual(a, []string{"F_20001128", "F_20001129", "F_20001130", "F_200012", "F_2001", "F_2002", "F_200301", "F_200302", "F_20030301"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("YMDH", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-28 22:00"), MustParseTime("2002-03-01 03:00"), MustParseTimeQuantum("YMDH"))
		if !reflect.DeepEqual(a, []string{"F_2000112822", "F_2000112823", "F_20001129", "F_20001130", "F_200012", "F_2001", "F_200201", "F_200202", "F_2002030100", "F_2002030101", "F_2002030102"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("M", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 00:00"), MustParseTime("2000-03-01 00:00"), MustParseTimeQuantum("M"))
		if !reflect.DeepEqual(a, []string{"F_200001", "F_200002"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("MD", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-29 00:00"), MustParseTime("2002-02-03 00:00"), MustParseTimeQuantum("MD"))
		if !reflect.DeepEqual(a, []string{"F_20001129", "F_20001130", "F_200012", "F_200101", "F_200102", "F_200103", "F_200104", "F_200105", "F_200106", "F_200107", "F_200108", "F_200109", "F_200110", "F_200111", "F_200112", "F_200201", "F_20020201", "F_20020202"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("MDH", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-29 22:00"), MustParseTime("2002-03-02 03:00"), MustParseTimeQuantum("MDH"))
		if !reflect.DeepEqual(a, []string{"F_2000112922", "F_2000112923", "F_20001130", "F_200012", "F_200101", "F_200102", "F_200103", "F_200104", "F_200105", "F_200106", "F_200107", "F_200108", "F_200109", "F_200110", "F_200111", "F_200112", "F_200201", "F_200202", "F_20020301", "F_2002030200", "F_2002030201", "F_2002030202"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("D", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 00:00"), MustParseTime("2000-01-04 00:00"), MustParseTimeQuantum("D"))
		if !reflect.DeepEqual(a, []string{"F_20000101", "F_20000102", "F_20000103"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("DH", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 22:00"), MustParseTime("2000-03-01 02:00"), MustParseTimeQuantum("DH"))
		if !reflect.DeepEqual(a, []string{"F_2000010122", "F_2000010123", "F_20000102", "F_20000103", "F_20000104", "F_20000105", "F_20000106", "F_20000107", "F_20000108", "F_20000109", "F_20000110", "F_20000111", "F_20000112", "F_20000113", "F_20000114", "F_20000115", "F_20000116", "F_20000117", "F_20000118", "F_20000119", "F_20000120", "F_20000121", "F_20000122", "F_20000123", "F_20000124", "F_20000125", "F_20000126", "F_20000127", "F_20000128", "F_20000129", "F_20000130", "F_20000131", "F_20000201", "F_20000202", "F_20000203", "F_20000204", "F_20000205", "F_20000206", "F_20000207", "F_20000208", "F_20000209", "F_20000210", "F_20000211", "F_20000212", "F_20000213", "F_20000214", "F_20000215", "F_20000216", "F_20000217", "F_20000218", "F_20000219", "F_20000220", "F_20000221", "F_20000222", "F_20000223", "F_20000224", "F_20000225", "F_20000226", "F_20000227", "F_20000228", "F_20000229", "F_2000030100", "F_2000030101"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("H", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 00:00"), MustParseTime("2000-01-01 02:00"), MustParseTimeQuantum("H"))
		if !reflect.DeepEqual(a, []string{"F_2000010100", "F_2000010101"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
}

// DefaultTimeLayout is the time layout used by the tests.
const DefaultTimeLayout = "2006-01-02 15:04"

// MustParseTime parses value using DefaultTimeLayout. Panic on error.
func MustParseTime(value string) time.Time {
	v, err := time.Parse(DefaultTimeLayout, value)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseTimePtr parses value using DefaultTimeLayout. Panic on error.
func MustParseTimePtr(value string) *time.Time {
	v := MustParseTime(value)
	return &v
}

// MustParseTimeQuantum parses v into a time quantum. Panic on error.
func MustParseTimeQuantum(v string) pilosa.TimeQuantum {
	q, err := pilosa.ParseTimeQuantum(v)
	if err != nil {
		panic(err)
	}
	return q
}
<commit_msg>remove MustParseTimePtr<commit_after>// Copyright 2017 Pilosa Corp.
//
// 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 pilosa_test

import (
	"reflect"
	"testing"
	"time"

	"github.com/pilosa/pilosa"
)

// Ensure string can be parsed into time quantum.
func TestParseTimeQuantum(t *testing.T) {
	t.Run("OK", func(t *testing.T) {
		if q, err := pilosa.ParseTimeQuantum("YMDH"); err != nil {
			t.Fatalf("unexpected error: %s", err)
		} else if q != pilosa.TimeQuantum("YMDH") {
			t.Fatalf("unexpected quantum: %#v", q)
		}
	})

	t.Run("ErrInvalidTimeQuantum", func(t *testing.T) {
		if _, err := pilosa.ParseTimeQuantum("BADQUANTUM"); err != pilosa.ErrInvalidTimeQuantum {
			t.Fatalf("unexpected error: %s", err)
		}
	})
}

// Ensure generated view name can be returned for a given time unit.
func TestViewByTimeUnit(t *testing.T) {
	ts := time.Date(2000, time.January, 2, 3, 4, 5, 6, time.UTC)

	t.Run("Y", func(t *testing.T) {
		if s := pilosa.ViewByTimeUnit("F", ts, 'Y'); s != "F_2000" {
			t.Fatalf("unexpected name: %s", s)
		}
	})
	t.Run("M", func(t *testing.T) {
		if s := pilosa.ViewByTimeUnit("F", ts, 'M'); s != "F_200001" {
			t.Fatalf("unexpected name: %s", s)
		}
	})
	t.Run("D", func(t *testing.T) {
		if s := pilosa.ViewByTimeUnit("F", ts, 'D'); s != "F_20000102" {
			t.Fatalf("unexpected name: %s", s)
		}
	})
	t.Run("H", func(t *testing.T) {
		if s := pilosa.ViewByTimeUnit("F", ts, 'H'); s != "F_2000010203" {
			t.Fatalf("unexpected name: %s", s)
		}
	})
}

// Ensure all applicable frame names can be generated when mutating a time bit.
func TestViewsByTime(t *testing.T) {
	ts := time.Date(2000, time.January, 2, 3, 4, 5, 6, time.UTC)

	t.Run("YMDH", func(t *testing.T) {
		a := pilosa.ViewsByTime("F", ts, MustParseTimeQuantum("YMDH"))
		if !reflect.DeepEqual(a, []string{"F_2000", "F_200001", "F_20000102", "F_2000010203"}) {
			t.Fatalf("unexpected names: %+v", a)
		}
	})

	t.Run("D", func(t *testing.T) {
		a := pilosa.ViewsByTime("F", ts, MustParseTimeQuantum("D"))
		if !reflect.DeepEqual(a, []string{"F_20000102"}) {
			t.Fatalf("unexpected names: %+v", a)
		}
	})
}

// Ensure sets of frames can be returned for a given time range.
func TestViewsByTimeRange(t *testing.T) {
	t.Run("Y", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 00:00"), MustParseTime("2002-01-01 00:00"), MustParseTimeQuantum("Y"))
		if !reflect.DeepEqual(a, []string{"F_2000", "F_2001"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("YM", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-01 00:00"), MustParseTime("2003-03-01 00:00"), MustParseTimeQuantum("YM"))
		if !reflect.DeepEqual(a, []string{"F_200011", "F_200012", "F_2001", "F_2002", "F_200301", "F_200302"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("YMD", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-28 00:00"), MustParseTime("2003-03-02 00:00"), MustParseTimeQuantum("YMD"))
		if !reflect.DeepEqual(a, []string{"F_20001128", "F_20001129", "F_20001130", "F_200012", "F_2001", "F_2002", "F_200301", "F_200302", "F_20030301"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("YMDH", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-28 22:00"), MustParseTime("2002-03-01 03:00"), MustParseTimeQuantum("YMDH"))
		if !reflect.DeepEqual(a, []string{"F_2000112822", "F_2000112823", "F_20001129", "F_20001130", "F_200012", "F_2001", "F_200201", "F_200202", "F_2002030100", "F_2002030101", "F_2002030102"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("M", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 00:00"), MustParseTime("2000-03-01 00:00"), MustParseTimeQuantum("M"))
		if !reflect.DeepEqual(a, []string{"F_200001", "F_200002"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("MD", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-29 00:00"), MustParseTime("2002-02-03 00:00"), MustParseTimeQuantum("MD"))
		if !reflect.DeepEqual(a, []string{"F_20001129", "F_20001130", "F_200012", "F_200101", "F_200102", "F_200103", "F_200104", "F_200105", "F_200106", "F_200107", "F_200108", "F_200109", "F_200110", "F_200111", "F_200112", "F_200201", "F_20020201", "F_20020202"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("MDH", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-11-29 22:00"), MustParseTime("2002-03-02 03:00"), MustParseTimeQuantum("MDH"))
		if !reflect.DeepEqual(a, []string{"F_2000112922", "F_2000112923", "F_20001130", "F_200012", "F_200101", "F_200102", "F_200103", "F_200104", "F_200105", "F_200106", "F_200107", "F_200108", "F_200109", "F_200110", "F_200111", "F_200112", "F_200201", "F_200202", "F_20020301", "F_2002030200", "F_2002030201", "F_2002030202"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("D", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 00:00"), MustParseTime("2000-01-04 00:00"), MustParseTimeQuantum("D"))
		if !reflect.DeepEqual(a, []string{"F_20000101", "F_20000102", "F_20000103"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("DH", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 22:00"), MustParseTime("2000-03-01 02:00"), MustParseTimeQuantum("DH"))
		if !reflect.DeepEqual(a, []string{"F_2000010122", "F_2000010123", "F_20000102", "F_20000103", "F_20000104", "F_20000105", "F_20000106", "F_20000107", "F_20000108", "F_20000109", "F_20000110", "F_20000111", "F_20000112", "F_20000113", "F_20000114", "F_20000115", "F_20000116", "F_20000117", "F_20000118", "F_20000119", "F_20000120", "F_20000121", "F_20000122", "F_20000123", "F_20000124", "F_20000125", "F_20000126", "F_20000127", "F_20000128", "F_20000129", "F_20000130", "F_20000131", "F_20000201", "F_20000202", "F_20000203", "F_20000204", "F_20000205", "F_20000206", "F_20000207", "F_20000208", "F_20000209", "F_20000210", "F_20000211", "F_20000212", "F_20000213", "F_20000214", "F_20000215", "F_20000216", "F_20000217", "F_20000218", "F_20000219", "F_20000220", "F_20000221", "F_20000222", "F_20000223", "F_20000224", "F_20000225", "F_20000226", "F_20000227", "F_20000228", "F_20000229", "F_2000030100", "F_2000030101"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
	t.Run("H", func(t *testing.T) {
		a := pilosa.ViewsByTimeRange("F", MustParseTime("2000-01-01 00:00"), MustParseTime("2000-01-01 02:00"), MustParseTimeQuantum("H"))
		if !reflect.DeepEqual(a, []string{"F_2000010100", "F_2000010101"}) {
			t.Fatalf("unexpected frames: %#v", a)
		}
	})
}

// DefaultTimeLayout is the time layout used by the tests.
const DefaultTimeLayout = "2006-01-02 15:04"

// MustParseTime parses value using DefaultTimeLayout. Panic on error.
func MustParseTime(value string) time.Time {
	v, err := time.Parse(DefaultTimeLayout, value)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseTimeQuantum parses v into a time quantum. Panic on error.
func MustParseTimeQuantum(v string) pilosa.TimeQuantum {
	q, err := pilosa.ParseTimeQuantum(v)
	if err != nil {
		panic(err)
	}
	return q
}
<|endoftext|>


<commit_before>package gtimeentry

import (
	"encoding/json"
	"fmt"
	"gopkg.in/dougEfresh/toggl-http-client.v8"
	"gopkg.in/dougEfresh/toggl-project.v8"
	"gopkg.in/dougEfresh/toggl-workspace.v8"
	"time"
)

type TimeEntry struct {
	Id          uint64                `json:"id,omitempty"`
	Description string                `json:"description"`
	Project     *gproject.Project     `json:"project"`
	Start       time.Time             `json:"start"`
	Stop        time.Time             `json:"stop"`
	Duration    uint64                `json:"duration"`
	Billable    bool                  `json:"billable"`
	Workspace   *gworkspace.Workspace `json:"workspace"`
	Tags        []string              `json:"tags"`
	Pid         uint64                `json:"pid"`
	Wid         uint64                `json:"wid"`
	Tid         uint64                `json:"tid"`
	CreatedWith string                `json:"created_with,omitempty" `
}

type TimeEntries []TimeEntry

const Endpoint = "/time_entries"
const EndpointCurrent = Endpoint + "/current"
const EndpointStart = Endpoint + "/start"

//Return a UserClient. An error is also returned when some configuration option is invalid
//    thc,err := gtoggl.NewClient("token")
//    uc,err := guser.NewClient(thc)
func NewClient(thc *ghttp.TogglHttpClient) *TimeEntryClient {
	tc := &TimeEntryClient{
		thc: thc,
	}
	tc.endpoint = thc.Url + Endpoint
	tc.currentEndpoint = thc.Url + EndpointCurrent
	tc.startEndpoint = thc.Url + EndpointStart
	return tc
}

type TimeEntryClient struct {
	thc             *ghttp.TogglHttpClient
	endpoint        string
	startEndpoint   string
	currentEndpoint string
}

func (c *TimeEntryClient) Get(tid uint64) (*TimeEntry, error) {
	return timeEntryResponse(c.thc.GetRequest(fmt.Sprintf("%s/%d", c.endpoint, tid)))
}

func (tc *TimeEntryClient) Delete(id uint64) error {
	_, err := tc.thc.DeleteRequest(fmt.Sprintf("%s/%d", tc.endpoint, id), nil)
	return err
}

func (c *TimeEntryClient) List() (TimeEntries, error) {
	body, err := c.thc.GetRequest(c.endpoint)
	var te TimeEntries
	if err != nil {
		return te, err
	}
	if body == nil {
		return nil, nil
	}
	err = json.Unmarshal(*body, &te)
	return te, err
}

func (c *TimeEntryClient) Create(t *TimeEntry) (*TimeEntry, error) {
	if len(t.CreatedWith) < 0 {
		t.CreatedWith = "gtoggl"
	}
	up := map[string]interface{}{"time_entry": t}
	return timeEntryResponse(c.thc.PostRequest(c.endpoint, up))
}

func (c *TimeEntryClient) Update(t *TimeEntry) (*TimeEntry, error) {
	up := map[string]interface{}{"time_entry": t}
	return timeEntryResponse(c.thc.PutRequest(fmt.Sprintf("%s/%d", c.endpoint, t.Id), up))
}

func timeEntryResponse(response *json.RawMessage, error error) (*TimeEntry, error) {
	if error != nil {
		return nil, error
	}
	if response == nil {
		return nil, nil
	}
	var tResp ghttp.TogglResponse
	err := json.Unmarshal(*response, &tResp)
	if err != nil {
		return nil, err
	}
	var t TimeEntry
	err = json.Unmarshal(*tResp.Data, &t)
	if err != nil {
		return nil, err
	}
	return &t, err
}
<commit_msg>Use int64 for TimeEntry.Duration<commit_after>package gtimeentry

import (
	"encoding/json"
	"fmt"
	"gopkg.in/dougEfresh/toggl-http-client.v8"
	"gopkg.in/dougEfresh/toggl-project.v8"
	"gopkg.in/dougEfresh/toggl-workspace.v8"
	"time"
)

type TimeEntry struct {
	Id          uint64                `json:"id,omitempty"`
	Description string                `json:"description"`
	Project     *gproject.Project     `json:"project"`
	Start       time.Time             `json:"start"`
	Stop        time.Time             `json:"stop"`
	Duration    int64                 `json:"duration"`
	Billable    bool                  `json:"billable"`
	Workspace   *gworkspace.Workspace `json:"workspace"`
	Tags        []string              `json:"tags"`
	Pid         uint64                `json:"pid"`
	Wid         uint64                `json:"wid"`
	Tid         uint64                `json:"tid"`
	CreatedWith string                `json:"created_with,omitempty" `
}

type TimeEntries []TimeEntry

const Endpoint = "/time_entries"
const EndpointCurrent = Endpoint + "/current"
const EndpointStart = Endpoint + "/start"

//Return a UserClient. An error is also returned when some configuration option is invalid
//    thc,err := gtoggl.NewClient("token")
//    uc,err := guser.NewClient(thc)
func NewClient(thc *ghttp.TogglHttpClient) *TimeEntryClient {
	tc := &TimeEntryClient{
		thc: thc,
	}
	tc.endpoint = thc.Url + Endpoint
	tc.currentEndpoint = thc.Url + EndpointCurrent
	tc.startEndpoint = thc.Url + EndpointStart
	return tc
}

type TimeEntryClient struct {
	thc             *ghttp.TogglHttpClient
	endpoint        string
	startEndpoint   string
	currentEndpoint string
}

func (c *TimeEntryClient) Get(tid uint64) (*TimeEntry, error) {
	return timeEntryResponse(c.thc.GetRequest(fmt.Sprintf("%s/%d", c.endpoint, tid)))
}

func (tc *TimeEntryClient) Delete(id uint64) error {
	_, err := tc.thc.DeleteRequest(fmt.Sprintf("%s/%d", tc.endpoint, id), nil)
	return err
}

func (c *TimeEntryClient) List() (TimeEntries, error) {
	body, err := c.thc.GetRequest(c.endpoint)
	var te TimeEntries
	if err != nil {
		return te, err
	}
	if body == nil {
		return nil, nil
	}
	err = json.Unmarshal(*body, &te)
	return te, err
}

func (c *TimeEntryClient) Create(t *TimeEntry) (*TimeEntry, error) {
	if len(t.CreatedWith) < 0 {
		t.CreatedWith = "gtoggl"
	}
	up := map[string]interface{}{"time_entry": t}
	return timeEntryResponse(c.thc.PostRequest(c.endpoint, up))
}

func (c *TimeEntryClient) Update(t *TimeEntry) (*TimeEntry, error) {
	up := map[string]interface{}{"time_entry": t}
	return timeEntryResponse(c.thc.PutRequest(fmt.Sprintf("%s/%d", c.endpoint, t.Id), up))
}

func timeEntryResponse(response *json.RawMessage, error error) (*TimeEntry, error) {
	if error != nil {
		return nil, error
	}
	if response == nil {
		return nil, nil
	}
	var tResp ghttp.TogglResponse
	err := json.Unmarshal(*response, &tResp)
	if err != nil {
		return nil, err
	}
	var t TimeEntry
	err = json.Unmarshal(*tResp.Data, &t)
	if err != nil {
		return nil, err
	}
	return &t, err
}
<|endoftext|>


<commit_before>package goetty

// timer wheel impl
// author:  zhangxu
// date:    2015-6-26
// version: 1.0.0

import (
	"container/list"
	"hash/fnv"
	"math"
	"sync"
	"time"
)

// SimpleTimeWheel Simple time wheel impl
type SimpleTimeWheel struct {
	timer *time.Ticker

	tick        time.Duration
	periodCount int64 // 每轮多少次
	pos         int64 // 当前指针
	period      int64 // 轮数

	callbacks  map[string]func(key string)
	timeoutMap map[int64]*list.List

	mutex *sync.Mutex
}

// NewSimpleTimeWheel create a simple time wheel
func NewSimpleTimeWheel(tick time.Duration, periodCount int64) *SimpleTimeWheel {
	timeWheel := &SimpleTimeWheel{
		timer:       time.NewTicker(tick),
		tick:        tick,
		periodCount: periodCount,
		pos:         0,
		period:      0,

		callbacks:  make(map[string]func(key string)),
		timeoutMap: make(map[int64]*list.List),

		mutex: &sync.Mutex{},
	}

	return timeWheel
}

// AddWithID add a timeout call with ID
func (t *SimpleTimeWheel) AddWithID(timeout time.Duration, key string, callback func(key string)) {
	t.mutex.Lock()

	index := t.passed() + int64(float64(timeout.Nanoseconds())/float64(t.tick.Nanoseconds())+0.5)

	l, ok := t.timeoutMap[index]
	if !ok {
		l = list.New()
		t.timeoutMap[index] = l
	}

	l.PushBack(key)
	t.callbacks[key] = callback
	t.mutex.Unlock()
}

// Add add a timeout callback
func (t *SimpleTimeWheel) Add(timeout time.Duration, callback func(key string)) string {
	key := NewKey()
	t.AddWithID(timeout, key, callback)
	return key
}

// Cancel cancel a callback
func (t *SimpleTimeWheel) Cancel(key string) {
	t.mutex.Lock()
	delete(t.callbacks, key)
	t.mutex.Unlock()
}

// Start start a timeout calc
func (t *SimpleTimeWheel) Start() {
	go func() {
		for {
			<-t.timer.C
			t.turn()
		}
	}()
}

// Stop stop
func (t *SimpleTimeWheel) Stop() {
	if nil != t.timer {
		t.timer.Stop()
	}
}

func (t *SimpleTimeWheel) turn() {
	t.mutex.Lock()
	t.mutex.Unlock()

	t.pos++

	if t.pos == t.periodCount {
		t.pos = 0
		t.period++
	}

	t.doTimeout()
}

func (t *SimpleTimeWheel) doTimeout() {
	timeKey := t.passed()

	keys, ok := t.timeoutMap[timeKey]

	if ok {
		for iter := keys.Front(); iter != nil; iter = iter.Next() {
			key, _ := iter.Value.(string)
			f, _ := t.callbacks[key]
			if nil != f {
				delete(t.callbacks, key)
				f(key)
			}
		}
	}

	delete(t.timeoutMap, timeKey)
}

func (t *SimpleTimeWheel) passed() int64 {
	return t.periodCount*t.period + t.pos
}

// HashedTimeWheel hash Simple time wheel
type HashedTimeWheel struct {
	mask        int
	wheelBucket []*SimpleTimeWheel
}

// NewHashedTimeWheel create a new HashedTimeWheel
func NewHashedTimeWheel(duration time.Duration, periodCount int64, powOf2 int) *HashedTimeWheel {
	max := int(math.Pow(2.0, float64(powOf2)))
	h := &HashedTimeWheel{
		mask:        max - 1,
		wheelBucket: make([]*SimpleTimeWheel, max),
	}

	h.init(duration, periodCount, max)

	return h
}

// Add add a timeout calc
func (h *HashedTimeWheel) Add(timeout time.Duration, callback func(key string)) string {
	key := NewKey()
	h.AddWithID(timeout, key, callback)
	return key
}

// AddWithID add a timeout calc by ID
func (h *HashedTimeWheel) AddWithID(timeout time.Duration, key string, callback func(key string)) string {
	index := hashCode(key) & h.mask
	h.wheelBucket[index].AddWithID(timeout, key, callback)
	return key
}

// Cancel calc a timeout
func (h *HashedTimeWheel) Cancel(key string) {
	index := hashCode(key) & h.mask
	h.wheelBucket[index].Cancel(key)
}

func (h *HashedTimeWheel) init(duration time.Duration, periodCount int64, max int) {
	for i := 0; i < max; i++ {
		h.wheelBucket[i] = NewSimpleTimeWheel(duration, periodCount)
	}
}

// Start start timeout calc
func (h *HashedTimeWheel) Start() {
	for i := 0; i < len(h.wheelBucket); i++ {
		go h.wheelBucket[i].Start()
	}
}

// Stop stop timeout calc
func (h *HashedTimeWheel) Stop() {
	for i := 0; i < len(h.wheelBucket); i++ {
		go h.wheelBucket[i].Stop()
	}
}

// HashCode get has code
func HashCode(v string) int {
	return hashCode(v)
}

func hashCode(v string) int {
	h := fnv.New32a()
	h.Write([]byte(v))
	code := h.Sum32()
	return int(code)
}
<commit_msg>fixbug concurrent read and wirte map<commit_after>package goetty

// timer wheel impl
// author:  zhangxu
// date:    2015-6-26
// version: 1.0.0

import (
	"container/list"
	"hash/fnv"
	"math"
	"sync"
	"time"
)

// SimpleTimeWheel Simple time wheel impl
type SimpleTimeWheel struct {
	timer *time.Ticker

	tick        time.Duration
	periodCount int64 // 每轮多少次
	pos         int64 // 当前指针
	period      int64 // 轮数

	callbacks  map[string]func(key string)
	timeoutMap map[int64]*list.List

	cbLock      *sync.RWMutex
	timeoutLock *sync.RWMutex
}

// NewSimpleTimeWheel create a new SimpleTimeWheel instance
func NewSimpleTimeWheel(tick time.Duration, periodCount int64) *SimpleTimeWheel {
	timeWheel := &SimpleTimeWheel{
		timer:       time.NewTicker(tick),
		tick:        tick,
		periodCount: periodCount,
		pos:         0,
		period:      0,

		callbacks:  make(map[string]func(key string)),
		timeoutMap: make(map[int64]*list.List),

		cbLock:      &sync.RWMutex{},
		timeoutLock: &sync.RWMutex{},
	}

	return timeWheel
}

// AddWithId add a timeout calc with spec id
func (t *SimpleTimeWheel) AddWithId(timeout time.Duration, key string, callback func(key string)) {
	index := t.passed() + int64(float64(timeout.Nanoseconds())/float64(t.tick.Nanoseconds())+0.5)

	t.timeoutLock.Lock()
	l, ok := t.timeoutMap[index]
	if !ok {
		l = list.New()
		t.timeoutMap[index] = l
	}
	t.timeoutLock.Unlock()

	t.cbLock.Lock()
	l.PushBack(key)
	t.callbacks[key] = callback
	t.cbLock.Unlock()

}

// Add add a timeout calc
func (t *SimpleTimeWheel) Add(timeout time.Duration, callback func(key string)) string {
	key := NewKey()
	t.AddWithId(timeout, key, callback)
	return key
}

// Cancel cancel a timeout calc
func (t *SimpleTimeWheel) Cancel(key string) {
	t.cbLock.Lock()
	delete(t.callbacks, key)
	t.cbLock.Unlock()
}

// Start start the time wheel
func (t *SimpleTimeWheel) Start() {
	go func() {
		for {
			<-t.timer.C
			t.turn()
		}
	}()
}

// Stop stop the time wheel
func (t *SimpleTimeWheel) Stop() {
	if nil != t.timer {
		t.timer.Stop()
	}
}

func (t *SimpleTimeWheel) turn() {
	t.timeoutLock.Lock()
	t.timeoutLock.Unlock()

	t.pos++

	if t.pos == t.periodCount {
		t.pos = 0
		t.period++
	}

	t.doTimeout()
}

func (t *SimpleTimeWheel) doTimeout() {
	timeKey := t.passed()

	t.timeoutLock.RLock()
	keys, ok := t.timeoutMap[timeKey]
	t.timeoutLock.RUnlock()

	if ok {
		for iter := keys.Front(); iter != nil; iter = iter.Next() {
			key, _ := iter.Value.(string)
			t.cbLock.RLock()
			f, _ := t.callbacks[key]
			t.cbLock.RUnlock()

			if nil != f {
				t.cbLock.Lock()
				delete(t.callbacks, key)
				t.cbLock.Unlock()

				f(key)
			}
		}
	}

	t.timeoutLock.Lock()
	delete(t.timeoutMap, timeKey)
	t.timeoutLock.Unlock()
}

func (t *SimpleTimeWheel) passed() int64 {
	return t.periodCount*t.period + t.pos
}

// HashedTimeWheel hashed SimpleTimeWheel
type HashedTimeWheel struct {
	mask        int
	wheelBucket []*SimpleTimeWheel
}

// NewHashedTimeWheel create a HashedTimeWheel instance
func NewHashedTimeWheel(duration time.Duration, periodCount int64, powOf2 int) *HashedTimeWheel {
	max := int(math.Pow(2.0, float64(powOf2)))
	h := &HashedTimeWheel{
		mask:        max - 1,
		wheelBucket: make([]*SimpleTimeWheel, max),
	}

	h.init(duration, periodCount, max)

	return h
}

// Add add a timeout calc
func (h *HashedTimeWheel) Add(timeout time.Duration, callback func(key string)) string {
	key := NewKey()
	h.AddWithId(timeout, key, callback)
	return key
}

// AddWithId add a timeout calc using spec id
func (h *HashedTimeWheel) AddWithId(timeout time.Duration, key string, callback func(key string)) string {
	index := hashCode(key) & h.mask
	h.wheelBucket[index].AddWithId(timeout, key, callback)
	return key
}

// Cancel cancel a timeout calc
func (h *HashedTimeWheel) Cancel(key string) {
	index := hashCode(key) & h.mask
	h.wheelBucket[index].Cancel(key)
}

func (h *HashedTimeWheel) init(duration time.Duration, periodCount int64, max int) {
	for i := 0; i < max; i++ {
		h.wheelBucket[i] = NewSimpleTimeWheel(duration, periodCount)
	}
}

// Start start the time wheel
func (h *HashedTimeWheel) Start() {
	for i := 0; i < len(h.wheelBucket); i++ {
		go h.wheelBucket[i].Start()
	}
}

// Stop stop the time wheel
func (h *HashedTimeWheel) Stop() {
	for i := 0; i < len(h.wheelBucket); i++ {
		go h.wheelBucket[i].Stop()
	}
}

// HashCode return hash code value
func HashCode(v string) int {
	return hashCode(v)
}

func hashCode(v string) int {
	h := fnv.New32a()
	h.Write([]byte(v))
	code := h.Sum32()
	return int(code)
}

<|endoftext|>


<commit_before>package tlsh

import (
	"bufio"
	"os"
	"testing"
)

var (
	testCases = []struct {
		filename string
		hash     string
	}{
		{"tests/test_file_1", "8ED02202FC30802303A002B03B33300FC30A82F83008C2FA000A0080B8BA0E02CCA0C3"},
		{"tests/test_file_2", "B2319634F5C033244EB792AA3168A366E737553DA305A28440CE842D7B57A2CC63B6EC"},
		{"tests/test_file_3", "EA31834386C503B62A920319BA4F92D3BF6FC2B863384515A4EA5638450BC1E9376AE9"},
		{"tests/test_file_4", "5111421E72610B73189A13A055B8A8D9B22BB25B7AAF2A84146DF245232A06CD5FB854"},
		{"tests/test_file_5", "E1D1B7337E4E03044FE22379D7C9C95ED66CE42426C39759CCEA9A2AF516838E723364"},
		{"tests/test_file_6", "2FE1A7723E8603145BF222F9979ACC7EF74CE4242BD3A7D49899F919F146814C3233A8"},
		{"tests/test_file_7_lena.jpg", "85C2F1CE3D989428683106EBE5EAAAC924F2D5020B38B1550DA8E5F0DD8C65DECF7037"},
		{"tests/test_file_8_lena.png", "F7A433B5648BCC69DD48E1DDF1A1876C56E08C0BB264438FAB412C4686FA3F3DB05E36"},
		{"tests/test_file_9_tinyssl.exe", "67A3AD97F601C873E11A0AF49D83D2D6BC7F7F709E522C9B74990B0E8D796822D1D48A"},
	}
)

func TestReal(t *testing.T) {
	for _, tc := range testCases {
		if hash, err := Hash(tc.filename); hash != tc.hash {
			if err != nil {
				t.Error(err)
			}
			t.Errorf("\nfilename: %s\n%s\n%s - doesn't match real hash\n", tc.filename, tc.hash, hash)
		}
	}
}

func BenchmarkPearson(b *testing.B) {
	var salt = byte(0)
	var keys = [3]byte{1, 3, 7}
	for n := 0; n < b.N; n++ {
		pearsonHash(salt, &keys)
	}
}

func BenchmarkFillBuckets(b *testing.B) {
	f, err := os.Open("tests/test_file_1")
	defer f.Close()
	if err != nil {
		b.Error(err)
	}
	f.Seek(0, 0)
	for n := 0; n < b.N; n++ {
		r := bufio.NewReader(f)
		fillBuckets(r)
		f.Seek(0, 0)
	}
}

func BenchmarkQuartilePoints(b *testing.B) {
	f, err := os.Open("tests/test_file_1")
	defer f.Close()
	if err != nil {
		b.Error(err)
	}
	r := bufio.NewReader(f)
	buckets, _, _, err := fillBuckets(r)
	if err != nil {
		b.Error(err)
	}
	for n := 0; n < b.N; n++ {
		quartilePoints(buckets)
	}
}
<commit_msg>Benchmark whole Hash package<commit_after>package tlsh

import (
	"bufio"
	"os"
	"testing"
)

var (
	testCases = []struct {
		filename string
		hash     string
	}{
		{"tests/test_file_1", "8ED02202FC30802303A002B03B33300FC30A82F83008C2FA000A0080B8BA0E02CCA0C3"},
		{"tests/test_file_2", "B2319634F5C033244EB792AA3168A366E737553DA305A28440CE842D7B57A2CC63B6EC"},
		{"tests/test_file_3", "EA31834386C503B62A920319BA4F92D3BF6FC2B863384515A4EA5638450BC1E9376AE9"},
		{"tests/test_file_4", "5111421E72610B73189A13A055B8A8D9B22BB25B7AAF2A84146DF245232A06CD5FB854"},
		{"tests/test_file_5", "E1D1B7337E4E03044FE22379D7C9C95ED66CE42426C39759CCEA9A2AF516838E723364"},
		{"tests/test_file_6", "2FE1A7723E8603145BF222F9979ACC7EF74CE4242BD3A7D49899F919F146814C3233A8"},
		{"tests/test_file_7_lena.jpg", "85C2F1CE3D989428683106EBE5EAAAC924F2D5020B38B1550DA8E5F0DD8C65DECF7037"},
		{"tests/test_file_8_lena.png", "F7A433B5648BCC69DD48E1DDF1A1876C56E08C0BB264438FAB412C4686FA3F3DB05E36"},
		{"tests/test_file_9_tinyssl.exe", "67A3AD97F601C873E11A0AF49D83D2D6BC7F7F709E522C9B74990B0E8D796822D1D48A"},
	}
)

func TestReal(t *testing.T) {
	for _, tc := range testCases {
		if hash, err := Hash(tc.filename); hash != tc.hash {
			if err != nil {
				t.Error(err)
			}
			t.Errorf("\nfilename: %s\n%s\n%s - doesn't match real hash\n", tc.filename, tc.hash, hash)
		}
	}
}

func BenchmarkPearson(b *testing.B) {
	var salt = byte(0)
	var keys = [3]byte{1, 3, 7}
	for n := 0; n < b.N; n++ {
		pearsonHash(salt, &keys)
	}
}

func BenchmarkFillBuckets(b *testing.B) {
	f, err := os.Open("tests/test_file_1")
	defer f.Close()
	if err != nil {
		b.Error(err)
	}
	f.Seek(0, 0)
	for n := 0; n < b.N; n++ {
		r := bufio.NewReader(f)
		fillBuckets(r)
		f.Seek(0, 0)
	}
}

func BenchmarkQuartilePoints(b *testing.B) {
	f, err := os.Open("tests/test_file_1")
	defer f.Close()
	if err != nil {
		b.Error(err)
	}
	r := bufio.NewReader(f)
	buckets, _, _, err := fillBuckets(r)
	if err != nil {
		b.Error(err)
	}
	for n := 0; n < b.N; n++ {
		quartilePoints(buckets)
	}
}

func BenchmarkHash(b *testing.B) {
	f := "tests/test_file_1"
	for n := 0; n < b.N; n++ {
		Hash(f)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 The Cockroach Authors.
//
// 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. See the AUTHORS file
// for names of contributors.
//
// Author: Arjun Narayan
//
// The TPC-H  program is intended to simulate the workload specified by
// the Transaction Processing Council Benchmark TPC-H

package main

import (
	"database/sql"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"

	"strconv"

	"github.com/cockroachdb/cockroach-go/crdb"
	_ "github.com/lib/pq"
)

var concurrency = flag.Int("load-concurrency", 2*runtime.NumCPU(),
	"Number of concurrent loaders populating the initial tables.")
var verbose = flag.Bool("v", false, "Print verbose debug output")
var drop = flag.Bool("drop", false,
	"Drop the existing table and recreate it to start from scratch")
var load = flag.Bool("load", false,
	"Load data into the database from ")
var restore = flag.String("restore", "",
	"Restore data from the specified backup file. Cannot be used with load.")
var dataDir = flag.String("data-dir", "data",
	"Source for data files to load from. Data must be generated using the DBGEN utility.")
var distsql = flag.Bool("dist-sql", true, "Use DistSQL for query execution (default true)")
var scaleFactor = flag.Uint("scale-factor", 1, "The Scale Factor for the TPC-H benchmark")
var insertsPerTransaction = flag.Uint("inserts-per-tx", 100, "Number of inserts to batch into a single transaction when loading data")
var queries = flag.String("queries", "1,3,7,8,9,19", "Queries to run. Use a comma separated list of query numbers. Default: (1,3,7,8,9,19)")

func runLoader(dbURL string, datafile string, t table, wg *sync.WaitGroup) {
	defer func() {
		if *verbose {
			fmt.Printf("Worker done loading from file '%s'\n", datafile)
		}
		wg.Done()
	}()

	parsedURL, err := url.Parse(dbURL)
	if err != nil {
		fmt.Printf("Error encountered in parsing DB URL: %s\n", err)
	}

	// Open connection to server
	db, err := sql.Open("postgres", parsedURL.String())
	if err != nil {
		fmt.Printf("Error encountered in connecting to database: %s\n", err)
	}

	filename := fmt.Sprintf("%s/%s", "data", datafile)
	if err := insertTableFromFile(db, filename, t); err != nil {
		fmt.Printf("Error encountered in table insertion: %s\n", err)
	}
}

func runRestore(db *sql.DB, restoreLoc string) error {
	restoreStmt := fmt.Sprintf("RESTORE DATABASE tpch FROM '%s'", restoreLoc)
	_, err := db.Exec(restoreStmt)
	return err
}

// setupDatabase performs initial setup for the example, creating a database
// with a single table. If the desired table already exists on the cluster, the
// existing table will be dropped if the -drop flag was specified.
func setupDatabase(dbURL string) (*sql.DB, error) {
	if *verbose {
		fmt.Printf("Setting up the database. Connecting to db: %s\n", dbURL)
	}
	parsedURL, err := url.Parse(dbURL)
	if err != nil {
		return nil, err
	}

	// Open connection to server and create a database.
	db, err := sql.Open("postgres", parsedURL.String())
	if err != nil {
		return nil, err
	}

	return db, nil
}

var usage = func() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s <db URL>\n\n", os.Args[0])
	flag.PrintDefaults()
}

func main() {
	flag.Usage = usage
	flag.Parse()
	if *verbose {
		fmt.Fprintf(os.Stdout, "Starting TPC-H load generator\n")
	}

	dbURL := "postgresql://root@localhost:26257/tpch?sslmode=disable"
	if flag.NArg() == 1 {
		dbURL = flag.Arg(0)
	}

	db, err := setupDatabase(dbURL)

	if err != nil {
		fmt.Printf("Setting up database connection failed: %s, continuing assuming database already exists.", err)
	}

	if (*restore != "") && *load {
		log.Fatal("Only one of -load or -restore must be specified.")
	}

	// Ensure the database exists
	if err = crdb.ExecuteTx(db, func(tx *sql.Tx) error {
		_, inErr := tx.Exec("CREATE DATABASE IF NOT EXISTS tpch")
		return inErr
	}); err != nil {
		if *verbose {
			log.Fatalf("Failed to create the %s\n",
				err)
		}
	}

	if *restore != "" {
		if err = runRestore(db, *restore); err != nil {
			log.Fatalf("Restore failed: %s", err)
		}
	}

	if *load {
		if err = createTables(db); err != nil {
			fmt.Printf("Creating tables and indices failed: %s\n", err)
		}

		if *verbose {
			fmt.Printf("Database setup complete. Loading...\n")
		}

		files, err := ioutil.ReadDir("./data/")
		if err != nil {
			log.Fatalf("Failed to read data directory for loading data: %s", err)
		}

		loadStart := time.Now()
		var wg sync.WaitGroup
		for _, file := range files {
			wg.Add(1)
			t, err := resolveTableTypeFromFileName(file.Name())
			if err != nil {
				log.Fatal(err)
			}
			runLoader(dbURL, file.Name(), t, &wg)
		}
		wg.Wait()
		if *verbose {
			fmt.Printf("Loading complete, total time elapsed: %s\n",
				time.Since(loadStart))
		}
	}

	listQueries := strings.Split(*queries, ",")
	for _, query := range listQueries {
		start := time.Now()
		query = strings.TrimSpace(query)
		queryInt, err := strconv.Atoi(query)
		if err != nil {
			fmt.Printf("Error: Query %s must be an integer", query)
		}
		numRows, err := runQuery(db, queryInt)
		elapsed := time.Now().Sub(start)
		if err != nil {
			fmt.Printf("Error occured when running query %s: %s\n", query, err)
		}
		fmt.Printf("Finished query %s: %d rows returned after %4.2f seconds\n",
			query, numRows, elapsed.Seconds())
	}
}
<commit_msg>tpch: use the new restore command<commit_after>// Copyright 2017 The Cockroach Authors.
//
// 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. See the AUTHORS file
// for names of contributors.
//
// Author: Arjun Narayan
//
// The TPC-H  program is intended to simulate the workload specified by
// the Transaction Processing Council Benchmark TPC-H

package main

import (
	"database/sql"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"

	"strconv"

	"github.com/cockroachdb/cockroach-go/crdb"
	_ "github.com/lib/pq"
)

var concurrency = flag.Int("load-concurrency", 2*runtime.NumCPU(),
	"Number of concurrent loaders populating the initial tables.")
var verbose = flag.Bool("v", false, "Print verbose debug output")
var drop = flag.Bool("drop", false,
	"Drop the existing table and recreate it to start from scratch")
var load = flag.Bool("load", false,
	"Load data into the database from ")
var restore = flag.String("restore", "",
	"Restore data from the specified backup file. Cannot be used with load.")
var dataDir = flag.String("data-dir", "data",
	"Source for data files to load from. Data must be generated using the DBGEN utility.")
var distsql = flag.Bool("dist-sql", true, "Use DistSQL for query execution (default true)")
var scaleFactor = flag.Uint("scale-factor", 1, "The Scale Factor for the TPC-H benchmark")
var insertsPerTransaction = flag.Uint("inserts-per-tx", 100, "Number of inserts to batch into a single transaction when loading data")
var queries = flag.String("queries", "1,3,7,8,9,19", "Queries to run. Use a comma separated list of query numbers. Default: (1,3,7,8,9,19)")

func runLoader(dbURL string, datafile string, t table, wg *sync.WaitGroup) {
	defer func() {
		if *verbose {
			fmt.Printf("Worker done loading from file '%s'\n", datafile)
		}
		wg.Done()
	}()

	parsedURL, err := url.Parse(dbURL)
	if err != nil {
		fmt.Printf("Error encountered in parsing DB URL: %s\n", err)
	}

	// Open connection to server
	db, err := sql.Open("postgres", parsedURL.String())
	if err != nil {
		fmt.Printf("Error encountered in connecting to database: %s\n", err)
	}

	filename := fmt.Sprintf("%s/%s", "data", datafile)
	if err := insertTableFromFile(db, filename, t); err != nil {
		fmt.Printf("Error encountered in table insertion: %s\n", err)
	}
}

func runRestore(db *sql.DB, restoreLoc string) error {
	restoreStmt := fmt.Sprintf("RESTORE tpch.* FROM '%s'", restoreLoc)
	_, err := db.Exec(restoreStmt)
	return err
}

// setupDatabase performs initial setup for the example, creating a database
// with a single table. If the desired table already exists on the cluster, the
// existing table will be dropped if the -drop flag was specified.
func setupDatabase(dbURL string) (*sql.DB, error) {
	if *verbose {
		fmt.Printf("Setting up the database. Connecting to db: %s\n", dbURL)
	}
	parsedURL, err := url.Parse(dbURL)
	if err != nil {
		return nil, err
	}

	// Open connection to server and create a database.
	db, err := sql.Open("postgres", parsedURL.String())
	if err != nil {
		return nil, err
	}

	return db, nil
}

var usage = func() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s <db URL>\n\n", os.Args[0])
	flag.PrintDefaults()
}

func main() {
	flag.Usage = usage
	flag.Parse()
	if *verbose {
		fmt.Fprintf(os.Stdout, "Starting TPC-H load generator\n")
	}

	dbURL := "postgresql://root@localhost:26257/tpch?sslmode=disable"
	if flag.NArg() == 1 {
		dbURL = flag.Arg(0)
	}

	db, err := setupDatabase(dbURL)

	if err != nil {
		fmt.Printf("Setting up database connection failed: %s, continuing assuming database already exists.", err)
	}

	if (*restore != "") && *load {
		log.Fatal("Only one of -load or -restore must be specified.")
	}

	// Ensure the database exists
	if err = crdb.ExecuteTx(db, func(tx *sql.Tx) error {
		_, inErr := tx.Exec("CREATE DATABASE IF NOT EXISTS tpch")
		return inErr
	}); err != nil {
		if *verbose {
			log.Fatalf("Failed to create the %s\n",
				err)
		}
	}

	if *restore != "" {
		if err = runRestore(db, *restore); err != nil {
			log.Fatalf("Restore failed: %s", err)
		}
	}

	if *load {
		if err = createTables(db); err != nil {
			fmt.Printf("Creating tables and indices failed: %s\n", err)
		}

		if *verbose {
			fmt.Printf("Database setup complete. Loading...\n")
		}

		files, err := ioutil.ReadDir("./data/")
		if err != nil {
			log.Fatalf("Failed to read data directory for loading data: %s", err)
		}

		loadStart := time.Now()
		var wg sync.WaitGroup
		for _, file := range files {
			wg.Add(1)
			t, err := resolveTableTypeFromFileName(file.Name())
			if err != nil {
				log.Fatal(err)
			}
			runLoader(dbURL, file.Name(), t, &wg)
		}
		wg.Wait()
		if *verbose {
			fmt.Printf("Loading complete, total time elapsed: %s\n",
				time.Since(loadStart))
		}
	}

	listQueries := strings.Split(*queries, ",")
	for _, query := range listQueries {
		start := time.Now()
		query = strings.TrimSpace(query)
		queryInt, err := strconv.Atoi(query)
		if err != nil {
			fmt.Printf("Error: Query %s must be an integer", query)
		}
		numRows, err := runQuery(db, queryInt)
		elapsed := time.Now().Sub(start)
		if err != nil {
			fmt.Printf("Error occured when running query %s: %s\n", query, err)
		}
		fmt.Printf("Finished query %s: %d rows returned after %4.2f seconds\n",
			query, numRows, elapsed.Seconds())
	}
}
<|endoftext|>


<commit_before>package pixel

import "github.com/go-gl/mathgl/mgl32"

// Transform holds space transformation information. Concretely, a transformation is specified by position,
// anchor, scale and rotation.
//
// All points are first rotated around the anchor. Then they are multiplied by the scale. If the
// scale factor is 2, the object becomes 2x bigger. Finally, all points are moved, so that the original
// anchor is located precisely at the position.
//
// Create a Transform object with the Position function. This sets the position variable, which is the
// most important. Then use methods, like Scale and Rotate to change scale, rotation and achor. The order
// in which you apply these methods is irrelevant.
//
//   pixel.Position(pixel.V(100, 100)).Rotate(math.Pi / 3).Scale(1.5)
type Transform struct {
	pos, anc, sca Vec
	rot           float64
}

// Position creates a Transformation object with specified position. Anchor is (0, 0), rotation is 0 and scale is 1.
func Position(position Vec) Transform {
	return Transform{
		pos: position,
		sca: V(1, 1),
	}
}

// GetPosition returns the position of a transform.
func (t Transform) GetPosition() Vec {
	return t.pos
}

// GetAnchor returns the anchor of a transform.
func (t Transform) GetAnchor() Vec {
	return t.anc
}

// GetScale returns the scale (2 dimensional) of transform.
func (t Transform) GetScale() Vec {
	return t.sca
}

// GetRotation returns the rotation of a transform (in radians).
func (t Transform) GetRotation() float64 {
	return t.rot
}

// Position sets position.
func (t Transform) Position(position Vec) Transform {
	t.pos = position
	return t
}

// Move adds delta to position.
func (t Transform) Move(delta Vec) Transform {
	t.pos += delta
	return t
}

// Anchor sets anchor. Anchor is the rotation center and will be moved to the position.
func (t Transform) Anchor(anchor Vec) Transform {
	t.anc = anchor
	return t
}

// MoveAnchor adds delta to anchor.
func (t Transform) MoveAnchor(delta Vec) Transform {
	t.anc += delta
	return t
}

// Scale scales the transform by the supplied factor.
//
// Note, that subsequent calls to this method accumulate the final scale factor. Scaling two times by 2 is equivalent
// to scaling once by 4.
func (t Transform) Scale(scale float64) Transform {
	t.sca = t.sca.Scaled(scale)
	return t
}

// ScaleXY scales the transform by the supplied X and Y factor. Note, that scale is applied before rotation.
//
// Note, that subsequent calls to this method accumulate the final scale factor. Scaling two times by 2 is equivalent
// to scaling once by 4.
func (t Transform) ScaleXY(scale Vec) Transform {
	t.sca = V(t.sca.X()*scale.X(), t.sca.Y()*scale.Y())
	return t
}

// Rotate rotates the transform by the supplied angle in radians.
//
// Note, that subsequent calls to this method accumulate the final rotation. Rotating two times by Pi/2 is
// equivalent to rotating once by Pi.
func (t Transform) Rotate(angle float64) Transform {
	t.rot += angle
	return t
}

// Mat3 returns a transformation matrix that satisfies previously set transform properties.
func (t Transform) Mat3() mgl32.Mat3 {
	mat := mgl32.Ident3()
	mat = mat.Mul3(mgl32.Translate2D(float32(t.pos.X()), float32(t.pos.Y())))
	mat = mat.Mul3(mgl32.Rotate3DZ(float32(t.rot)))
	mat = mat.Mul3(mgl32.Scale2D(float32(t.sca.X()), float32(t.sca.Y())))
	mat = mat.Mul3(mgl32.Translate2D(float32(-t.anc.X()), float32(-t.anc.Y())))
	return mat
}

// Camera is a convenience function, that returns a Transform that acts like a camera.
// Center is the position in the world coordinates, that will be projected onto the center of the screen.
// One unit in world coordinates will be projected onto zoom pixels.
//
// It is possible to apply additional rotations, scales and moves to the returned transform.
func Camera(center, zoom, screenSize Vec) Transform {
	return Position(0).Anchor(center).ScaleXY(2 * zoom).ScaleXY(V(1/screenSize.X(), 1/screenSize.Y()))
}
<commit_msg>add InvMat3, Project and Unproject methods to Transform<commit_after>package pixel

import "github.com/go-gl/mathgl/mgl32"

// Transform holds space transformation information. Concretely, a transformation is specified by position,
// anchor, scale and rotation.
//
// All points are first rotated around the anchor. Then they are multiplied by the scale. If the
// scale factor is 2, the object becomes 2x bigger. Finally, all points are moved, so that the original
// anchor is located precisely at the position.
//
// Create a Transform object with the Position function. This sets the position variable, which is the
// most important. Then use methods, like Scale and Rotate to change scale, rotation and achor. The order
// in which you apply these methods is irrelevant.
//
//   pixel.Position(pixel.V(100, 100)).Rotate(math.Pi / 3).Scale(1.5)
type Transform struct {
	pos, anc, sca Vec
	rot           float64
}

// Position creates a Transformation object with specified position. Anchor is (0, 0), rotation is 0 and scale is 1.
func Position(position Vec) Transform {
	return Transform{
		pos: position,
		sca: V(1, 1),
	}
}

// GetPosition returns the position of a transform.
func (t Transform) GetPosition() Vec {
	return t.pos
}

// GetAnchor returns the anchor of a transform.
func (t Transform) GetAnchor() Vec {
	return t.anc
}

// GetScale returns the scale (2 dimensional) of transform.
func (t Transform) GetScale() Vec {
	return t.sca
}

// GetRotation returns the rotation of a transform (in radians).
func (t Transform) GetRotation() float64 {
	return t.rot
}

// Position sets position.
func (t Transform) Position(position Vec) Transform {
	t.pos = position
	return t
}

// Move adds delta to position.
func (t Transform) Move(delta Vec) Transform {
	t.pos += delta
	return t
}

// Anchor sets anchor. Anchor is the rotation center and will be moved to the position.
func (t Transform) Anchor(anchor Vec) Transform {
	t.anc = anchor
	return t
}

// MoveAnchor adds delta to anchor.
func (t Transform) MoveAnchor(delta Vec) Transform {
	t.anc += delta
	return t
}

// Scale scales the transform by the supplied factor.
//
// Note, that subsequent calls to this method accumulate the final scale factor. Scaling two times by 2 is equivalent
// to scaling once by 4.
func (t Transform) Scale(scale float64) Transform {
	t.sca = t.sca.Scaled(scale)
	return t
}

// ScaleXY scales the transform by the supplied X and Y factor. Note, that scale is applied before rotation.
//
// Note, that subsequent calls to this method accumulate the final scale factor. Scaling two times by 2 is equivalent
// to scaling once by 4.
func (t Transform) ScaleXY(scale Vec) Transform {
	t.sca = V(t.sca.X()*scale.X(), t.sca.Y()*scale.Y())
	return t
}

// Rotate rotates the transform by the supplied angle in radians.
//
// Note, that subsequent calls to this method accumulate the final rotation. Rotating two times by Pi/2 is
// equivalent to rotating once by Pi.
func (t Transform) Rotate(angle float64) Transform {
	t.rot += angle
	return t
}

// Project transforms a vector by a transform.
func (t Transform) Project(v Vec) Vec {
	mat := t.Mat3()
	vec := mgl32.Vec3{float32(v.X()), float32(v.Y()), 1}
	pro := mat.Mul3x1(vec)
	return V(float64(pro.X()), float64(pro.Y()))
}

// Unproject does the inverse operation to Project.
func (t Transform) Unproject(v Vec) Vec {
	mat := t.InvMat3()
	vec := mgl32.Vec3{float32(v.X()), float32(v.Y()), 1}
	unp := mat.Mul3x1(vec)
	return V(float64(unp.X()), float64(unp.Y()))
}

// Mat3 returns a transformation matrix that satisfies previously set transform properties.
func (t Transform) Mat3() mgl32.Mat3 {
	mat := mgl32.Ident3()
	mat = mat.Mul3(mgl32.Translate2D(float32(t.pos.X()), float32(t.pos.Y())))
	mat = mat.Mul3(mgl32.Rotate3DZ(float32(t.rot)))
	mat = mat.Mul3(mgl32.Scale2D(float32(t.sca.X()), float32(t.sca.Y())))
	mat = mat.Mul3(mgl32.Translate2D(float32(-t.anc.X()), float32(-t.anc.Y())))
	return mat
}

// InvMat3 returns an inverse transformation matrix to the matrix returned by Mat3 method.
func (t Transform) InvMat3() mgl32.Mat3 {
	mat := mgl32.Ident3()
	mat = mat.Mul3(mgl32.Translate2D(float32(t.anc.X()), float32(t.anc.Y())))
	mat = mat.Mul3(mgl32.Scale2D(float32(1/t.sca.X()), float32(1/t.sca.Y())))
	mat = mat.Mul3(mgl32.Rotate3DZ(float32(-t.rot)))
	mat = mat.Mul3(mgl32.Translate2D(float32(-t.pos.X()), float32(-t.pos.Y())))
	return mat
}

// Camera is a convenience function, that returns a Transform that acts like a camera.
// Center is the position in the world coordinates, that will be projected onto the center of the screen.
// One unit in world coordinates will be projected onto zoom pixels.
//
// It is possible to apply additional rotations, scales and moves to the returned transform.
func Camera(center, zoom, screenSize Vec) Transform {
	return Position(0).Anchor(center).ScaleXY(2 * zoom).ScaleXY(V(1/screenSize.X(), 1/screenSize.Y()))
}
<|endoftext|>


<commit_before>// Package treeprint provides a simple ASCII tree composing tool.
package treeprint

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
)

type Value interface{}
type MetaValue interface{}

// Tree represents a tree structure with leaf-nodes and branch-nodes.
type Tree interface {
	// AddNode adds a new node to a branch.
	AddNode(v Value) Tree
	// AddMetaNode adds a new node with meta value provided to a branch.
	AddMetaNode(meta MetaValue, v Value) Tree
	// AddBranch adds a new branch node (a level deeper).
	AddBranch(v Value) Tree
	// AddMetaBranch adds a new branch node (a level deeper) with meta value provided.
	AddMetaBranch(meta MetaValue, v Value) Tree
	// Branch converts a leaf-node to a branch-node,
	// applying this on a branch-node does no effect.
	Branch() Tree
	// FindByMeta finds a node whose meta value matches the provided one by reflect.DeepEqual,
	// returns nil if not found.
	FindByMeta(meta MetaValue) Tree
	// FindByValue finds a node whose value matches the provided one by reflect.DeepEqual,
	// returns nil if not found.
	FindByValue(value Value) Tree
	//  returns the last node of a tree
	FindLastNode() Tree
	// String renders the tree or subtree as a string.
	String() string
	// Bytes renders the tree or subtree as byteslice.
	Bytes() []byte

	SetValue(value Value)
}

type node struct {
	Root  *node
	Meta  MetaValue
	Value Value
	Nodes []*node
}

func (n *node) FindLastNode() Tree {
	ns := n.Nodes
	n = ns[len(ns)-1]
	return n
}

func (n *node) AddNode(v Value) Tree {
	n.Nodes = append(n.Nodes, &node{
		Root:  n,
		Value: v,
	})
	if n.Root != nil {
		return n.Root
	}
	return n
}

func (n *node) AddMetaNode(meta MetaValue, v Value) Tree {
	n.Nodes = append(n.Nodes, &node{
		Root:  n,
		Meta:  meta,
		Value: v,
	})
	if n.Root != nil {
		return n.Root
	}
	return n
}

func (n *node) AddBranch(v Value) Tree {
	branch := &node{
		Value: v,
	}
	n.Nodes = append(n.Nodes, branch)
	return branch
}

func (n *node) AddMetaBranch(meta MetaValue, v Value) Tree {
	branch := &node{
		Meta:  meta,
		Value: v,
	}
	n.Nodes = append(n.Nodes, branch)
	return branch
}

func (n *node) Branch() Tree {
	n.Root = nil
	return n
}

func (n *node) FindByMeta(meta MetaValue) Tree {
	for _, node := range n.Nodes {
		if reflect.DeepEqual(node.Meta, meta) {
			return node
		}
		if v := node.FindByMeta(meta); v != nil {
			return v
		}
	}
	return nil
}

func (n *node) FindByValue(value Value) Tree {
	for _, node := range n.Nodes {
		if reflect.DeepEqual(node.Value, value) {
			return node
		}
		if v := node.FindByMeta(value); v != nil {
			return v
		}
	}
	return nil
}

func (n *node) Bytes() []byte {
	buf := new(bytes.Buffer)
	level := 0
	var levelsEnded []int
	if n.Root == nil {
		buf.WriteString(fmt.Sprintf("%v",n.Value))
		buf.WriteByte('\n')
	} else {
		edge := EdgeTypeMid
		if len(n.Nodes) == 0 {
			edge = EdgeTypeEnd
			levelsEnded = append(levelsEnded, level)
		}
		printValues(buf, 0, levelsEnded, edge, n.Meta, n.Value)
	}
	if len(n.Nodes) > 0 {
		printNodes(buf, level, levelsEnded, n.Nodes)
	}
	return buf.Bytes()
}

func (n *node) String() string {
	return string(n.Bytes())
}

func (n *node) SetValue(value Value){
	n.Value = value
}

func printNodes(wr io.Writer,
	level int, levelsEnded []int, nodes []*node) {

	for i, node := range nodes {
		edge := EdgeTypeMid
		if i == len(nodes)-1 {
			levelsEnded = append(levelsEnded, level)
			edge = EdgeTypeEnd
		}
		printValues(wr, level, levelsEnded, edge, node.Meta, node.Value)
		if len(node.Nodes) > 0 {
			printNodes(wr, level+1, levelsEnded, node.Nodes)
		}
	}
}

func printValues(wr io.Writer,
	level int, levelsEnded []int, edge EdgeType, meta MetaValue, val Value) {

	for i := 0; i < level; i++ {
		if isEnded(levelsEnded, i) {
			fmt.Fprint(wr, "    ")
			continue
		}
		fmt.Fprintf(wr, "%s   ", EdgeTypeLink)
	}
	if meta != nil {
		fmt.Fprintf(wr, "%s [%v]  %v\n", edge, meta, val)
		return
	}
	fmt.Fprintf(wr, "%s %v\n", edge, val)
}

func isEnded(levelsEnded []int, level int) bool {
	for _, l := range levelsEnded {
		if l == level {
			return true
		}
	}
	return false
}

type EdgeType string

var (
	EdgeTypeLink  EdgeType = "│"
	EdgeTypeMid   EdgeType = "├──"
	EdgeTypeEnd   EdgeType = "└──"
)

func New() Tree {
	return &node{Value: "."}
}
<commit_msg>Add support for MetaValue in root node<commit_after>// Package treeprint provides a simple ASCII tree composing tool.
package treeprint

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
)

type Value interface{}
type MetaValue interface{}

// Tree represents a tree structure with leaf-nodes and branch-nodes.
type Tree interface {
	// AddNode adds a new node to a branch.
	AddNode(v Value) Tree
	// AddMetaNode adds a new node with meta value provided to a branch.
	AddMetaNode(meta MetaValue, v Value) Tree
	// AddBranch adds a new branch node (a level deeper).
	AddBranch(v Value) Tree
	// AddMetaBranch adds a new branch node (a level deeper) with meta value provided.
	AddMetaBranch(meta MetaValue, v Value) Tree
	// Branch converts a leaf-node to a branch-node,
	// applying this on a branch-node does no effect.
	Branch() Tree
	// FindByMeta finds a node whose meta value matches the provided one by reflect.DeepEqual,
	// returns nil if not found.
	FindByMeta(meta MetaValue) Tree
	// FindByValue finds a node whose value matches the provided one by reflect.DeepEqual,
	// returns nil if not found.
	FindByValue(value Value) Tree
	//  returns the last node of a tree
	FindLastNode() Tree
	// String renders the tree or subtree as a string.
	String() string
	// Bytes renders the tree or subtree as byteslice.
	Bytes() []byte

	SetValue(value Value)
	SetMetaValue(meta MetaValue)
}

type node struct {
	Root  *node
	Meta  MetaValue
	Value Value
	Nodes []*node
}

func (n *node) FindLastNode() Tree {
	ns := n.Nodes
	n = ns[len(ns)-1]
	return n
}

func (n *node) AddNode(v Value) Tree {
	n.Nodes = append(n.Nodes, &node{
		Root:  n,
		Value: v,
	})
	if n.Root != nil {
		return n.Root
	}
	return n
}

func (n *node) AddMetaNode(meta MetaValue, v Value) Tree {
	n.Nodes = append(n.Nodes, &node{
		Root:  n,
		Meta:  meta,
		Value: v,
	})
	if n.Root != nil {
		return n.Root
	}
	return n
}

func (n *node) AddBranch(v Value) Tree {
	branch := &node{
		Value: v,
	}
	n.Nodes = append(n.Nodes, branch)
	return branch
}

func (n *node) AddMetaBranch(meta MetaValue, v Value) Tree {
	branch := &node{
		Meta:  meta,
		Value: v,
	}
	n.Nodes = append(n.Nodes, branch)
	return branch
}

func (n *node) Branch() Tree {
	n.Root = nil
	return n
}

func (n *node) FindByMeta(meta MetaValue) Tree {
	for _, node := range n.Nodes {
		if reflect.DeepEqual(node.Meta, meta) {
			return node
		}
		if v := node.FindByMeta(meta); v != nil {
			return v
		}
	}
	return nil
}

func (n *node) FindByValue(value Value) Tree {
	for _, node := range n.Nodes {
		if reflect.DeepEqual(node.Value, value) {
			return node
		}
		if v := node.FindByMeta(value); v != nil {
			return v
		}
	}
	return nil
}

func (n *node) Bytes() []byte {
	buf := new(bytes.Buffer)
	level := 0
	var levelsEnded []int
	if n.Root == nil {
		if n.Meta != nil {
			buf.WriteString(fmt.Sprintf("[%v]  %v", n.Meta, n.Value))
		} else {
			buf.WriteString(fmt.Sprintf("%v",n.Value))
		}
		buf.WriteByte('\n')
	} else {
		edge := EdgeTypeMid
		if len(n.Nodes) == 0 {
			edge = EdgeTypeEnd
			levelsEnded = append(levelsEnded, level)
		}
		printValues(buf, 0, levelsEnded, edge, n.Meta, n.Value)
	}
	if len(n.Nodes) > 0 {
		printNodes(buf, level, levelsEnded, n.Nodes)
	}
	return buf.Bytes()
}

func (n *node) String() string {
	return string(n.Bytes())
}

func (n *node) SetValue(value Value){
	n.Value = value
}

func (n *node) SetMetaValue(meta MetaValue){
	n.Meta = meta
}

func printNodes(wr io.Writer,
	level int, levelsEnded []int, nodes []*node) {

	for i, node := range nodes {
		edge := EdgeTypeMid
		if i == len(nodes)-1 {
			levelsEnded = append(levelsEnded, level)
			edge = EdgeTypeEnd
		}
		printValues(wr, level, levelsEnded, edge, node.Meta, node.Value)
		if len(node.Nodes) > 0 {
			printNodes(wr, level+1, levelsEnded, node.Nodes)
		}
	}
}

func printValues(wr io.Writer,
	level int, levelsEnded []int, edge EdgeType, meta MetaValue, val Value) {

	for i := 0; i < level; i++ {
		if isEnded(levelsEnded, i) {
			fmt.Fprint(wr, "    ")
			continue
		}
		fmt.Fprintf(wr, "%s   ", EdgeTypeLink)
	}
	if meta != nil {
		fmt.Fprintf(wr, "%s [%v]  %v\n", edge, meta, val)
		return
	}
	fmt.Fprintf(wr, "%s %v\n", edge, val)
}

func isEnded(levelsEnded []int, level int) bool {
	for _, l := range levelsEnded {
		if l == level {
			return true
		}
	}
	return false
}

type EdgeType string

var (
	EdgeTypeLink  EdgeType = "│"
	EdgeTypeMid   EdgeType = "├──"
	EdgeTypeEnd   EdgeType = "└──"
)

func New() Tree {
	return &node{Value: "."}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 - The TXTdirect Authors
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 txtdirect

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
)

const (
	basezone        = "_redirect"
	defaultSub      = "www"
	defaultProtocol = "https"
)

type record struct {
	Version string
	To      string
	Code    int
	Type    string
	Vcs     string
	From    string
	Default string
}

// Config contains the middleware's configuration
type Config struct {
	Enable   []string
	Redirect string
}

func (r *record) Parse(str string) error {
	s := strings.Split(str, ";")
	for _, l := range s {
		switch {
		case strings.HasPrefix(l, "v="):
			l = strings.TrimPrefix(l, "v=")
			r.Version = l
			if r.Version != "txtv0" {
				return fmt.Errorf("unhandled version '%s'", r.Version)
			}
			log.Print("WARN: txtv0 is not suitable for production")

		case strings.HasPrefix(l, "to="):
			l = strings.TrimPrefix(l, "to=")
			r.To = l

		case strings.HasPrefix(l, "code="):
			l = strings.TrimPrefix(l, "code=")
			i, err := strconv.Atoi(l)
			if err != nil {
				return fmt.Errorf("could not parse status code: %s", err)
			}
			r.Code = i

		case strings.HasPrefix(l, "type="):
			l = strings.TrimPrefix(l, "type=")
			r.Type = l

		case strings.HasPrefix(l, "vcs="):
			l = strings.TrimPrefix(l, "vcs=")
			r.Vcs = l

		case strings.HasPrefix(l, "default="):
			l = strings.TrimPrefix(l, "default=")
			r.Default = l

		default:
			if r.To != "" {
				return fmt.Errorf("multiple values without keys")
			}
			r.To = l
		}
	}

	if r.Code == 0 {
		r.Code = 301
	}

	if r.Type == "" {
		r.Type = "host"
	}

	return nil
}

func getBaseTarget(rec record) (string, int) {
	return rec.To, rec.Code
}

func getRecord(host, path string) (record, error) {
	if strings.Contains(host, ":") {
		hostSlice := strings.Split(host, ":")
		host = hostSlice[0]
	}
	zone := strings.Join([]string{basezone, host}, ".")

	var absoluteZone string
	if strings.HasSuffix(zone, ".") {
		absoluteZone = zone
	} else {
		absoluteZone = strings.Join([]string{zone, "."}, "")
	}
	s, err := net.LookupTXT(absoluteZone)

	if err != nil {
		return record{}, fmt.Errorf("could not get TXT record: %s", err)
	}

	rec := record{}
	if err = rec.Parse(s[0]); err != nil {
		return rec, fmt.Errorf("could not parse record: %s", err)
	}

	if rec.To == "" {
		s := []string{defaultProtocol, "://", defaultSub, ".", host}
		rec.To = strings.Join(s, "")
	}

	return rec, nil
}

func contains(array []string, word string) bool {
	for _, w := range array {
		if w == word {
			return true
		}
	}
	return false
}

// Redirect the request depending on the redirect record found
func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
	host := r.Host
	path := r.URL.Path

	bl := make(map[string]bool)
	bl["/favicon.ico"] = true

	if bl[path] {
		http.Redirect(w, r, strings.Join([]string{host, path}, ""), 200)
		return nil
	}

	rec, err := getRecord(host, path)
	if err != nil {
		if strings.HasSuffix(err.Error(), "no such host") {
			if c.Redirect != "" {
				http.Redirect(w, r, c.Redirect, http.StatusMovedPermanently)
				return nil
			}
			if contains(c.Enable, "www") {
				s := []string{defaultProtocol, "://", defaultSub, ".", host}
				http.Redirect(w, r, strings.Join(s, ""), 301)
				return nil
			}
			http.NotFound(w, r)
			return nil
		}
		return err
	}

	if !contains(c.Enable, rec.Type) {
		return fmt.Errorf("option disabled")
	}

	fallback, code := getBaseTarget(rec)

	if rec.Type == "path" {
		if path == "/" {
			http.Redirect(w, r, rec.Default, rec.Code)
			return nil
		}
		if path != "" {
			zone, from, _ := zoneFromPath(host, path, rec)
			rec, err = getFinalRecord(zone, from)
			if err != nil {
				if fallback != "" {
					http.Redirect(w, r, fallback, code)
				} else if c.Redirect != "" {
					http.Redirect(w, r, c.Redirect, 403)
				}
				http.NotFound(w, r)
				return err
			}
		}
	}

	if rec.Type == "host" {
		to, code := getBaseTarget(rec)
		http.Redirect(w, r, to, code)
		return nil
	}

	if rec.Type == "gometa" {
		return gometa(w, rec, host, path)
	}

	return fmt.Errorf("record type %s unsupported", rec.Type)
}
<commit_msg>Rename Default to Root in record<commit_after>/*
Copyright 2017 - The TXTdirect Authors
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 txtdirect

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
)

const (
	basezone        = "_redirect"
	defaultSub      = "www"
	defaultProtocol = "https"
)

type record struct {
	Version string
	To      string
	Code    int
	Type    string
	Vcs     string
	From    string
	Root    string
}

// Config contains the middleware's configuration
type Config struct {
	Enable   []string
	Redirect string
}

func (r *record) Parse(str string) error {
	s := strings.Split(str, ";")
	for _, l := range s {
		switch {
		case strings.HasPrefix(l, "v="):
			l = strings.TrimPrefix(l, "v=")
			r.Version = l
			if r.Version != "txtv0" {
				return fmt.Errorf("unhandled version '%s'", r.Version)
			}
			log.Print("WARN: txtv0 is not suitable for production")

		case strings.HasPrefix(l, "to="):
			l = strings.TrimPrefix(l, "to=")
			r.To = l

		case strings.HasPrefix(l, "code="):
			l = strings.TrimPrefix(l, "code=")
			i, err := strconv.Atoi(l)
			if err != nil {
				return fmt.Errorf("could not parse status code: %s", err)
			}
			r.Code = i

		case strings.HasPrefix(l, "type="):
			l = strings.TrimPrefix(l, "type=")
			r.Type = l

		case strings.HasPrefix(l, "vcs="):
			l = strings.TrimPrefix(l, "vcs=")
			r.Vcs = l

		case strings.HasPrefix(l, "root="):
			l = strings.TrimPrefix(l, "root=")
			r.Root = l

		default:
			if r.To != "" {
				return fmt.Errorf("multiple values without keys")
			}
			r.To = l
		}
	}

	if r.Code == 0 {
		r.Code = 301
	}

	if r.Type == "" {
		r.Type = "host"
	}

	return nil
}

func getBaseTarget(rec record) (string, int) {
	return rec.To, rec.Code
}

func getRecord(host, path string) (record, error) {
	if strings.Contains(host, ":") {
		hostSlice := strings.Split(host, ":")
		host = hostSlice[0]
	}
	zone := strings.Join([]string{basezone, host}, ".")

	var absoluteZone string
	if strings.HasSuffix(zone, ".") {
		absoluteZone = zone
	} else {
		absoluteZone = strings.Join([]string{zone, "."}, "")
	}
	s, err := net.LookupTXT(absoluteZone)

	if err != nil {
		return record{}, fmt.Errorf("could not get TXT record: %s", err)
	}

	rec := record{}
	if err = rec.Parse(s[0]); err != nil {
		return rec, fmt.Errorf("could not parse record: %s", err)
	}

	if rec.To == "" {
		s := []string{defaultProtocol, "://", defaultSub, ".", host}
		rec.To = strings.Join(s, "")
	}

	return rec, nil
}

func contains(array []string, word string) bool {
	for _, w := range array {
		if w == word {
			return true
		}
	}
	return false
}

// Redirect the request depending on the redirect record found
func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
	host := r.Host
	path := r.URL.Path

	bl := make(map[string]bool)
	bl["/favicon.ico"] = true

	if bl[path] {
		http.Redirect(w, r, strings.Join([]string{host, path}, ""), 200)
		return nil
	}

	rec, err := getRecord(host, path)
	if err != nil {
		if strings.HasSuffix(err.Error(), "no such host") {
			if c.Redirect != "" {
				http.Redirect(w, r, c.Redirect, http.StatusMovedPermanently)
				return nil
			}
			if contains(c.Enable, "www") {
				s := []string{defaultProtocol, "://", defaultSub, ".", host}
				http.Redirect(w, r, strings.Join(s, ""), 301)
				return nil
			}
			http.NotFound(w, r)
			return nil
		}
		return err
	}

	if !contains(c.Enable, rec.Type) {
		return fmt.Errorf("option disabled")
	}

	fallback, code := getBaseTarget(rec)

	if rec.Type == "path" {
		if path == "/" {
			http.Redirect(w, r, rec.Root, rec.Code)
			return nil
		}
		if path != "" {
			zone, from, _ := zoneFromPath(host, path, rec)
			rec, err = getFinalRecord(zone, from)
			if err != nil {
				if fallback != "" {
					http.Redirect(w, r, fallback, code)
				} else if c.Redirect != "" {
					http.Redirect(w, r, c.Redirect, 403)
				}
				http.NotFound(w, r)
				return err
			}
		}
	}

	if rec.Type == "host" {
		to, code := getBaseTarget(rec)
		http.Redirect(w, r, to, code)
		return nil
	}

	if rec.Type == "gometa" {
		return gometa(w, rec, host, path)
	}

	return fmt.Errorf("record type %s unsupported", rec.Type)
}
<|endoftext|>