<commit_before>// Package with a LightStrand that implementes the hue.API interface. It maps
// light ids to socket locations on a strand of lights.
package strand

import (
	"errors"
	"fmt"
	"github.com/bcurren/go-hue"
	"strconv"
	"strings"
)

// Structure that holds the mapping from socket id to light id. This implements
// the hue.API interface so it can be used as a drop in replacement.
type LightStrand struct {
	API    hue.API
	Length int
	Lights *TwoWayMap
}

// Create a new light strand with the given length and hue.API to delegate to.
func NewLightStrand(length int, api hue.API) *LightStrand {
	var lightStrand LightStrand
	lightStrand.API = api
	lightStrand.Length = length
	lightStrand.Lights = NewTwoWayMap()

	return &lightStrand
}

// Create a new light strand with the given length and hue.API to delegate to.
func NewLightStrandWithMap(length int, api hue.API, initMap map[string]string) *LightStrand {
	var lightStrand LightStrand
	lightStrand.API = api
	lightStrand.Length = length
	lightStrand.Lights = LoadTwoWayMap(initMap)

	return &lightStrand
}

func (lg *LightStrand) IsMappedSocketId(socketId string) bool {
	if lg.Lights.GetValue(socketId) != "" {
		return true
	}
	return false
}

func (lg *LightStrand) ChangeLength(newLength int) {
	oldLength := lg.Length
	lg.Length = newLength

	for i := newLength + 1; i <= oldLength; i++ {
		socketId := strconv.Itoa(i)
		lg.Lights.DeleteWithKey(socketId)
	}
}

func (lg *LightStrand) CleanInvalidLightIds() error {
	lights, err := lg.API.GetLights()
	if err != nil {
		return err
	}

	lg.cleanInvalidMappedLightIds(lights)
	return nil
}

// An interactive way of mapping all unmapped light bulbs on the hue bridge. This
// function does the following:
//
// 1. Turn all lights normal state
// 2. For each unmapped light
//   a. Turn the bulb selectedState
//   b. Call socketToLightFunc - The implementation should return the socket id for
//      the unmapped light. If 'x' returned, skip mapping the bulb.
//   c. Map the bulb to the socket id
//   d. Turn the buld normal state and continue
//
// This should be used to interactively prompt a person to map a light to a position
// in the strand.
func (lg *LightStrand) MapUnmappedLights(normalState, selectedState *hue.LightState,
	socketToLightFunc func(string) string) error {

	unmappedLightIds, err := lg.GetUnmappedLightIds()
	if err != nil {
		return err
	}

	for _, unmappedLightId := range unmappedLightIds {
		// Turn new unmapped light selected state
		err = lg.API.SetLightState(unmappedLightId, selectedState)
		if err != nil {
			return err
		}

		// Update the map. Skip socket ids 'x'.
		socketId := socketToLightFunc(unmappedLightId)
		if "X" != strings.ToUpper(socketId) || socketId == "" {
			if !lg.validSocketId(socketId) {
				return errors.New(fmt.Sprintf("Invalid socket id provided '%s'.", socketId))
			}
			lg.Lights.Set(socketId, unmappedLightId)
		}

		// Turn newly mapped light to normal color
		err = lg.API.SetLightState(unmappedLightId, normalState)
		if err != nil {
			return err
		}
	}

	err = lg.API.SetGroupState(hue.AllLightsGroupId, normalState)
	if err != nil {
		return err
	}

	return nil
}

// Get a list of the unmapped light ids.
func (lg *LightStrand) GetUnmappedLightIds() ([]string, error) {
	lights, err := lg.API.GetLights()
	if err != nil {
		return nil, err
	}

	lg.cleanInvalidMappedLightIds(lights)
	unmappedLightIds := lg.getUnmappedLightIds(lights)

	return unmappedLightIds, nil
}

func (lg *LightStrand) GetMap() map[string]string {
	return lg.Lights.Normal
}

func (lg *LightStrand) cleanInvalidMappedLightIds(allHueLights []hue.Light) {
	allMappedLightIds := lg.Lights.GetValues()

	for _, mappedLightId := range allMappedLightIds {
		invalidLightId := true
		for _, hueLight := range allHueLights {
			if hueLight.Id == mappedLightId {
				invalidLightId = false
				break
			}
		}
		if invalidLightId {
			lg.Lights.DeleteWithValue(mappedLightId)
		}
	}
}

func (lg *LightStrand) getUnmappedLightIds(allHueLights []hue.Light) []string {
	allMappedLightIds := lg.Lights.GetValues()

	unmappedLights := make([]string, 0, 5)
	for _, hueLight := range allHueLights {
		alreadyMapped := false
		for _, mappedLightId := range allMappedLightIds {
			if hueLight.Id == mappedLightId {
				alreadyMapped = true
				break
			}
		}
		if !alreadyMapped {
			unmappedLights = append(unmappedLights, hueLight.Id)
		}
	}

	return unmappedLights
}

func (lg *LightStrand) validSocketId(socketId string) bool {
	socketIdAsInt, err := strconv.Atoi(socketId)
	if err != nil {
		return false
	}

	if socketIdAsInt <= 0 || socketIdAsInt > lg.Length {
		return false
	}

	return true
}
<commit_msg>turn all lights to bg state before mapping<commit_after>// Package with a LightStrand that implementes the hue.API interface. It maps
// light ids to socket locations on a strand of lights.
package strand

import (
	"errors"
	"fmt"
	"github.com/bcurren/go-hue"
	"strconv"
	"strings"
)

// Structure that holds the mapping from socket id to light id. This implements
// the hue.API interface so it can be used as a drop in replacement.
type LightStrand struct {
	API    hue.API
	Length int
	Lights *TwoWayMap
}

// Create a new light strand with the given length and hue.API to delegate to.
func NewLightStrand(length int, api hue.API) *LightStrand {
	var lightStrand LightStrand
	lightStrand.API = api
	lightStrand.Length = length
	lightStrand.Lights = NewTwoWayMap()

	return &lightStrand
}

// Create a new light strand with the given length and hue.API to delegate to.
func NewLightStrandWithMap(length int, api hue.API, initMap map[string]string) *LightStrand {
	var lightStrand LightStrand
	lightStrand.API = api
	lightStrand.Length = length
	lightStrand.Lights = LoadTwoWayMap(initMap)

	return &lightStrand
}

func (lg *LightStrand) IsMappedSocketId(socketId string) bool {
	if lg.Lights.GetValue(socketId) != "" {
		return true
	}
	return false
}

func (lg *LightStrand) ChangeLength(newLength int) {
	oldLength := lg.Length
	lg.Length = newLength

	for i := newLength + 1; i <= oldLength; i++ {
		socketId := strconv.Itoa(i)
		lg.Lights.DeleteWithKey(socketId)
	}
}

func (lg *LightStrand) CleanInvalidLightIds() error {
	lights, err := lg.API.GetLights()
	if err != nil {
		return err
	}

	lg.cleanInvalidMappedLightIds(lights)
	return nil
}

// An interactive way of mapping all unmapped light bulbs on the hue bridge. This
// function does the following:
//
// 1. Turn all lights normal state
// 2. For each unmapped light
//   a. Turn the bulb selectedState
//   b. Call socketToLightFunc - The implementation should return the socket id for
//      the unmapped light. If 'x' returned, skip mapping the bulb.
//   c. Map the bulb to the socket id
//   d. Turn the buld normal state and continue
//
// This should be used to interactively prompt a person to map a light to a position
// in the strand.
func (lg *LightStrand) MapUnmappedLights(normalState, selectedState *hue.LightState,
	socketToLightFunc func(string) string) error {

	unmappedLightIds, err := lg.GetUnmappedLightIds()
	if err != nil {
		return err
	}

	err = lg.API.SetGroupState(hue.AllLightsGroupId, normalState)
	if err != nil {
		return err
	}

	for _, unmappedLightId := range unmappedLightIds {
		// Turn new unmapped light selected state
		err = lg.API.SetLightState(unmappedLightId, selectedState)
		if err != nil {
			return err
		}

		// Update the map. Skip socket ids 'x'.
		socketId := socketToLightFunc(unmappedLightId)
		if "X" != strings.ToUpper(socketId) || socketId == "" {
			if !lg.validSocketId(socketId) {
				return errors.New(fmt.Sprintf("Invalid socket id provided '%s'.", socketId))
			}
			lg.Lights.Set(socketId, unmappedLightId)
		}

		// Turn newly mapped light to normal color
		err = lg.API.SetLightState(unmappedLightId, normalState)
		if err != nil {
			return err
		}
	}

	err = lg.API.SetGroupState(hue.AllLightsGroupId, normalState)
	if err != nil {
		return err
	}

	return nil
}

// Get a list of the unmapped light ids.
func (lg *LightStrand) GetUnmappedLightIds() ([]string, error) {
	lights, err := lg.API.GetLights()
	if err != nil {
		return nil, err
	}

	lg.cleanInvalidMappedLightIds(lights)
	unmappedLightIds := lg.getUnmappedLightIds(lights)

	return unmappedLightIds, nil
}

func (lg *LightStrand) GetMap() map[string]string {
	return lg.Lights.Normal
}

func (lg *LightStrand) cleanInvalidMappedLightIds(allHueLights []hue.Light) {
	allMappedLightIds := lg.Lights.GetValues()

	for _, mappedLightId := range allMappedLightIds {
		invalidLightId := true
		for _, hueLight := range allHueLights {
			if hueLight.Id == mappedLightId {
				invalidLightId = false
				break
			}
		}
		if invalidLightId {
			lg.Lights.DeleteWithValue(mappedLightId)
		}
	}
}

func (lg *LightStrand) getUnmappedLightIds(allHueLights []hue.Light) []string {
	allMappedLightIds := lg.Lights.GetValues()

	unmappedLights := make([]string, 0, 5)
	for _, hueLight := range allHueLights {
		alreadyMapped := false
		for _, mappedLightId := range allMappedLightIds {
			if hueLight.Id == mappedLightId {
				alreadyMapped = true
				break
			}
		}
		if !alreadyMapped {
			unmappedLights = append(unmappedLights, hueLight.Id)
		}
	}

	return unmappedLights
}

func (lg *LightStrand) validSocketId(socketId string) bool {
	socketIdAsInt, err := strconv.Atoi(socketId)
	if err != nil {
		return false
	}

	if socketIdAsInt <= 0 || socketIdAsInt > lg.Length {
		return false
	}

	return true
}
<|endoftext|>


<commit_before>package mustache

import (
    "os"
    "path"
    "strings"
    "testing"
)

type Test struct {
    tmpl     string
    context  interface{}
    expected string
}

type Data struct {
    A   bool
    B   string
}

type User struct {
    Name string
    Id   int64
}

type settings struct {
    Allow bool
}

func (u User) Func1() string {
    return u.Name
}

func (u *User) Func2() string {
    return u.Name
}

func (u *User) Func3() (map[string]string, error) {
    return map[string]string{"name": u.Name}, nil
}

func (u *User) Func4() (map[string]string, error) {
    return nil, nil
}

func (u *User) Func5() (*settings, error) {
    return &settings{true}, nil
}

func (u *User) Func6() ([]interface{}, error) {
    var v []interface{}
    v = append(v, &settings{true})
    return v, nil
}

func (u User) Truefunc1() bool {
    return true
}

func (u *User) Truefunc2() bool {
    return true
}

func makeVector(n int) []interface{} {
    var v []interface{}
    for i := 0; i < n; i++ {
        v = append(v, &User{"Mike", 1})
    }
    return v
}

type Category struct {
    Tag         string
    Description string
}

func (c Category) DisplayName() string {
    return c.Tag + " - " + c.Description
}

var tests = []Test{
    {`hello world`, nil, "hello world"},
    {`hello {{name}}`, map[string]string{"name": "world"}, "hello world"},
    {`{{var}}`, map[string]string{"var": "5 > 2"}, "5 > 2"},
    {`{{{var}}}`, map[string]string{"var": "5 > 2"}, "5 > 2"},
    {`{{a}}{{b}}{{c}}{{d}}`, map[string]string{"a": "a", "b": "b", "c": "c", "d": "d"}, "abcd"},
    {`0{{a}}1{{b}}23{{c}}456{{d}}89`, map[string]string{"a": "a", "b": "b", "c": "c", "d": "d"}, "0a1b23c456d89"},
    {`hello {{! comment }}world`, map[string]string{}, "hello world"},
    {`{{ a }}{{=<% %>=}}<%b %><%={{ }}=%>{{ c }}`, map[string]string{"a": "a", "b": "b", "c": "c"}, "abc"},
    {`{{ a }}{{= <% %> =}}<%b %><%= {{ }}=%>{{c}}`, map[string]string{"a": "a", "b": "b", "c": "c"}, "abc"},

    //does not exist
    {`{{dne}}`, map[string]string{"name": "world"}, ""},
    {`{{dne}}`, User{"Mike", 1}, ""},
    {`{{dne}}`, &User{"Mike", 1}, ""},
    {`{{#has}}{{/has}}`, &User{"Mike", 1}, ""},

    //section tests
    {`{{#A}}{{B}}{{/A}}`, Data{true, "hello"}, "hello"},
    {`{{#A}}{{{B}}}{{/A}}`, Data{true, "5 > 2"}, "5 > 2"},
    {`{{#A}}{{B}}{{/A}}`, Data{true, "5 > 2"}, "5 > 2"},
    {`{{#A}}{{B}}{{/A}}`, Data{false, "hello"}, ""},
    {`{{a}}{{#b}}{{b}}{{/b}}{{c}}`, map[string]string{"a": "a", "b": "b", "c": "c"}, "abc"},
    {`{{#A}}{{B}}{{/A}}`, struct {
        A []struct {
            B string
        }
    }{[]struct {
        B string
    }{{"a"}, {"b"}, {"c"}}},
        "abc",
    },
    {`{{#A}}{{b}}{{/A}}`, struct{ A []map[string]string }{[]map[string]string{{"b": "a"}, {"b": "b"}, {"b": "c"}}}, "abc"},

    {`{{#users}}{{Name}}{{/users}}`, map[string]interface{}{"users": []User{{"Mike", 1}}}, "Mike"},

    {`{{#users}}gone{{Name}}{{/users}}`, map[string]interface{}{"users": nil}, ""},
    {`{{#users}}gone{{Name}}{{/users}}`, map[string]interface{}{"users": (*User)(nil)}, ""},
    {`{{#users}}gone{{Name}}{{/users}}`, map[string]interface{}{"users": []User{}}, ""},

    {`{{#users}}{{Name}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, "Mike"},
    {`{{#users}}{{Name}}{{/users}}`, map[string]interface{}{"users": []interface{}{&User{"Mike", 12}}}, "Mike"},
    {`{{#users}}{{Name}}{{/users}}`, map[string]interface{}{"users": makeVector(1)}, "Mike"},
    {`{{Name}}`, User{"Mike", 1}, "Mike"},
    {`{{Name}}`, &User{"Mike", 1}, "Mike"},
    {"{{#users}}\n{{Name}}\n{{/users}}", map[string]interface{}{"users": makeVector(2)}, "Mike\nMike\n"},
    {"{{#users}}\r\n{{Name}}\r\n{{/users}}", map[string]interface{}{"users": makeVector(2)}, "Mike\r\nMike\r\n"},

    // implicit iterator tests
    {`"{{#list}}({{.}}){{/list}}"`, map[string]interface{}{"list": []string{"a", "b", "c", "d", "e"}}, "\"(a)(b)(c)(d)(e)\""},
    {`"{{#list}}({{.}}){{/list}}"`, map[string]interface{}{"list": []int{1, 2, 3, 4, 5}}, "\"(1)(2)(3)(4)(5)\""},
    {`"{{#list}}({{.}}){{/list}}"`, map[string]interface{}{"list": []float64{1.10, 2.20, 3.30, 4.40, 5.50}}, "\"(1.1)(2.2)(3.3)(4.4)(5.5)\""},

    //inverted section tests
    {`{{a}}{{^b}}b{{/b}}{{c}}`, map[string]string{"a": "a", "c": "c"}, "abc"},
    {`{{a}}{{^b}}b{{/b}}{{c}}`, map[string]interface{}{"a": "a", "b": false, "c": "c"}, "abc"},
    {`{{^a}}b{{/a}}`, map[string]interface{}{"a": false}, "b"},
    {`{{^a}}b{{/a}}`, map[string]interface{}{"a": true}, ""},
    {`{{^a}}b{{/a}}`, map[string]interface{}{"a": "nonempty string"}, ""},
    {`{{^a}}b{{/a}}`, map[string]interface{}{"a": []string{}}, "b"},

    //function tests
    {`{{#users}}{{Func1}}{{/users}}`, map[string]interface{}{"users": []User{{"Mike", 1}}}, "Mike"},
    {`{{#users}}{{Func1}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, "Mike"},
    {`{{#users}}{{Func2}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, "Mike"},

    {`{{#users}}{{#Func3}}{{name}}{{/Func3}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, "Mike"},
    {`{{#users}}{{#Func4}}{{name}}{{/Func4}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, ""},
    {`{{#Truefunc1}}abcd{{/Truefunc1}}`, User{"Mike", 1}, "abcd"},
    {`{{#Truefunc1}}abcd{{/Truefunc1}}`, &User{"Mike", 1}, "abcd"},
    {`{{#Truefunc2}}abcd{{/Truefunc2}}`, &User{"Mike", 1}, "abcd"},
    {`{{#Func5}}{{#Allow}}abcd{{/Allow}}{{/Func5}}`, &User{"Mike", 1}, "abcd"},
    {`{{#user}}{{#Func5}}{{#Allow}}abcd{{/Allow}}{{/Func5}}{{/user}}`, map[string]interface{}{"user": &User{"Mike", 1}}, "abcd"},
    {`{{#user}}{{#Func6}}{{#Allow}}abcd{{/Allow}}{{/Func6}}{{/user}}`, map[string]interface{}{"user": &User{"Mike", 1}}, "abcd"},

    //context chaining
    {`hello {{#section}}{{name}}{{/section}}`, map[string]interface{}{"section": map[string]string{"name": "world"}}, "hello world"},
    {`hello {{#section}}{{name}}{{/section}}`, map[string]interface{}{"name": "bob", "section": map[string]string{"name": "world"}}, "hello world"},
    {`hello {{#bool}}{{#section}}{{name}}{{/section}}{{/bool}}`, map[string]interface{}{"bool": true, "section": map[string]string{"name": "world"}}, "hello world"},
    {`{{#users}}{{canvas}}{{/users}}`, map[string]interface{}{"canvas": "hello", "users": []User{{"Mike", 1}}}, "hello"},
    {`{{#categories}}{{DisplayName}}{{/categories}}`, map[string][]*Category{
        "categories": {&Category{"a", "b"}},
    }, "a - b"},
}

func TestBasic(t *testing.T) {
    for _, test := range tests {
        output := Render(test.tmpl, test.context)
        if output != test.expected {
            t.Fatalf("%q expected %q got %q", test.tmpl, test.expected, output)
        }
    }
}

func TestFile(t *testing.T) {
    filename := path.Join(path.Join(os.Getenv("PWD"), "tests"), "test1.mustache")
    expected := "hello world"
    output := RenderFile(filename, map[string]string{"name": "world"})
    if output != expected {
        t.Fatalf("testfile expected %q got %q", expected, output)
    }
}

func TestPartial(t *testing.T) {
    filename := path.Join(path.Join(os.Getenv("PWD"), "tests"), "test2.mustache")
    println(filename)
    expected := "hello world"
    output := RenderFile(filename, map[string]string{"Name": "world"})
    if output != expected {
        t.Fatalf("testpartial expected %q got %q", expected, output)
    }
}

/*
func TestSectionPartial(t *testing.T) {
    filename := path.Join(path.Join(os.Getenv("PWD"), "tests"), "test3.mustache")
    expected := "Mike\nJoe\n"
    context := map[string]interface{}{"users": []User{{"Mike", 1}, {"Joe", 2}}}
    output := RenderFile(filename, context)
    if output != expected {
        t.Fatalf("testSectionPartial expected %q got %q", expected, output)
    }
}
*/
func TestMultiContext(t *testing.T) {
    output := Render(`{{hello}} {{World}}`, map[string]string{"hello": "hello"}, struct{ World string }{"world"})
    output2 := Render(`{{hello}} {{World}}`, struct{ World string }{"world"}, map[string]string{"hello": "hello"})
    if output != "hello world" || output2 != "hello world" {
        t.Fatalf("TestMultiContext expected %q got %q", "hello world", output)
    }
}

var malformed = []Test{
    {`{{#a}}{{}}{{/a}}`, Data{true, "hello"}, "empty tag"},
    {`{{}}`, nil, "empty tag"},
    {`{{}`, nil, "unmatched open tag"},
    {`{{`, nil, "unmatched open tag"},
}

func TestMalformed(t *testing.T) {
    for _, test := range malformed {
        output := Render(test.tmpl, test.context)
        if strings.Index(output, test.expected) == -1 {
            t.Fatalf("%q expected %q in error %q", test.tmpl, test.expected, output)
        }
    }
}

type LayoutTest struct {
    layout   string
    tmpl     string
    context  interface{}
    expected string
}

var layoutTests = []LayoutTest{
    {`Header {{content}} Footer`, `Hello World`, nil, `Header Hello World Footer`},
    {`Header {{content}} Footer`, `Hello {{s}}`, map[string]string{"s": "World"}, `Header Hello World Footer`},
    {`Header {{content}} Footer`, `Hello {{content}}`, map[string]string{"content": "World"}, `Header Hello World Footer`},
    {`Header {{extra}} {{content}} Footer`, `Hello {{content}}`, map[string]string{"content": "World", "extra": "extra"}, `Header extra Hello World Footer`},
    {`Header {{content}} {{content}} Footer`, `Hello {{content}}`, map[string]string{"content": "World"}, `Header Hello World Hello World Footer`},
}

func TestLayout(t *testing.T) {
    for _, test := range layoutTests {
        output := RenderInLayout(test.tmpl, test.layout, test.context)
        if output != test.expected {
            t.Fatalf("%q expected %q got %q", test.tmpl, test.expected, output)
        }
    }
}
<commit_msg>Test for bad syntax<commit_after>package mustache

import (
    "os"
    "path"
    "strings"
    "testing"
)

type Test struct {
    tmpl     string
    context  interface{}
    expected string
}

type Data struct {
    A   bool
    B   string
}

type User struct {
    Name string
    Id   int64
}

type settings struct {
    Allow bool
}

func (u User) Func1() string {
    return u.Name
}

func (u *User) Func2() string {
    return u.Name
}

func (u *User) Func3() (map[string]string, error) {
    return map[string]string{"name": u.Name}, nil
}

func (u *User) Func4() (map[string]string, error) {
    return nil, nil
}

func (u *User) Func5() (*settings, error) {
    return &settings{true}, nil
}

func (u *User) Func6() ([]interface{}, error) {
    var v []interface{}
    v = append(v, &settings{true})
    return v, nil
}

func (u User) Truefunc1() bool {
    return true
}

func (u *User) Truefunc2() bool {
    return true
}

func makeVector(n int) []interface{} {
    var v []interface{}
    for i := 0; i < n; i++ {
        v = append(v, &User{"Mike", 1})
    }
    return v
}

type Category struct {
    Tag         string
    Description string
}

func (c Category) DisplayName() string {
    return c.Tag + " - " + c.Description
}

var tests = []Test{
    {`hello world`, nil, "hello world"},
    {`hello {{name}}`, map[string]string{"name": "world"}, "hello world"},
    {`{{var}}`, map[string]string{"var": "5 > 2"}, "5 > 2"},
    {`{{{var}}}`, map[string]string{"var": "5 > 2"}, "5 > 2"},
    {`{{a}}{{b}}{{c}}{{d}}`, map[string]string{"a": "a", "b": "b", "c": "c", "d": "d"}, "abcd"},
    {`0{{a}}1{{b}}23{{c}}456{{d}}89`, map[string]string{"a": "a", "b": "b", "c": "c", "d": "d"}, "0a1b23c456d89"},
    {`hello {{! comment }}world`, map[string]string{}, "hello world"},
    {`{{ a }}{{=<% %>=}}<%b %><%={{ }}=%>{{ c }}`, map[string]string{"a": "a", "b": "b", "c": "c"}, "abc"},
    {`{{ a }}{{= <% %> =}}<%b %><%= {{ }}=%>{{c}}`, map[string]string{"a": "a", "b": "b", "c": "c"}, "abc"},

    //does not exist
    {`{{dne}}`, map[string]string{"name": "world"}, ""},
    {`{{dne}}`, User{"Mike", 1}, ""},
    {`{{dne}}`, &User{"Mike", 1}, ""},
    {`{{#has}}{{/has}}`, &User{"Mike", 1}, ""},

    //section tests
    {`{{#A}}{{B}}{{/A}}`, Data{true, "hello"}, "hello"},
    {`{{#A}}{{{B}}}{{/A}}`, Data{true, "5 > 2"}, "5 > 2"},
    {`{{#A}}{{B}}{{/A}}`, Data{true, "5 > 2"}, "5 > 2"},
    {`{{#A}}{{B}}{{/A}}`, Data{false, "hello"}, ""},
    {`{{a}}{{#b}}{{b}}{{/b}}{{c}}`, map[string]string{"a": "a", "b": "b", "c": "c"}, "abc"},
    {`{{#A}}{{B}}{{/A}}`, struct {
        A []struct {
            B string
        }
    }{[]struct {
        B string
    }{{"a"}, {"b"}, {"c"}}},
        "abc",
    },
    {`{{#A}}{{b}}{{/A}}`, struct{ A []map[string]string }{[]map[string]string{{"b": "a"}, {"b": "b"}, {"b": "c"}}}, "abc"},

    {`{{#users}}{{Name}}{{/users}}`, map[string]interface{}{"users": []User{{"Mike", 1}}}, "Mike"},

    {`{{#users}}gone{{Name}}{{/users}}`, map[string]interface{}{"users": nil}, ""},
    {`{{#users}}gone{{Name}}{{/users}}`, map[string]interface{}{"users": (*User)(nil)}, ""},
    {`{{#users}}gone{{Name}}{{/users}}`, map[string]interface{}{"users": []User{}}, ""},

    {`{{#users}}{{Name}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, "Mike"},
    {`{{#users}}{{Name}}{{/users}}`, map[string]interface{}{"users": []interface{}{&User{"Mike", 12}}}, "Mike"},
    {`{{#users}}{{Name}}{{/users}}`, map[string]interface{}{"users": makeVector(1)}, "Mike"},
    {`{{Name}}`, User{"Mike", 1}, "Mike"},
    {`{{Name}}`, &User{"Mike", 1}, "Mike"},
    {"{{#users}}\n{{Name}}\n{{/users}}", map[string]interface{}{"users": makeVector(2)}, "Mike\nMike\n"},
    {"{{#users}}\r\n{{Name}}\r\n{{/users}}", map[string]interface{}{"users": makeVector(2)}, "Mike\r\nMike\r\n"},

    // implicit iterator tests
    {`"{{#list}}({{.}}){{/list}}"`, map[string]interface{}{"list": []string{"a", "b", "c", "d", "e"}}, "\"(a)(b)(c)(d)(e)\""},
    {`"{{#list}}({{.}}){{/list}}"`, map[string]interface{}{"list": []int{1, 2, 3, 4, 5}}, "\"(1)(2)(3)(4)(5)\""},
    {`"{{#list}}({{.}}){{/list}}"`, map[string]interface{}{"list": []float64{1.10, 2.20, 3.30, 4.40, 5.50}}, "\"(1.1)(2.2)(3.3)(4.4)(5.5)\""},

    //inverted section tests
    {`{{a}}{{^b}}b{{/b}}{{c}}`, map[string]string{"a": "a", "c": "c"}, "abc"},
    {`{{a}}{{^b}}b{{/b}}{{c}}`, map[string]interface{}{"a": "a", "b": false, "c": "c"}, "abc"},
    {`{{^a}}b{{/a}}`, map[string]interface{}{"a": false}, "b"},
    {`{{^a}}b{{/a}}`, map[string]interface{}{"a": true}, ""},
    {`{{^a}}b{{/a}}`, map[string]interface{}{"a": "nonempty string"}, ""},
    {`{{^a}}b{{/a}}`, map[string]interface{}{"a": []string{}}, "b"},

    //function tests
    {`{{#users}}{{Func1}}{{/users}}`, map[string]interface{}{"users": []User{{"Mike", 1}}}, "Mike"},
    {`{{#users}}{{Func1}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, "Mike"},
    {`{{#users}}{{Func2}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, "Mike"},

    {`{{#users}}{{#Func3}}{{name}}{{/Func3}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, "Mike"},
    {`{{#users}}{{#Func4}}{{name}}{{/Func4}}{{/users}}`, map[string]interface{}{"users": []*User{{"Mike", 1}}}, ""},
    {`{{#Truefunc1}}abcd{{/Truefunc1}}`, User{"Mike", 1}, "abcd"},
    {`{{#Truefunc1}}abcd{{/Truefunc1}}`, &User{"Mike", 1}, "abcd"},
    {`{{#Truefunc2}}abcd{{/Truefunc2}}`, &User{"Mike", 1}, "abcd"},
    {`{{#Func5}}{{#Allow}}abcd{{/Allow}}{{/Func5}}`, &User{"Mike", 1}, "abcd"},
    {`{{#user}}{{#Func5}}{{#Allow}}abcd{{/Allow}}{{/Func5}}{{/user}}`, map[string]interface{}{"user": &User{"Mike", 1}}, "abcd"},
    {`{{#user}}{{#Func6}}{{#Allow}}abcd{{/Allow}}{{/Func6}}{{/user}}`, map[string]interface{}{"user": &User{"Mike", 1}}, "abcd"},

    //context chaining
    {`hello {{#section}}{{name}}{{/section}}`, map[string]interface{}{"section": map[string]string{"name": "world"}}, "hello world"},
    {`hello {{#section}}{{name}}{{/section}}`, map[string]interface{}{"name": "bob", "section": map[string]string{"name": "world"}}, "hello world"},
    {`hello {{#bool}}{{#section}}{{name}}{{/section}}{{/bool}}`, map[string]interface{}{"bool": true, "section": map[string]string{"name": "world"}}, "hello world"},
    {`{{#users}}{{canvas}}{{/users}}`, map[string]interface{}{"canvas": "hello", "users": []User{{"Mike", 1}}}, "hello"},
    {`{{#categories}}{{DisplayName}}{{/categories}}`, map[string][]*Category{
        "categories": {&Category{"a", "b"}},
    }, "a - b"},

    //invalid syntax - https://github.com/hoisie/mustache/issues/10
    {`{{#a}}{{#b}}{{/a}}{{/b}}}`, map[string]interface{}{}, "line 1: interleaved closing tag: a"},
}

func TestBasic(t *testing.T) {
    for _, test := range tests {
        output := Render(test.tmpl, test.context)
        if output != test.expected {
            t.Fatalf("%q expected %q got %q", test.tmpl, test.expected, output)
        }
    }
}

func TestFile(t *testing.T) {
    filename := path.Join(path.Join(os.Getenv("PWD"), "tests"), "test1.mustache")
    expected := "hello world"
    output := RenderFile(filename, map[string]string{"name": "world"})
    if output != expected {
        t.Fatalf("testfile expected %q got %q", expected, output)
    }
}

func TestPartial(t *testing.T) {
    filename := path.Join(path.Join(os.Getenv("PWD"), "tests"), "test2.mustache")
    println(filename)
    expected := "hello world"
    output := RenderFile(filename, map[string]string{"Name": "world"})
    if output != expected {
        t.Fatalf("testpartial expected %q got %q", expected, output)
    }
}

/*
func TestSectionPartial(t *testing.T) {
    filename := path.Join(path.Join(os.Getenv("PWD"), "tests"), "test3.mustache")
    expected := "Mike\nJoe\n"
    context := map[string]interface{}{"users": []User{{"Mike", 1}, {"Joe", 2}}}
    output := RenderFile(filename, context)
    if output != expected {
        t.Fatalf("testSectionPartial expected %q got %q", expected, output)
    }
}
*/
func TestMultiContext(t *testing.T) {
    output := Render(`{{hello}} {{World}}`, map[string]string{"hello": "hello"}, struct{ World string }{"world"})
    output2 := Render(`{{hello}} {{World}}`, struct{ World string }{"world"}, map[string]string{"hello": "hello"})
    if output != "hello world" || output2 != "hello world" {
        t.Fatalf("TestMultiContext expected %q got %q", "hello world", output)
    }
}

var malformed = []Test{
    {`{{#a}}{{}}{{/a}}`, Data{true, "hello"}, "empty tag"},
    {`{{}}`, nil, "empty tag"},
    {`{{}`, nil, "unmatched open tag"},
    {`{{`, nil, "unmatched open tag"},
}

func TestMalformed(t *testing.T) {
    for _, test := range malformed {
        output := Render(test.tmpl, test.context)
        if strings.Index(output, test.expected) == -1 {
            t.Fatalf("%q expected %q in error %q", test.tmpl, test.expected, output)
        }
    }
}

type LayoutTest struct {
    layout   string
    tmpl     string
    context  interface{}
    expected string
}

var layoutTests = []LayoutTest{
    {`Header {{content}} Footer`, `Hello World`, nil, `Header Hello World Footer`},
    {`Header {{content}} Footer`, `Hello {{s}}`, map[string]string{"s": "World"}, `Header Hello World Footer`},
    {`Header {{content}} Footer`, `Hello {{content}}`, map[string]string{"content": "World"}, `Header Hello World Footer`},
    {`Header {{extra}} {{content}} Footer`, `Hello {{content}}`, map[string]string{"content": "World", "extra": "extra"}, `Header extra Hello World Footer`},
    {`Header {{content}} {{content}} Footer`, `Hello {{content}}`, map[string]string{"content": "World"}, `Header Hello World Hello World Footer`},
}

func TestLayout(t *testing.T) {
    for _, test := range layoutTests {
        output := RenderInLayout(test.tmpl, test.layout, test.context)
        if output != test.expected {
            t.Fatalf("%q expected %q got %q", test.tmpl, test.expected, output)
        }
    }
}
<|endoftext|>


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

package native

import (
	"math"

	"github.com/gonum/blas"
	"github.com/gonum/blas/blas64"
	"github.com/gonum/lapack"
)

// Dlaexc swaps two adjacent diagonal blocks of order 1 or 2 in an n×n upper
// quasi-triangular matrix T by an orthogonal similarity transformation.
//
// T must be in Schur canonical form, that is, block upper triangular with 1×1
// and 2×2 diagonal blocks; each 2×2 diagonal block has its diagonal elements
// equal and its off-diagonal elements of opposite sign. On return, T will
// contain the updated matrix again in Schur canonical form.
//
// If wantq is true, the transformation is accumulated in the n×n matrix Q,
// otherwise Q is not referenced.
//
// j1 is the index of the first row of the first block. n1 and n2 are the order
// of the first and second block, respectively.
//
// work much have length at least n, otherwise Dlaexc will panic.
//
// If ok is false, the transformed matrix T would be too far from Schur form.
// The blocks are not swapped, and T and Q are not modified.
func (impl Implementation) Dlaexc(wantq bool, n int, t []float64, ldt int, q []float64, ldq int, j1, n1, n2 int, work []float64) (ok bool) {
	checkMatrix(n, n, t, ldt)
	if wantq {
		checkMatrix(n, n, q, ldq)
	}
	if j1 < 0 || n <= j1 {
		panic("lapack: index j1 out of range")
	}
	if len(work) < n {
		panic(badWork)
	}
	if n1 < 0 || 2 < n1 {
		panic("lapack: invalid value of n1")
	}
	if n2 < 0 || 2 < n2 {
		panic("lapack: invalid value of n2")
	}

	if n == 0 || n1 == 0 || n2 == 0 {
		return true
	}
	if j1+n1 >= n {
		// TODO(vladimir-ch): Reference LAPACK does this check whether
		// the start of the second block is in the matrix T. It returns
		// true if it is not and moreover it does not check whether the
		// whole second block fits into T. This does not feel
		// satisfactory. The only caller of Dlaexc is Dtrexc, so if the
		// caller makes sure that this does not happen, we could be
		// stricter here.
		return true
	}

	j2 := j1 + 1
	j3 := j1 + 2

	bi := blas64.Implementation()

	if n1 == 1 && n2 == 1 {
		// Swap two 1×1 blocks.
		t11 := t[j1*ldt+j1]
		t22 := t[j2*ldt+j2]

		// Determine the transformation to perform the interchange.
		cs, sn, _ := impl.Dlartg(t[j1*ldt+j2], t22-t11)

		// Apply transformation to the matrix T.
		if n-j3 > 0 {
			bi.Drot(n-j3, t[j1*ldt+j3:], 1, t[j2*ldt+j3:], 1, cs, sn)
		}
		if j1 > 0 {
			bi.Drot(j1, t[j1:], ldt, t[j2:], ldt, cs, sn)
		}

		t[j1*ldt+j1] = t22
		t[j2*ldt+j2] = t11

		if wantq {
			// Accumulate transformation in the matrix Q.
			bi.Drot(n, q[j1:], ldq, q[j2:], ldq, cs, sn)
		}

		return true
	}

	// Swapping involves at least one 2×2 block.
	//
	// Copy the diagonal block of order n1+n2 to the local array d and
	// compute its norm.
	nd := n1 + n2
	var d [16]float64
	const ldd = 4
	impl.Dlacpy(blas.All, nd, nd, t[j1*ldt+j1:], ldt, d[:], ldd)
	dnorm := impl.Dlange(lapack.MaxAbs, nd, nd, d[:], ldd, work)

	// Compute machine-dependent threshold for test for accepting swap.
	eps := dlamchP
	thresh := math.Max(10*eps*dnorm, dlamchS/eps)

	// Solve T11*X - X*T22 = scale*T12 for X.
	var x [4]float64
	const ldx = 2
	scale, _, _ := impl.Dlasy2(false, false, -1, n1, n2, d[:], ldd, d[n1*ldd+n1:], ldd, d[n1:], ldd, x[:], ldx)

	// Swap the adjacent diagonal blocks.
	switch {
	case n1 == 1 && n2 == 2:
		// Generate elementary reflector H so that
		//  ( scale, X11, X12 ) H = ( 0, 0, * )
		u := [3]float64{scale, x[0], 1}
		_, tau := impl.Dlarfg(3, x[1], u[:2], 1)
		t11 := t[j1*ldt+j1]

		// Perform swap provisionally on diagonal block in d.
		impl.Dlarfx(blas.Left, 3, 3, u[:], tau, d[:], ldd, work)
		impl.Dlarfx(blas.Right, 3, 3, u[:], tau, d[:], ldd, work)

		// Test whether to reject swap.
		if math.Max(math.Abs(d[2*ldd]), math.Max(math.Abs(d[2*ldd+1]), math.Abs(d[2*ldd+2]-t11))) > thresh {
			return false
		}

		// Accept swap: apply transformation to the entire matrix T.
		impl.Dlarfx(blas.Left, 3, n-j1, u[:], tau, t[j1*ldt+j1:], ldt, work)
		impl.Dlarfx(blas.Right, j2+1, 3, u[:], tau, t[j1:], ldt, work)

		t[j3*ldt+j1] = 0
		t[j3*ldt+j2] = 0
		t[j3*ldt+j3] = t11

		if wantq {
			// Accumulate transformation in the matrix Q.
			impl.Dlarfx(blas.Right, n, 3, u[:], tau, q[j1:], ldq, work)
		}

	case n1 == 2 && n2 == 1:
		//  Generate elementary reflector H so that:
		//   H (  -X11 ) = ( * )
		//     (  -X21 ) = ( 0 )
		//     ( scale ) = ( 0 )
		u := [3]float64{1, -x[ldx], scale}
		_, tau := impl.Dlarfg(3, -x[0], u[1:], 1)
		t33 := t[j3*ldt+j3]

		// Perform swap provisionally on diagonal block in D.
		impl.Dlarfx(blas.Left, 3, 3, u[:], tau, d[:], ldd, work)
		impl.Dlarfx(blas.Right, 3, 3, u[:], tau, d[:], ldd, work)

		// Test whether to reject swap.
		if math.Max(math.Abs(d[ldd]), math.Max(math.Abs(d[2*ldd]), math.Abs(d[0]-t33))) > thresh {
			return false
		}

		// Accept swap: apply transformation to the entire matrix T.
		impl.Dlarfx(blas.Right, j3+1, 3, u[:], tau, t[j1:], ldt, work)
		impl.Dlarfx(blas.Left, 3, n-j1-1, u[:], tau, t[j1*ldt+j2:], ldt, work)

		t[j1*ldt+j1] = t33
		t[j2*ldt+j1] = 0
		t[j3*ldt+j1] = 0

		if wantq {
			// Accumulate transformation in the matrix Q.
			impl.Dlarfx(blas.Right, n, 3, u[:], tau, q[j1:], ldq, work)
		}

	default: // n1 == 2 && n2 == 2
		// Generate elementary reflectors H_1 and H_2 so that:
		//  H_2 H_1 (  -X11  -X12 ) = (  *  * )
		//          (  -X21  -X22 )   (  0  * )
		//          ( scale    0  )   (  0  0 )
		//          (    0  scale )   (  0  0 )
		u1 := [3]float64{1, -x[ldx], scale}
		_, tau1 := impl.Dlarfg(3, -x[0], u1[1:], 1)

		temp := -tau1 * (x[1] + u1[1]*x[ldx+1])
		u2 := [3]float64{1, -temp * u1[2], scale}
		_, tau2 := impl.Dlarfg(3, -temp*u1[1]-x[ldx+1], u2[1:], 1)

		// Perform swap provisionally on diagonal block in D.
		impl.Dlarfx(blas.Left, 3, 4, u1[:], tau1, d[:], ldd, work)
		impl.Dlarfx(blas.Right, 4, 3, u1[:], tau1, d[:], ldd, work)
		impl.Dlarfx(blas.Left, 3, 4, u2[:], tau2, d[ldd:], ldd, work)
		impl.Dlarfx(blas.Right, 4, 3, u2[:], tau2, d[1:], ldd, work)

		// Test whether to reject swap.
		m1 := math.Max(math.Abs(d[2*ldd]), math.Abs(d[2*ldd+1]))
		m2 := math.Max(math.Abs(d[3*ldd]), math.Abs(d[3*ldd+1]))
		if math.Max(m1, m2) > thresh {
			return false
		}

		// Accept swap: apply transformation to the entire matrix T.
		j4 := j1 + 3
		impl.Dlarfx(blas.Left, 3, n-j1, u1[:], tau1, t[j1*ldt+j1:], ldt, work)
		impl.Dlarfx(blas.Right, j4+1, 3, u1[:], tau1, t[j1:], ldt, work)
		impl.Dlarfx(blas.Left, 3, n-j1, u2[:], tau2, t[j2*ldt+j1:], ldt, work)
		impl.Dlarfx(blas.Right, j4+1, 3, u2[:], tau2, t[j2:], ldt, work)

		t[j3*ldt+j1] = 0
		t[j3*ldt+j2] = 0
		t[j4*ldt+j1] = 0
		t[j4*ldt+j2] = 0

		if wantq {
			// Accumulate transformation in the matrix Q.
			impl.Dlarfx(blas.Right, n, 3, u1[:], tau1, q[j1:], ldq, work)
			impl.Dlarfx(blas.Right, n, 3, u2[:], tau2, q[j2:], ldq, work)
		}
	}

	if n2 == 2 {
		// Standardize new 2×2 block T11.
		a, b := t[j1*ldt+j1], t[j1*ldt+j2]
		c, d := t[j2*ldt+j1], t[j2*ldt+j2]
		var cs, sn float64
		t[j1*ldt+j1], t[j1*ldt+j2], t[j2*ldt+j1], t[j2*ldt+j2], _, _, _, _, cs, sn = impl.Dlanv2(a, b, c, d)
		if n-j1-2 > 0 {
			bi.Drot(n-j1-2, t[j1*ldt+j1+2:], 1, t[j2*ldt+j1+2:], 1, cs, sn)
		}
		if j1 > 0 {
			bi.Drot(j1, t[j1:], ldt, t[j2:], ldt, cs, sn)
		}
		if wantq {
			bi.Drot(n, q[j1:], ldq, q[j2:], ldq, cs, sn)
		}
	}
	if n1 == 2 {
		// Standardize new 2×2 block T22.
		j3 := j1 + n2
		j4 := j3 + 1
		a, b := t[j3*ldt+j3], t[j3*ldt+j4]
		c, d := t[j4*ldt+j3], t[j4*ldt+j4]
		var cs, sn float64
		t[j3*ldt+j3], t[j3*ldt+j4], t[j4*ldt+j3], t[j4*ldt+j4], _, _, _, _, cs, sn = impl.Dlanv2(a, b, c, d)
		if n-j3-2 > 0 {
			bi.Drot(n-j3-2, t[j3*ldt+j3+2:], 1, t[j4*ldt+j3+2:], 1, cs, sn)
		}
		bi.Drot(j3, t[j3:], ldt, t[j4:], ldt, cs, sn)
		if wantq {
			bi.Drot(n, q[j3:], ldq, q[j4:], ldq, cs, sn)
		}
	}

	return true
}
<commit_msg>native: document that Dlaexc is internal routine<commit_after>// Copyright ©2016 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package native

import (
	"math"

	"github.com/gonum/blas"
	"github.com/gonum/blas/blas64"
	"github.com/gonum/lapack"
)

// Dlaexc swaps two adjacent diagonal blocks of order 1 or 2 in an n×n upper
// quasi-triangular matrix T by an orthogonal similarity transformation.
//
// T must be in Schur canonical form, that is, block upper triangular with 1×1
// and 2×2 diagonal blocks; each 2×2 diagonal block has its diagonal elements
// equal and its off-diagonal elements of opposite sign. On return, T will
// contain the updated matrix again in Schur canonical form.
//
// If wantq is true, the transformation is accumulated in the n×n matrix Q,
// otherwise Q is not referenced.
//
// j1 is the index of the first row of the first block. n1 and n2 are the order
// of the first and second block, respectively.
//
// work much have length at least n, otherwise Dlaexc will panic.
//
// If ok is false, the transformed matrix T would be too far from Schur form.
// The blocks are not swapped, and T and Q are not modified.
//
// Dlaexc is an internal routine. It is exported for testing purposes.
func (impl Implementation) Dlaexc(wantq bool, n int, t []float64, ldt int, q []float64, ldq int, j1, n1, n2 int, work []float64) (ok bool) {
	checkMatrix(n, n, t, ldt)
	if wantq {
		checkMatrix(n, n, q, ldq)
	}
	if j1 < 0 || n <= j1 {
		panic("lapack: index j1 out of range")
	}
	if len(work) < n {
		panic(badWork)
	}
	if n1 < 0 || 2 < n1 {
		panic("lapack: invalid value of n1")
	}
	if n2 < 0 || 2 < n2 {
		panic("lapack: invalid value of n2")
	}

	if n == 0 || n1 == 0 || n2 == 0 {
		return true
	}
	if j1+n1 >= n {
		// TODO(vladimir-ch): Reference LAPACK does this check whether
		// the start of the second block is in the matrix T. It returns
		// true if it is not and moreover it does not check whether the
		// whole second block fits into T. This does not feel
		// satisfactory. The only caller of Dlaexc is Dtrexc, so if the
		// caller makes sure that this does not happen, we could be
		// stricter here.
		return true
	}

	j2 := j1 + 1
	j3 := j1 + 2

	bi := blas64.Implementation()

	if n1 == 1 && n2 == 1 {
		// Swap two 1×1 blocks.
		t11 := t[j1*ldt+j1]
		t22 := t[j2*ldt+j2]

		// Determine the transformation to perform the interchange.
		cs, sn, _ := impl.Dlartg(t[j1*ldt+j2], t22-t11)

		// Apply transformation to the matrix T.
		if n-j3 > 0 {
			bi.Drot(n-j3, t[j1*ldt+j3:], 1, t[j2*ldt+j3:], 1, cs, sn)
		}
		if j1 > 0 {
			bi.Drot(j1, t[j1:], ldt, t[j2:], ldt, cs, sn)
		}

		t[j1*ldt+j1] = t22
		t[j2*ldt+j2] = t11

		if wantq {
			// Accumulate transformation in the matrix Q.
			bi.Drot(n, q[j1:], ldq, q[j2:], ldq, cs, sn)
		}

		return true
	}

	// Swapping involves at least one 2×2 block.
	//
	// Copy the diagonal block of order n1+n2 to the local array d and
	// compute its norm.
	nd := n1 + n2
	var d [16]float64
	const ldd = 4
	impl.Dlacpy(blas.All, nd, nd, t[j1*ldt+j1:], ldt, d[:], ldd)
	dnorm := impl.Dlange(lapack.MaxAbs, nd, nd, d[:], ldd, work)

	// Compute machine-dependent threshold for test for accepting swap.
	eps := dlamchP
	thresh := math.Max(10*eps*dnorm, dlamchS/eps)

	// Solve T11*X - X*T22 = scale*T12 for X.
	var x [4]float64
	const ldx = 2
	scale, _, _ := impl.Dlasy2(false, false, -1, n1, n2, d[:], ldd, d[n1*ldd+n1:], ldd, d[n1:], ldd, x[:], ldx)

	// Swap the adjacent diagonal blocks.
	switch {
	case n1 == 1 && n2 == 2:
		// Generate elementary reflector H so that
		//  ( scale, X11, X12 ) H = ( 0, 0, * )
		u := [3]float64{scale, x[0], 1}
		_, tau := impl.Dlarfg(3, x[1], u[:2], 1)
		t11 := t[j1*ldt+j1]

		// Perform swap provisionally on diagonal block in d.
		impl.Dlarfx(blas.Left, 3, 3, u[:], tau, d[:], ldd, work)
		impl.Dlarfx(blas.Right, 3, 3, u[:], tau, d[:], ldd, work)

		// Test whether to reject swap.
		if math.Max(math.Abs(d[2*ldd]), math.Max(math.Abs(d[2*ldd+1]), math.Abs(d[2*ldd+2]-t11))) > thresh {
			return false
		}

		// Accept swap: apply transformation to the entire matrix T.
		impl.Dlarfx(blas.Left, 3, n-j1, u[:], tau, t[j1*ldt+j1:], ldt, work)
		impl.Dlarfx(blas.Right, j2+1, 3, u[:], tau, t[j1:], ldt, work)

		t[j3*ldt+j1] = 0
		t[j3*ldt+j2] = 0
		t[j3*ldt+j3] = t11

		if wantq {
			// Accumulate transformation in the matrix Q.
			impl.Dlarfx(blas.Right, n, 3, u[:], tau, q[j1:], ldq, work)
		}

	case n1 == 2 && n2 == 1:
		//  Generate elementary reflector H so that:
		//   H (  -X11 ) = ( * )
		//     (  -X21 ) = ( 0 )
		//     ( scale ) = ( 0 )
		u := [3]float64{1, -x[ldx], scale}
		_, tau := impl.Dlarfg(3, -x[0], u[1:], 1)
		t33 := t[j3*ldt+j3]

		// Perform swap provisionally on diagonal block in D.
		impl.Dlarfx(blas.Left, 3, 3, u[:], tau, d[:], ldd, work)
		impl.Dlarfx(blas.Right, 3, 3, u[:], tau, d[:], ldd, work)

		// Test whether to reject swap.
		if math.Max(math.Abs(d[ldd]), math.Max(math.Abs(d[2*ldd]), math.Abs(d[0]-t33))) > thresh {
			return false
		}

		// Accept swap: apply transformation to the entire matrix T.
		impl.Dlarfx(blas.Right, j3+1, 3, u[:], tau, t[j1:], ldt, work)
		impl.Dlarfx(blas.Left, 3, n-j1-1, u[:], tau, t[j1*ldt+j2:], ldt, work)

		t[j1*ldt+j1] = t33
		t[j2*ldt+j1] = 0
		t[j3*ldt+j1] = 0

		if wantq {
			// Accumulate transformation in the matrix Q.
			impl.Dlarfx(blas.Right, n, 3, u[:], tau, q[j1:], ldq, work)
		}

	default: // n1 == 2 && n2 == 2
		// Generate elementary reflectors H_1 and H_2 so that:
		//  H_2 H_1 (  -X11  -X12 ) = (  *  * )
		//          (  -X21  -X22 )   (  0  * )
		//          ( scale    0  )   (  0  0 )
		//          (    0  scale )   (  0  0 )
		u1 := [3]float64{1, -x[ldx], scale}
		_, tau1 := impl.Dlarfg(3, -x[0], u1[1:], 1)

		temp := -tau1 * (x[1] + u1[1]*x[ldx+1])
		u2 := [3]float64{1, -temp * u1[2], scale}
		_, tau2 := impl.Dlarfg(3, -temp*u1[1]-x[ldx+1], u2[1:], 1)

		// Perform swap provisionally on diagonal block in D.
		impl.Dlarfx(blas.Left, 3, 4, u1[:], tau1, d[:], ldd, work)
		impl.Dlarfx(blas.Right, 4, 3, u1[:], tau1, d[:], ldd, work)
		impl.Dlarfx(blas.Left, 3, 4, u2[:], tau2, d[ldd:], ldd, work)
		impl.Dlarfx(blas.Right, 4, 3, u2[:], tau2, d[1:], ldd, work)

		// Test whether to reject swap.
		m1 := math.Max(math.Abs(d[2*ldd]), math.Abs(d[2*ldd+1]))
		m2 := math.Max(math.Abs(d[3*ldd]), math.Abs(d[3*ldd+1]))
		if math.Max(m1, m2) > thresh {
			return false
		}

		// Accept swap: apply transformation to the entire matrix T.
		j4 := j1 + 3
		impl.Dlarfx(blas.Left, 3, n-j1, u1[:], tau1, t[j1*ldt+j1:], ldt, work)
		impl.Dlarfx(blas.Right, j4+1, 3, u1[:], tau1, t[j1:], ldt, work)
		impl.Dlarfx(blas.Left, 3, n-j1, u2[:], tau2, t[j2*ldt+j1:], ldt, work)
		impl.Dlarfx(blas.Right, j4+1, 3, u2[:], tau2, t[j2:], ldt, work)

		t[j3*ldt+j1] = 0
		t[j3*ldt+j2] = 0
		t[j4*ldt+j1] = 0
		t[j4*ldt+j2] = 0

		if wantq {
			// Accumulate transformation in the matrix Q.
			impl.Dlarfx(blas.Right, n, 3, u1[:], tau1, q[j1:], ldq, work)
			impl.Dlarfx(blas.Right, n, 3, u2[:], tau2, q[j2:], ldq, work)
		}
	}

	if n2 == 2 {
		// Standardize new 2×2 block T11.
		a, b := t[j1*ldt+j1], t[j1*ldt+j2]
		c, d := t[j2*ldt+j1], t[j2*ldt+j2]
		var cs, sn float64
		t[j1*ldt+j1], t[j1*ldt+j2], t[j2*ldt+j1], t[j2*ldt+j2], _, _, _, _, cs, sn = impl.Dlanv2(a, b, c, d)
		if n-j1-2 > 0 {
			bi.Drot(n-j1-2, t[j1*ldt+j1+2:], 1, t[j2*ldt+j1+2:], 1, cs, sn)
		}
		if j1 > 0 {
			bi.Drot(j1, t[j1:], ldt, t[j2:], ldt, cs, sn)
		}
		if wantq {
			bi.Drot(n, q[j1:], ldq, q[j2:], ldq, cs, sn)
		}
	}
	if n1 == 2 {
		// Standardize new 2×2 block T22.
		j3 := j1 + n2
		j4 := j3 + 1
		a, b := t[j3*ldt+j3], t[j3*ldt+j4]
		c, d := t[j4*ldt+j3], t[j4*ldt+j4]
		var cs, sn float64
		t[j3*ldt+j3], t[j3*ldt+j4], t[j4*ldt+j3], t[j4*ldt+j4], _, _, _, _, cs, sn = impl.Dlanv2(a, b, c, d)
		if n-j3-2 > 0 {
			bi.Drot(n-j3-2, t[j3*ldt+j3+2:], 1, t[j4*ldt+j3+2:], 1, cs, sn)
		}
		bi.Drot(j3, t[j3:], ldt, t[j4:], ldt, cs, sn)
		if wantq {
			bi.Drot(n, q[j3:], ldq, q[j4:], ldq, cs, sn)
		}
	}

	return true
}
<|endoftext|>


<commit_before>package images

import (
    "testing"
    "fmt"
    "os"
)

func TestNegative(t *testing.T) {
    img, err := Open("./testdata/test.jpg")
    if img.Error != nil {
        t.Errorf("Error %q", err.Error())
    }
    if img.Format != "jpeg" {
        t.Errorf("Error Format, %q", img.Format)
    }
    if img.Width() != 457 || img.Height() != 343 {
        t.Errorf("Error size, %q %q", fmt.Sprintf("%v", img.Width()), fmt.Sprintf("%v", img.Height()))
    }
    if img.Quality != 100 {
        t.Errorf("Error default quality, %q", img.Quality)
    }

    img_negative := img.Negative()
    img_negative.Format = "jpeg"

    if img_negative.Error != nil {
        t.Errorf("Error negative %q", img_negative.Error.Error())
    }
    if img_negative.Format != "jpeg" {
        t.Errorf("Error negative Format, %q", img_negative.Format)
    }
    if img_negative.Width() != 457 || img_negative.Height() != 343 {
        t.Errorf("Error negative size, %q %q", fmt.Sprintf("%v", img_negative.Width()), fmt.Sprintf("%v", img_negative.Height()))
    }
    if img_negative.Quality != 100 {
        t.Errorf("Error negative default quality, %q", img_negative.Quality)
    }

    err = img_negative.Save("./testdata/test_negative.jpg")
    if err != nil {
        t.Errorf("Error negative save, %q", err.Error())
    }

    img2, err := Open("./testdata/test_negative.jpg")
    if err != nil {
        t.Errorf("Error negative open, %q", err.Error())
    }
    if img2.Format != "jpeg" {
        t.Errorf("Error negative Format, %q", img.Format)
    }
    if img2.Width() != 457 || img2.Height() != 343 {
        t.Errorf("Error negative open size, %q %q", fmt.Sprintf("%v", img2.Width()), fmt.Sprintf("%v", img2.Height()))
    }

}

func TestHashFile(t *testing.T) {
    file, err := os.Open("./testdata/test.jpg")
    if err != nil {
        t.Errorf("Error image open, %q", err)
    }
    defer file.Close()
    hashfile := GetHashFile(file)
    if hashfile != "e269a4995ad439664251b38951448022706e037b40d243475f1bb3ae74329212" {
        t.Errorf("Error image hash256 file, %q", hashfile)
    }
}

func TestHashFileNegative(t *testing.T) {
    file, err := os.Open("./testdata/test_negative.jpg")
    if err != nil {
        t.Errorf("Error negative open, %q", err)
    }
    defer file.Close()
    hashfile := GetHashFile(file)
    if hashfile != "b4d65104a11a52df7ece664680d7db58a8ec83992b64d8f4699e7b0c2b3e1cb8" {
        t.Errorf("Error negative hash256 file, %q", hashfile)
    }
}

<commit_msg>Add test for Negative func, hashfile, for Golang Devel Version<commit_after>package images

import (
    "testing"
    "fmt"
    "os"
    "runtime"
    "strings"
)

func TestNegative(t *testing.T) {
    img, err := Open("./testdata/test.jpg")
    if img.Error != nil {
        t.Errorf("Error %q", err.Error())
    }
    if img.Format != "jpeg" {
        t.Errorf("Error Format, %q", img.Format)
    }
    if img.Width() != 457 || img.Height() != 343 {
        t.Errorf("Error size, %q %q", fmt.Sprintf("%v", img.Width()), fmt.Sprintf("%v", img.Height()))
    }
    if img.Quality != 100 {
        t.Errorf("Error default quality, %q", img.Quality)
    }

    img_negative := img.Negative()
    img_negative.Format = "jpeg"

    if img_negative.Error != nil {
        t.Errorf("Error negative %q", img_negative.Error.Error())
    }
    if img_negative.Format != "jpeg" {
        t.Errorf("Error negative Format, %q", img_negative.Format)
    }
    if img_negative.Width() != 457 || img_negative.Height() != 343 {
        t.Errorf("Error negative size, %q %q", fmt.Sprintf("%v", img_negative.Width()), fmt.Sprintf("%v", img_negative.Height()))
    }
    if img_negative.Quality != 100 {
        t.Errorf("Error negative default quality, %q", img_negative.Quality)
    }

    err = img_negative.Save("./testdata/test_negative.jpg")
    if err != nil {
        t.Errorf("Error negative save, %q", err.Error())
    }

    img2, err := Open("./testdata/test_negative.jpg")
    if err != nil {
        t.Errorf("Error negative open, %q", err.Error())
    }
    if img2.Format != "jpeg" {
        t.Errorf("Error negative Format, %q", img.Format)
    }
    if img2.Width() != 457 || img2.Height() != 343 {
        t.Errorf("Error negative open size, %q %q", fmt.Sprintf("%v", img2.Width()), fmt.Sprintf("%v", img2.Height()))
    }

}

func TestHashFile(t *testing.T) {
    file, err := os.Open("./testdata/test.jpg")
    if err != nil {
        t.Errorf("Error image open, %q", err)
    }
    defer file.Close()
    hashfile := GetHashFile(file)
    if hashfile != "e269a4995ad439664251b38951448022706e037b40d243475f1bb3ae74329212" {
        t.Errorf("Error image hash256 file, %q", hashfile)
    }
}

func TestHashFileNegative(t *testing.T) {
    file, err := os.Open("./testdata/test_negative.jpg")
    if err != nil {
        t.Errorf("Error negative open, %q", err)
    }
    defer file.Close()
    hashfile := GetHashFile(file)

    go_version_devel := strings.Contains(runtime.Version(), "devel")

    if !go_version_devel {
        if hashfile != "b4d65104a11a52df7ece664680d7db58a8ec83992b64d8f4699e7b0c2b3e1cb8" {
            t.Errorf("Error negative hash256 file, %q, %q", runtime.Version(), hashfile)
        }
    } else {
        // see https://github.com/golang/go/commit/28388c4eb102f3218bbbdcca4699de6b078bdde6#diff-1e31509dba8d6eff03847d207acdb790R304
        if hashfile != "c0e19e49bde43035047619dca96bc906bdd7e3172f62cc34fc4f2be2683b0760" {
            t.Errorf("Error negative hash256 file, %q, %q", runtime.Version(), hashfile)
        }
    }
}

<|endoftext|>


<commit_before>package dungeonfs
<commit_msg>Delete dungeonfs.go<commit_after><|endoftext|>


<commit_before>package ebda

import (
	"bytes"
	"encoding/binary"

	"github.com/bobuhiro11/gokvm/bootparam"
)

// Extended BIOS Data Area (EBDA).
type EBDA struct {
	// padding
	// It must be aligned with 16 bytes and its size must be less than 1KB.
	// https://github.com/torvalds/linux/blob/2f111a6fd5b5297b4e92f53798ca086f7c7d33a4/arch/x86/kernel/mpparse.c#L597
	_        [16 * 3]uint8
	mpfIntel MPFIntel
	mpcTable MPCTable
}

func (e *EBDA) Bytes() ([]byte, error) {
	buf := new(bytes.Buffer)

	if err := binary.Write(buf, binary.LittleEndian, e); err != nil {
		return []byte{}, err
	}

	return buf.Bytes(), nil
}

func New() (*EBDA, error) {
	e := &EBDA{}

	mpfIntel, err := NewMPFIntel()
	if err != nil {
		return e, err
	}

	e.mpfIntel = *mpfIntel

	mpcTable, err := NewMPCTable()
	if err != nil {
		return e, err
	}

	e.mpcTable = *mpcTable

	return e, nil
}

// Intel MP Floating Pointer Structure
// ported from https://github.com/torvalds/linux/blob/5bfc75d92/arch/x86/include/asm/mpspec_def.h#L22-L33
type MPFIntel struct {
	Signature     uint32
	PhysPtr       uint32
	Length        uint8
	Specification uint8
	CheckSum      uint8
	Feature1      uint8
	Feature2      uint8
	Feature3      uint8
	Feature4      uint8
	Feature5      uint8
}

func NewMPFIntel() (*MPFIntel, error) {
	m := &MPFIntel{}
	m.Signature = (('_' << 24) | ('P' << 16) | ('M' << 8) | '_')
	m.Length = 1 // this must be 1
	m.Specification = 4
	m.PhysPtr = bootparam.EBDAStart + 0x40

	var err error

	m.CheckSum, err = m.CalcCheckSum()
	if err != nil {
		return m, err
	}

	m.CheckSum ^= uint8(0xff)
	m.CheckSum++

	return m, nil
}

func (m *MPFIntel) CalcCheckSum() (uint8, error) {
	bytes, err := m.Bytes()
	if err != nil {
		return 0, err
	}

	tmp := uint32(0)
	for _, b := range bytes {
		tmp += uint32(b)
	}

	return uint8(tmp & 0xff), nil
}

func (m *MPFIntel) Bytes() ([]byte, error) {
	buf := new(bytes.Buffer)

	if err := binary.Write(buf, binary.LittleEndian, m); err != nil {
		return []byte{}, err
	}

	return buf.Bytes(), nil
}

// MP Configuration Table Header
// ported from https://github.com/torvalds/linux/blob/5bfc75d92/arch/x86/include/asm/mpspec_def.h#L37-L49
type MPCTable struct {
	Signature uint32
	Length    uint16
	Spec      uint8
	CheckSum  uint8
	OEM       [8]uint8
	ProductID [12]uint8
	OEMPtr    uint32
	OEMSize   uint16
	OEMCount  uint16
	LAPIC     uint32 // Local APIC addresss must be set.
	Reserved  uint32
}

func NewMPCTable() (*MPCTable, error) {
	m := &MPCTable{}
	m.Signature = (('P' << 24) | ('M' << 16) | ('C' << 8) | 'P')
	m.Length = 44 // this field must contain the size of entries.
	m.Spec = 1
	m.LAPIC = 0xFEE00000

	var err error

	m.CheckSum, err = m.CalcCheckSum()
	if err != nil {
		return m, err
	}

	m.CheckSum ^= uint8(0xff)
	m.CheckSum++

	return m, nil
}

func (m *MPCTable) CalcCheckSum() (uint8, error) {
	bytes, err := m.Bytes()
	if err != nil {
		return 0, err
	}

	tmp := uint32(0)
	for _, b := range bytes {
		tmp += uint32(b)
	}

	return uint8(tmp & 0xff), nil
}

func (m *MPCTable) Bytes() ([]byte, error) {
	buf := new(bytes.Buffer)

	if err := binary.Write(buf, binary.LittleEndian, m); err != nil {
		return []byte{}, err
	}

	return buf.Bytes(), nil
}
<commit_msg>ebda: add mpc_cpu struct<commit_after>package ebda

import (
	"bytes"
	"encoding/binary"
	"unsafe"

	"github.com/bobuhiro11/gokvm/bootparam"
)

// this must be fixed.
const NumCPUs = 2

// Extended BIOS Data Area (EBDA).
type EBDA struct {
	// padding
	// It must be aligned with 16 bytes and its size must be less than 1KB.
	// https://github.com/torvalds/linux/blob/2f111a6fd5b5297b4e92f53798ca086f7c7d33a4/arch/x86/kernel/mpparse.c#L597
	_        [16 * 3]uint8
	mpfIntel MPFIntel
	mpcTable MPCTable
}

func (e *EBDA) Bytes() ([]byte, error) {
	buf := new(bytes.Buffer)

	if err := binary.Write(buf, binary.LittleEndian, e); err != nil {
		return []byte{}, err
	}

	return buf.Bytes(), nil
}

func New() (*EBDA, error) {
	e := &EBDA{}

	mpfIntel, err := NewMPFIntel()
	if err != nil {
		return e, err
	}

	e.mpfIntel = *mpfIntel

	mpcTable, err := NewMPCTable()
	if err != nil {
		return e, err
	}

	e.mpcTable = *mpcTable

	return e, nil
}

// Intel MP Floating Pointer Structure
// ported from https://github.com/torvalds/linux/blob/5bfc75d92/arch/x86/include/asm/mpspec_def.h#L22-L33
type MPFIntel struct {
	Signature     uint32
	PhysPtr       uint32
	Length        uint8
	Specification uint8
	CheckSum      uint8
	Feature1      uint8
	Feature2      uint8
	Feature3      uint8
	Feature4      uint8
	Feature5      uint8
}

func NewMPFIntel() (*MPFIntel, error) {
	m := &MPFIntel{}
	m.Signature = (('_' << 24) | ('P' << 16) | ('M' << 8) | '_')
	m.Length = 1 // this must be 1
	m.Specification = 4
	m.PhysPtr = bootparam.EBDAStart + 0x40

	var err error

	m.CheckSum, err = m.CalcCheckSum()
	if err != nil {
		return m, err
	}

	m.CheckSum ^= uint8(0xff)
	m.CheckSum++

	return m, nil
}

func (m *MPFIntel) CalcCheckSum() (uint8, error) {
	bytes, err := m.Bytes()
	if err != nil {
		return 0, err
	}

	tmp := uint32(0)
	for _, b := range bytes {
		tmp += uint32(b)
	}

	return uint8(tmp & 0xff), nil
}

func (m *MPFIntel) Bytes() ([]byte, error) {
	buf := new(bytes.Buffer)

	if err := binary.Write(buf, binary.LittleEndian, m); err != nil {
		return []byte{}, err
	}

	return buf.Bytes(), nil
}

// MP Configuration Table Header
// ported from https://github.com/torvalds/linux/blob/5bfc75d92/arch/x86/include/asm/mpspec_def.h#L37-L49
type MPCTable struct {
	Signature uint32
	Length    uint16
	Spec      uint8
	CheckSum  uint8
	OEM       [8]uint8
	ProductID [12]uint8
	OEMPtr    uint32
	OEMSize   uint16
	OEMCount  uint16
	LAPIC     uint32 // Local APIC addresss must be set.
	Reserved  uint32

	mpcCPU [NumCPUs]MPCCpu
}

func NewMPCTable() (*MPCTable, error) {
	m := &MPCTable{}
	m.Signature = (('P' << 24) | ('M' << 16) | ('C' << 8) | 'P')
	m.Length = uint16(unsafe.Sizeof(MPCTable{})) // this field must contain the size of entries.
	// m.Length += uint16(unsafe.Sizeof(MPCCpu{})) * NumCPUs
	m.Spec = 1
	m.LAPIC = 0xFEE00000

	var err error

	for i := 0; i < NumCPUs; i++ {
		mpcCPU, err := NewMPCCpu(i)
		if err != nil {
			return m, err
		}

		m.mpcCPU[i] = *mpcCPU
	}

	m.CheckSum, err = m.CalcCheckSum()
	if err != nil {
		return m, err
	}

	m.CheckSum ^= uint8(0xff)
	m.CheckSum++

	return m, nil
}

func (m *MPCTable) CalcCheckSum() (uint8, error) {
	bytes, err := m.Bytes()
	if err != nil {
		return 0, err
	}

	tmp := uint32(0)
	for _, b := range bytes {
		tmp += uint32(b)
	}

	return uint8(tmp & 0xff), nil
}

func (m *MPCTable) Bytes() ([]byte, error) {
	buf := new(bytes.Buffer)

	if err := binary.Write(buf, binary.LittleEndian, m); err != nil {
		return []byte{}, err
	}

	return buf.Bytes(), nil
}

type MPCCpu struct {
	Type        uint8
	APICID      uint8 // Local APIC number
	APICVER     uint8
	CPUFlag     uint8
	CPUFeature  uint32
	FeatureFlag uint32
	Reserved    [2]uint32
}

func NewMPCCpu(i int) (*MPCCpu, error) {
	m := &MPCCpu{}

	m.Type = 0
	m.APICID = uint8(i)
	m.APICVER = 0x14
	m.CPUFlag |= 1 // enabled processor

	if i == 0 {
		m.CPUFlag |= 2 // boot processor
	}

	return m, nil
}
<|endoftext|>


<commit_before>// +build !wasm

package input

import (
	"context"
	"fmt"
	"time"

	"github.com/Azure/azure-storage-queue-go/azqueue"
	"github.com/Jeffail/benthos/v3/internal/service/azure"
	"github.com/Jeffail/benthos/v3/lib/input/reader"
	"github.com/Jeffail/benthos/v3/lib/log"
	"github.com/Jeffail/benthos/v3/lib/message"
	"github.com/Jeffail/benthos/v3/lib/metrics"
	"github.com/Jeffail/benthos/v3/lib/types"
)

// AzureQueueStorage is a benthos reader.Type implementation that reads messages
// from an Azure Queue Storage container.
type azureQueueStorage struct {
	conf AzureQueueStorageConfig

	queueURL *azqueue.QueueURL

	log   log.Modular
	stats metrics.Type
}

// newAzureQueueStorage creates a new Azure Storage Queue input type.
func newAzureQueueStorage(conf AzureQueueStorageConfig, log log.Modular, stats metrics.Type) (*azureQueueStorage, error) {
	serviceURL, err := azure.GetQueueServiceURL(conf.StorageAccount, conf.StorageAccessKey, conf.StorageConnectionString)
	if err != nil {
		return nil, err
	}
	queueURL := serviceURL.NewQueueURL(conf.QueueName)
	a := &azureQueueStorage{
		conf:     conf,
		log:      log,
		stats:    stats,
		queueURL: &queueURL,
	}
	return a, nil
}

// ConnectWithContext attempts to establish a connection
func (a *azureQueueStorage) ConnectWithContext(ctx context.Context) error {
	return nil
}

// ReadWithContext attempts to read a new message from the target Azure Storage Queue
// Storage container.
func (a *azureQueueStorage) ReadWithContext(ctx context.Context) (msg types.Message, ackFn reader.AsyncAckFn, err error) {
	messageURL := a.queueURL.NewMessagesURL()
	dequeue, err := messageURL.Dequeue(ctx, 1, 30*time.Second)
	if err != nil {
		if cerr, ok := err.(azqueue.StorageError); ok {
			if cerr.ServiceCode() == azqueue.ServiceCodeQueueNotFound {
				ctx := context.Background()
				_, err = a.queueURL.Create(ctx, azqueue.Metadata{})
				return nil, nil, err
			}
			return nil, nil, fmt.Errorf("storage error message: %v", cerr)
		}
		return nil, nil, fmt.Errorf("error dequeing message: %v", err)
	}
	if n := dequeue.NumMessages(); n > 0 {
		props, _ := a.queueURL.GetProperties(ctx)
		metadata := props.NewMetadata()
		msg := message.New(nil)
		dqm := make([]*azqueue.DequeuedMessage, n)
		for i := int32(0); i < n; i++ {
			queueMsg := dequeue.Message(i)
			part := message.NewPart([]byte(queueMsg.Text))
			meta := part.Metadata()
			meta.Set("queue_storage_insertion_time", queueMsg.InsertionTime.Format(time.RFC3339))
			for k, v := range metadata {
				meta.Set(k, v)
			}
			msg.Append(part)
			dqm[i] = queueMsg
		}
		return msg, func(rctx context.Context, res types.Response) error {
			for i := int32(0); i < n; i++ {
				msgIDURL := messageURL.NewMessageIDURL(dqm[i].ID)
				_, err = msgIDURL.Delete(ctx, dqm[i].PopReceipt)
				if err != nil {
					return fmt.Errorf("error deleting message: %v", err)
				}
			}
			return nil
		}, nil
	}
	return nil, nil, nil
}

// CloseAsync begins cleaning up resources used by this reader asynchronously.
func (a *azureQueueStorage) CloseAsync() {
}

// WaitForClose will block until either the reader is closed or a specified
// timeout occurs.
func (a *azureQueueStorage) WaitForClose(time.Duration) error {
	return nil
}

//------------------------------------------------------------------------------
<commit_msg>Use acknowledge context from parameter to prevent expired context error<commit_after>// +build !wasm

package input

import (
	"context"
	"fmt"
	"time"

	"github.com/Azure/azure-storage-queue-go/azqueue"
	"github.com/Jeffail/benthos/v3/internal/service/azure"
	"github.com/Jeffail/benthos/v3/lib/input/reader"
	"github.com/Jeffail/benthos/v3/lib/log"
	"github.com/Jeffail/benthos/v3/lib/message"
	"github.com/Jeffail/benthos/v3/lib/metrics"
	"github.com/Jeffail/benthos/v3/lib/types"
)

// AzureQueueStorage is a benthos reader.Type implementation that reads messages
// from an Azure Queue Storage container.
type azureQueueStorage struct {
	conf AzureQueueStorageConfig

	queueURL *azqueue.QueueURL

	log   log.Modular
	stats metrics.Type
}

// newAzureQueueStorage creates a new Azure Storage Queue input type.
func newAzureQueueStorage(conf AzureQueueStorageConfig, log log.Modular, stats metrics.Type) (*azureQueueStorage, error) {
	serviceURL, err := azure.GetQueueServiceURL(conf.StorageAccount, conf.StorageAccessKey, conf.StorageConnectionString)
	if err != nil {
		return nil, err
	}
	queueURL := serviceURL.NewQueueURL(conf.QueueName)
	a := &azureQueueStorage{
		conf:     conf,
		log:      log,
		stats:    stats,
		queueURL: &queueURL,
	}
	return a, nil
}

// ConnectWithContext attempts to establish a connection
func (a *azureQueueStorage) ConnectWithContext(ctx context.Context) error {
	return nil
}

// ReadWithContext attempts to read a new message from the target Azure Storage Queue
// Storage container.
func (a *azureQueueStorage) ReadWithContext(ctx context.Context) (msg types.Message, ackFn reader.AsyncAckFn, err error) {
	messageURL := a.queueURL.NewMessagesURL()
	dequeue, err := messageURL.Dequeue(ctx, 1, 30*time.Second)
	if err != nil {
		if cerr, ok := err.(azqueue.StorageError); ok {
			if cerr.ServiceCode() == azqueue.ServiceCodeQueueNotFound {
				ctx := context.Background()
				_, err = a.queueURL.Create(ctx, azqueue.Metadata{})
				return nil, nil, err
			}
			return nil, nil, fmt.Errorf("storage error message: %v", cerr)
		}
		return nil, nil, fmt.Errorf("error dequeing message: %v", err)
	}
	if n := dequeue.NumMessages(); n > 0 {
		props, _ := a.queueURL.GetProperties(ctx)
		metadata := props.NewMetadata()
		msg := message.New(nil)
		dqm := make([]*azqueue.DequeuedMessage, n)
		for i := int32(0); i < n; i++ {
			queueMsg := dequeue.Message(i)
			part := message.NewPart([]byte(queueMsg.Text))
			meta := part.Metadata()
			meta.Set("queue_storage_insertion_time", queueMsg.InsertionTime.Format(time.RFC3339))
			for k, v := range metadata {
				meta.Set(k, v)
			}
			msg.Append(part)
			dqm[i] = queueMsg
		}
		return msg, func(ctx context.Context, res types.Response) error {
			for i := int32(0); i < n; i++ {
				msgIDURL := messageURL.NewMessageIDURL(dqm[i].ID)
				_, err = msgIDURL.Delete(ctx, dqm[i].PopReceipt)
				if err != nil {
					return fmt.Errorf("error deleting message: %v", err)
				}
			}
			return nil
		}, nil
	}
	return nil, nil, nil
}

// CloseAsync begins cleaning up resources used by this reader asynchronously.
func (a *azureQueueStorage) CloseAsync() {
}

// WaitForClose will block until either the reader is closed or a specified
// timeout occurs.
func (a *azureQueueStorage) WaitForClose(time.Duration) error {
	return nil
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/url"
	"time"

	"github.com/elastic/libbeat/beat"
	"github.com/elastic/libbeat/cfgfile"
	"github.com/elastic/libbeat/common"
	"github.com/elastic/libbeat/logp"
	"github.com/elastic/libbeat/publisher"

	"github.com/mrkschan/nginxbeat/parser"
)

const selector = "nginxbeat"

// Nginxbeat implements Beater interface and sends Nginx status using libbeat.
type Nginxbeat struct {
	// NbConfig holds configurations of Nginxbeat parsed by libbeat.
	NbConfig ConfigSettings

	done   chan uint
	events publisher.Client

	url    *url.URL
	format string
	period time.Duration
}

// Config Nginxbeat according to nginxbeat.yml.
func (nb *Nginxbeat) Config(b *beat.Beat) error {
	err := cfgfile.Read(&nb.NbConfig, "")
	if err != nil {
		logp.Err("Error reading configuration file: %v", err)
		return err
	}

	var u string
	if nb.NbConfig.Input.URL != "" {
		u = nb.NbConfig.Input.URL
	} else {
		u = "http://127.0.0.1/status"
	}
	nb.url, err = url.Parse(u)
	if err != nil {
		logp.Err("Invalid Nginx status page: %v", err)
		return err
	}

	var f string
	if nb.NbConfig.Input.Format != "" {
		f = nb.NbConfig.Input.Format
	} else {
		f = "stub"
	}
	if f != "stub" && f != "plus" {
		err = fmt.Errorf("%s is an unsupported format", f)
	}
	if err != nil {
		logp.Err("Invalid Nginx status format: %v", err)
		return err
	}
	nb.format = f

	if nb.NbConfig.Input.Period != nil {
		nb.period = time.Duration(*nb.NbConfig.Input.Period) * time.Second
	} else {
		nb.period = 10 * time.Second
	}

	logp.Debug(selector, "Init nginxbeat")
	logp.Debug(selector, "Watch %v", nb.url)
	logp.Debug(selector, "Format %v", nb.format)
	logp.Debug(selector, "Period %v", nb.period)

	return nil
}

// Setup Nginxbeat.
func (nb *Nginxbeat) Setup(b *beat.Beat) error {
	nb.events = b.Events
	nb.done = make(chan uint)

	return nil
}

// Run Nginxbeat.
func (nb *Nginxbeat) Run(b *beat.Beat) error {
	logp.Debug(selector, "Run nginxbeat")

	var p parser.Parser
	switch nb.format {
	case "stub":
		p = parser.NewStubParser()
	case "plus":
		p = parser.NewPlusParser()
	}

	ticker := time.NewTicker(nb.period)
	defer ticker.Stop()

	for {
		select {
		case <-nb.done:
			goto GotoFinish
		case <-ticker.C:
		}

		start := time.Now()

		s, err := p.Parse(nb.url.String())
		if err != nil {
			logp.Err("Fail to read Nginx status: %v", err)
			goto GotoNext
		}
		nb.events.PublishEvent(common.MapStr{
			"@@timestamp": common.Time(time.Now()),
			"type":       "nginx",
			"nginx":      s,
		})

	GotoNext:
		end := time.Now()
		duration := end.Sub(start)
		if duration.Nanoseconds() > nb.period.Nanoseconds() {
			logp.Warn("Ignoring tick(s) due to processing taking longer than one period")
		}
	}

GotoFinish:
	return nil
}

// Cleanup Nginxbeat.
func (nb *Nginxbeat) Cleanup(b *beat.Beat) error {
	return nil
}

// Stop Nginxbeat.
func (nb *Nginxbeat) Stop() {
	logp.Debug(selector, "Stop nginxbeat")
	close(nb.done)
}
<commit_msg>Use correct field name '@timestamp'<commit_after>package main

import (
	"fmt"
	"net/url"
	"time"

	"github.com/elastic/libbeat/beat"
	"github.com/elastic/libbeat/cfgfile"
	"github.com/elastic/libbeat/common"
	"github.com/elastic/libbeat/logp"
	"github.com/elastic/libbeat/publisher"

	"github.com/mrkschan/nginxbeat/parser"
)

const selector = "nginxbeat"

// Nginxbeat implements Beater interface and sends Nginx status using libbeat.
type Nginxbeat struct {
	// NbConfig holds configurations of Nginxbeat parsed by libbeat.
	NbConfig ConfigSettings

	done   chan uint
	events publisher.Client

	url    *url.URL
	format string
	period time.Duration
}

// Config Nginxbeat according to nginxbeat.yml.
func (nb *Nginxbeat) Config(b *beat.Beat) error {
	err := cfgfile.Read(&nb.NbConfig, "")
	if err != nil {
		logp.Err("Error reading configuration file: %v", err)
		return err
	}

	var u string
	if nb.NbConfig.Input.URL != "" {
		u = nb.NbConfig.Input.URL
	} else {
		u = "http://127.0.0.1/status"
	}
	nb.url, err = url.Parse(u)
	if err != nil {
		logp.Err("Invalid Nginx status page: %v", err)
		return err
	}

	var f string
	if nb.NbConfig.Input.Format != "" {
		f = nb.NbConfig.Input.Format
	} else {
		f = "stub"
	}
	if f != "stub" && f != "plus" {
		err = fmt.Errorf("%s is an unsupported format", f)
	}
	if err != nil {
		logp.Err("Invalid Nginx status format: %v", err)
		return err
	}
	nb.format = f

	if nb.NbConfig.Input.Period != nil {
		nb.period = time.Duration(*nb.NbConfig.Input.Period) * time.Second
	} else {
		nb.period = 10 * time.Second
	}

	logp.Debug(selector, "Init nginxbeat")
	logp.Debug(selector, "Watch %v", nb.url)
	logp.Debug(selector, "Format %v", nb.format)
	logp.Debug(selector, "Period %v", nb.period)

	return nil
}

// Setup Nginxbeat.
func (nb *Nginxbeat) Setup(b *beat.Beat) error {
	nb.events = b.Events
	nb.done = make(chan uint)

	return nil
}

// Run Nginxbeat.
func (nb *Nginxbeat) Run(b *beat.Beat) error {
	logp.Debug(selector, "Run nginxbeat")

	var p parser.Parser
	switch nb.format {
	case "stub":
		p = parser.NewStubParser()
	case "plus":
		p = parser.NewPlusParser()
	}

	ticker := time.NewTicker(nb.period)
	defer ticker.Stop()

	for {
		select {
		case <-nb.done:
			goto GotoFinish
		case <-ticker.C:
		}

		start := time.Now()

		s, err := p.Parse(nb.url.String())
		if err != nil {
			logp.Err("Fail to read Nginx status: %v", err)
			goto GotoNext
		}
		nb.events.PublishEvent(common.MapStr{
			"@timestamp": common.Time(time.Now()),
			"type":       "nginx",
			"nginx":      s,
		})

	GotoNext:
		end := time.Now()
		duration := end.Sub(start)
		if duration.Nanoseconds() > nb.period.Nanoseconds() {
			logp.Warn("Ignoring tick(s) due to processing taking longer than one period")
		}
	}

GotoFinish:
	return nil
}

// Cleanup Nginxbeat.
func (nb *Nginxbeat) Cleanup(b *beat.Beat) error {
	return nil
}

// Stop Nginxbeat.
func (nb *Nginxbeat) Stop() {
	logp.Debug(selector, "Stop nginxbeat")
	close(nb.done)
}
<|endoftext|>


<commit_before>package relay

import (
	"bytes"
	"compress/gzip"
	"crypto/tls"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	"github.com/influxdata/influxdb/models"
)

// HTTP is a relay for HTTP influxdb writes
type HTTP struct {
	addr string
	name string

	https bool
	cert  string

	closing int64
	l       net.Listener

	backends []*httpBackend
}

const (
	DefaultHTTPTimeout      = 10 * time.Second
	DefaultMaxDelayInterval = 10 * time.Second
	DefaultBatchSizeKB      = 512

	KB = 1024
	MB = 1024 * KB
)

func NewHTTP(cfg HTTPConfig) (Relay, error) {
	h := new(HTTP)

	h.addr = cfg.Addr
	h.name = cfg.Name

	h.cert = cfg.TLSCombinedPem

	for i := range cfg.Outputs {
		backend, err := newHTTPBackend(&cfg.Outputs[i])
		if err != nil {
			return nil, err
		}

		h.backends = append(h.backends, backend)
	}

	return h, nil
}

func (h *HTTP) Name() string {
	if h.name == "" {
		return "http://" + h.addr
	}
	return h.name
}

func (h *HTTP) Run() error {
	if h.cert != "" {
		cert, err := tls.LoadX509KeyPair(h.cert, h.cert)
		if err != nil {
			return err
		}

		l, err := tls.Listen("tcp", h.addr, &tls.Config{
			Certificates: []tls.Certificate{cert},
		})
		if err != nil {
			return err
		}
		h.l = l

		log.Printf("Starting HTTPS relay %q on %v", h.Name(), h.addr)
	} else {
		l, err := net.Listen("tcp", h.addr)
		if err != nil {
			return err
		}
		h.l = l

		log.Printf("Starting HTTP relay %q on %v", h.Name(), h.addr)
	}

	err := http.Serve(h.l, h)
	if atomic.LoadInt64(&h.closing) != 0 {
		return nil
	}
	return err
}

func (h *HTTP) Stop() error {
	atomic.StoreInt64(&h.closing, 1)
	return h.l.Close()
}

func (h *HTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	start := time.Now()
	if r.URL.Path != "/write" {
		jsonError(w, http.StatusNotFound, "invalid write endpoint")
		return
	}

	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusNoContent)
		} else {
			jsonError(w, http.StatusMethodNotAllowed, "invalid write method")
		}
		return
	}

	// fail early if we're missing the database
	if r.URL.Query().Get("db") == "" {
		jsonError(w, http.StatusBadRequest, "missing parameter: db")
		return
	}

	var body = r.Body

	if r.Header.Get("Content-Encoding") == "gzip" {
		b, err := gzip.NewReader(r.Body)
		if err != nil {
			jsonError(w, http.StatusBadRequest, "unable to decode gzip body")
		}
		defer b.Close()
		body = b
	}

	bodyBuf := getBuf()
	_, err := bodyBuf.ReadFrom(body)
	if err != nil {
		putBuf(bodyBuf)
		jsonError(w, http.StatusInternalServerError, "problem reading request body")
		return
	}

	precision := r.URL.Query().Get("precision")
	points, err := models.ParsePointsWithPrecision(bodyBuf.Bytes(), start, precision)
	if err != nil {
		putBuf(bodyBuf)
		jsonError(w, http.StatusBadRequest, "unable to parse points")
		return
	}

	outBuf := getBuf()
	for _, p := range points {
		if _, err = outBuf.WriteString(p.PrecisionString(precision)); err != nil {
			break
		}
		if err = outBuf.WriteByte('\n'); err != nil {
			break
		}
	}

	// done with the input points
	putBuf(bodyBuf)

	if err != nil {
		putBuf(outBuf)
		jsonError(w, http.StatusInternalServerError, "problem writing points")
		return
	}

	// normalize query string
	query := r.URL.Query().Encode()

	outBytes := outBuf.Bytes()

	var wg sync.WaitGroup
	wg.Add(len(h.backends))

	var responses = make(chan *responseData, len(h.backends))

	for _, b := range h.backends {
		b := b
		go func() {
			defer wg.Done()
			resp, err := b.post(outBytes, query)
			if err != nil {
				log.Printf("Problem posting to relay %q backend %q: %v", h.Name(), b.name, err)
			} else {
				if resp.StatusCode/100 == 5 {
					log.Printf("5xx response for relay %q backend %q: %v", h.Name(), b.name, resp.StatusCode)
				}
				responses <- resp
			}
		}()
	}

	go func() {
		wg.Wait()
		close(responses)
		putBuf(outBuf)
	}()

	var errResponse *responseData

	for resp := range responses {
		switch resp.StatusCode / 100 {
		case 2:
			w.WriteHeader(http.StatusNoContent)
			return

		case 4:
			// user error
			resp.Write(w)
			return

		default:
			// hold on to one of the responses to return back to the client
			errResponse = resp
		}
	}

	// no successful writes
	if errResponse == nil {
		// failed to make any valid request...
		jsonError(w, http.StatusServiceUnavailable, "unable to write points")
		return
	}

	errResponse.Write(w)
}

type responseData struct {
	ContentType     string
	ContentEncoding string
	StatusCode      int
	Body            []byte
}

func (rd *responseData) Write(w http.ResponseWriter) {
	if rd.ContentType != "" {
		w.Header().Set("Content-Type", rd.ContentType)
	}

	if rd.ContentEncoding != "" {
		w.Header().Set("Content-Encoding", rd.ContentEncoding)
	}

	w.Header().Set("Content-Length", strconv.Itoa(len(rd.Body)))
	w.WriteHeader(rd.StatusCode)
	w.Write(rd.Body)
}

func jsonError(w http.ResponseWriter, code int, message string) {
	w.Header().Set("Content-Type", "application/json")
	data := fmt.Sprintf("{\"error\":%q}\n", message)
	w.Header().Set("Content-Length", fmt.Sprint(len(data)))
	w.WriteHeader(code)
	w.Write([]byte(data))
}

type poster interface {
	post([]byte, string) (*responseData, error)
}

type simplePoster struct {
	client   *http.Client
	location string
}

func newSimplePoster(location string, timeout time.Duration) *simplePoster {
	return &simplePoster{
		client:   &http.Client{Timeout: timeout},
		location: location,
	}
}

func (b *simplePoster) post(buf []byte, query string) (*responseData, error) {
	req, err := http.NewRequest("POST", b.location, bytes.NewReader(buf))
	if err != nil {
		return nil, err
	}

	req.URL.RawQuery = query
	req.Header.Set("Content-Type", "text/plain")
	req.Header.Set("Content-Length", strconv.Itoa(len(buf)))

	resp, err := b.client.Do(req)
	if err != nil {
		return nil, err
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if err = resp.Body.Close(); err != nil {
		return nil, err
	}

	return &responseData{
		ContentType:     resp.Header.Get("Conent-Type"),
		ContentEncoding: resp.Header.Get("Conent-Encoding"),
		StatusCode:      resp.StatusCode,
		Body:            data,
	}, nil
}

type httpBackend struct {
	poster
	name string
}

func newHTTPBackend(cfg *HTTPOutputConfig) (*httpBackend, error) {
	if cfg.Name == "" {
		cfg.Name = cfg.Location
	}

	timeout := DefaultHTTPTimeout
	if cfg.Timeout != "" {
		t, err := time.ParseDuration(cfg.Timeout)
		if err != nil {
			return nil, fmt.Errorf("error parsing HTTP timeout '%v'", err)
		}
		timeout = t
	}

	var p poster = newSimplePoster(cfg.Location, timeout)

	// If configured, create a retryBuffer per backend.
	// This way we serialize retries against each backend.
	if cfg.BufferSizeMB > 0 {
		max := DefaultMaxDelayInterval
		if cfg.MaxDelayInterval != "" {
			m, err := time.ParseDuration(cfg.MaxDelayInterval)
			if err != nil {
				return nil, fmt.Errorf("error parsing max retry time %v", err)
			}
			max = m
		}

		batch := DefaultBatchSizeKB * KB
		if cfg.MaxBatchKB > 0 {
			batch = cfg.MaxBatchKB * KB
		}

		p = newRetryBuffer(cfg.BufferSizeMB*MB, batch, max, p)
	}

	return &httpBackend{
		poster: p,
		name:   cfg.Name,
	}, nil
}

var ErrBufferFull = errors.New("retry buffer full")

var bufPool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}

func getBuf() *bytes.Buffer {
	if bb, ok := bufPool.Get().(*bytes.Buffer); ok {
		return bb
	}
	return new(bytes.Buffer)
}

func putBuf(b *bytes.Buffer) {
	b.Reset()
	bufPool.Put(b)
}
<commit_msg>use tls.NewListener<commit_after>package relay

import (
	"bytes"
	"compress/gzip"
	"crypto/tls"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/influxdata/influxdb/models"
)

// HTTP is a relay for HTTP influxdb writes
type HTTP struct {
	addr   string
	name   string
	schema string

	cert string

	closing int64
	l       net.Listener

	backends []*httpBackend
}

const (
	DefaultHTTPTimeout      = 10 * time.Second
	DefaultMaxDelayInterval = 10 * time.Second
	DefaultBatchSizeKB      = 512

	KB = 1024
	MB = 1024 * KB
)

func NewHTTP(cfg HTTPConfig) (Relay, error) {
	h := new(HTTP)

	h.addr = cfg.Addr
	h.name = cfg.Name

	h.cert = cfg.TLSCombinedPem

	h.schema = "http"
	if h.cert != "" {
		h.schema = "https"
	}

	for i := range cfg.Outputs {
		backend, err := newHTTPBackend(&cfg.Outputs[i])
		if err != nil {
			return nil, err
		}

		h.backends = append(h.backends, backend)
	}

	return h, nil
}

func (h *HTTP) Name() string {
	if h.name == "" {
		return fmt.Sprintf("%s://%s", h.schema, h.addr)
	}
	return h.name
}

func (h *HTTP) Run() error {
	l, err := net.Listen("tcp", h.addr)
	if err != nil {
		return err
	}

	// support HTTPS
	if h.cert != "" {
		cert, err := tls.LoadX509KeyPair(h.cert, h.cert)
		if err != nil {
			return err
		}

		l = tls.NewListener(l, &tls.Config{
			Certificates: []tls.Certificate{cert},
		})
	}

	h.l = l

	log.Printf("Starting %s relay %q on %v", strings.ToUpper(h.schema), h.Name(), h.addr)

	err = http.Serve(h.l, h)
	if atomic.LoadInt64(&h.closing) != 0 {
		return nil
	}
	return err
}

func (h *HTTP) Stop() error {
	atomic.StoreInt64(&h.closing, 1)
	return h.l.Close()
}

func (h *HTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	start := time.Now()
	if r.URL.Path != "/write" {
		jsonError(w, http.StatusNotFound, "invalid write endpoint")
		return
	}

	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusNoContent)
		} else {
			jsonError(w, http.StatusMethodNotAllowed, "invalid write method")
		}
		return
	}

	// fail early if we're missing the database
	if r.URL.Query().Get("db") == "" {
		jsonError(w, http.StatusBadRequest, "missing parameter: db")
		return
	}

	var body = r.Body

	if r.Header.Get("Content-Encoding") == "gzip" {
		b, err := gzip.NewReader(r.Body)
		if err != nil {
			jsonError(w, http.StatusBadRequest, "unable to decode gzip body")
		}
		defer b.Close()
		body = b
	}

	bodyBuf := getBuf()
	_, err := bodyBuf.ReadFrom(body)
	if err != nil {
		putBuf(bodyBuf)
		jsonError(w, http.StatusInternalServerError, "problem reading request body")
		return
	}

	precision := r.URL.Query().Get("precision")
	points, err := models.ParsePointsWithPrecision(bodyBuf.Bytes(), start, precision)
	if err != nil {
		putBuf(bodyBuf)
		jsonError(w, http.StatusBadRequest, "unable to parse points")
		return
	}

	outBuf := getBuf()
	for _, p := range points {
		if _, err = outBuf.WriteString(p.PrecisionString(precision)); err != nil {
			break
		}
		if err = outBuf.WriteByte('\n'); err != nil {
			break
		}
	}

	// done with the input points
	putBuf(bodyBuf)

	if err != nil {
		putBuf(outBuf)
		jsonError(w, http.StatusInternalServerError, "problem writing points")
		return
	}

	// normalize query string
	query := r.URL.Query().Encode()

	outBytes := outBuf.Bytes()

	var wg sync.WaitGroup
	wg.Add(len(h.backends))

	var responses = make(chan *responseData, len(h.backends))

	for _, b := range h.backends {
		b := b
		go func() {
			defer wg.Done()
			resp, err := b.post(outBytes, query)
			if err != nil {
				log.Printf("Problem posting to relay %q backend %q: %v", h.Name(), b.name, err)
			} else {
				if resp.StatusCode/100 == 5 {
					log.Printf("5xx response for relay %q backend %q: %v", h.Name(), b.name, resp.StatusCode)
				}
				responses <- resp
			}
		}()
	}

	go func() {
		wg.Wait()
		close(responses)
		putBuf(outBuf)
	}()

	var errResponse *responseData

	for resp := range responses {
		switch resp.StatusCode / 100 {
		case 2:
			w.WriteHeader(http.StatusNoContent)
			return

		case 4:
			// user error
			resp.Write(w)
			return

		default:
			// hold on to one of the responses to return back to the client
			errResponse = resp
		}
	}

	// no successful writes
	if errResponse == nil {
		// failed to make any valid request...
		jsonError(w, http.StatusServiceUnavailable, "unable to write points")
		return
	}

	errResponse.Write(w)
}

type responseData struct {
	ContentType     string
	ContentEncoding string
	StatusCode      int
	Body            []byte
}

func (rd *responseData) Write(w http.ResponseWriter) {
	if rd.ContentType != "" {
		w.Header().Set("Content-Type", rd.ContentType)
	}

	if rd.ContentEncoding != "" {
		w.Header().Set("Content-Encoding", rd.ContentEncoding)
	}

	w.Header().Set("Content-Length", strconv.Itoa(len(rd.Body)))
	w.WriteHeader(rd.StatusCode)
	w.Write(rd.Body)
}

func jsonError(w http.ResponseWriter, code int, message string) {
	w.Header().Set("Content-Type", "application/json")
	data := fmt.Sprintf("{\"error\":%q}\n", message)
	w.Header().Set("Content-Length", fmt.Sprint(len(data)))
	w.WriteHeader(code)
	w.Write([]byte(data))
}

type poster interface {
	post([]byte, string) (*responseData, error)
}

type simplePoster struct {
	client   *http.Client
	location string
}

func newSimplePoster(location string, timeout time.Duration) *simplePoster {
	return &simplePoster{
		client:   &http.Client{Timeout: timeout},
		location: location,
	}
}

func (b *simplePoster) post(buf []byte, query string) (*responseData, error) {
	req, err := http.NewRequest("POST", b.location, bytes.NewReader(buf))
	if err != nil {
		return nil, err
	}

	req.URL.RawQuery = query
	req.Header.Set("Content-Type", "text/plain")
	req.Header.Set("Content-Length", strconv.Itoa(len(buf)))

	resp, err := b.client.Do(req)
	if err != nil {
		return nil, err
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if err = resp.Body.Close(); err != nil {
		return nil, err
	}

	return &responseData{
		ContentType:     resp.Header.Get("Conent-Type"),
		ContentEncoding: resp.Header.Get("Conent-Encoding"),
		StatusCode:      resp.StatusCode,
		Body:            data,
	}, nil
}

type httpBackend struct {
	poster
	name string
}

func newHTTPBackend(cfg *HTTPOutputConfig) (*httpBackend, error) {
	if cfg.Name == "" {
		cfg.Name = cfg.Location
	}

	timeout := DefaultHTTPTimeout
	if cfg.Timeout != "" {
		t, err := time.ParseDuration(cfg.Timeout)
		if err != nil {
			return nil, fmt.Errorf("error parsing HTTP timeout '%v'", err)
		}
		timeout = t
	}

	var p poster = newSimplePoster(cfg.Location, timeout)

	// If configured, create a retryBuffer per backend.
	// This way we serialize retries against each backend.
	if cfg.BufferSizeMB > 0 {
		max := DefaultMaxDelayInterval
		if cfg.MaxDelayInterval != "" {
			m, err := time.ParseDuration(cfg.MaxDelayInterval)
			if err != nil {
				return nil, fmt.Errorf("error parsing max retry time %v", err)
			}
			max = m
		}

		batch := DefaultBatchSizeKB * KB
		if cfg.MaxBatchKB > 0 {
			batch = cfg.MaxBatchKB * KB
		}

		p = newRetryBuffer(cfg.BufferSizeMB*MB, batch, max, p)
	}

	return &httpBackend{
		poster: p,
		name:   cfg.Name,
	}, nil
}

var ErrBufferFull = errors.New("retry buffer full")

var bufPool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}

func getBuf() *bytes.Buffer {
	if bb, ok := bufPool.Get().(*bytes.Buffer); ok {
		return bb
	}
	return new(bytes.Buffer)
}

func putBuf(b *bytes.Buffer) {
	b.Reset()
	bufPool.Put(b)
}
<|endoftext|>


<commit_before>package render

import (
	"encoding/xml"
	"io"
)

type xmlRenderer struct {
	value interface{}
}

func (s xmlRenderer) ContentType() string {
	return "application/xml"
}

func (s xmlRenderer) Render(w io.Writer, data Data) error {
	return xml.NewEncoder(w).Encode(s.value)
}

// XML renders the value using the "application/xml"
// content type.
func XML(v interface{}) Renderer {
	return xmlRenderer{value: v}
}

// XML renders the value using the "application/xml"
// content type.
func (e *Engine) XML(v interface{}) Renderer {
	return XML(v)
}
<commit_msg>indent xml<commit_after>package render

import (
	"encoding/xml"
	"io"
)

type xmlRenderer struct {
	value interface{}
}

func (s xmlRenderer) ContentType() string {
	return "application/xml"
}

func (s xmlRenderer) Render(w io.Writer, data Data) error {
	enc := xml.NewEncoder(w)
	enc.Indent("", "  ")
	return enc.Encode(s.value)
}

// XML renders the value using the "application/xml"
// content type.
func XML(v interface{}) Renderer {
	return xmlRenderer{value: v}
}

// XML renders the value using the "application/xml"
// content type.
func (e *Engine) XML(v interface{}) Renderer {
	return XML(v)
}
<|endoftext|>