<commit_before>package form

import (
	"encoding/json"
	"mime/multipart"
	"net/http"
	"net/url"
)

type value struct {
	Form          url.Values
	PostForm      url.Values
	MultipartForm *multipart.Form
}

func newValue(r *http.Request) *value {
	v := &value{}
	count := 0
	if r.Form != nil {
		if len(r.Form) > 0 {
			v.Form = url.Values{}
		}
		for key, value := range r.Form {
			count++
			v.Form[key] = append(v.Form[key], value...)
		}
	}
	if r.PostForm != nil {
		if len(r.PostForm) > 0 {
			v.PostForm = url.Values{}
		}
		for key, value := range r.PostForm {
			count++
			v.PostForm[key] = append(v.PostForm[key], value...)
		}
	}
	if r.MultipartForm != nil {
		if len(r.MultipartForm.Value) > 0 {
			if v.MultipartForm == nil {
				v.MultipartForm = &multipart.Form{}
			}
			v.MultipartForm.Value = map[string][]string{}
		}
		for key, value := range r.MultipartForm.Value {
			count++
			v.MultipartForm.Value[key] = append(v.MultipartForm.Value[key], value...)
		}
		if len(r.MultipartForm.File) > 0 {
			if v.MultipartForm == nil {
				v.MultipartForm = &multipart.Form{}
			}
			v.MultipartForm.File = map[string][]*multipart.FileHeader{}
		}
		for key, value := range r.MultipartForm.File {
			count++
			v.MultipartForm.File[key] = append(v.MultipartForm.File[key], value...)
		}
	}
	if count == 0 {
		return nil
	}
	return v
}

func newValueSerializeArray(r *http.Request) *value {
	v := &value{PostForm: url.Values{}}

	data := []struct {
		Name  string `json:"name"`
		Value string `json:"value"`
	}{}

	jDec := json.NewDecoder(r.Body)
	defer r.Body.Close()

	jDec.Decode(&data)

	for _, item := range data {
		v.PostForm[item.Name] = append(v.PostForm[item.Name], item.Value)
	}

	return v
}

func (r *value) Shift(name string) string {
	str := ""
	if r.MultipartForm != nil && len(r.MultipartForm.Value[name]) > 0 {
		if len(r.MultipartForm.Value[name]) <= 1 {
			if len(r.MultipartForm.Value[name]) == 1 {
				str = r.MultipartForm.Value[name][0]
			}
			delete(r.MultipartForm.Value, name)
		} else {
			str, r.MultipartForm.Value[name] =
				r.MultipartForm.Value[name][0], r.MultipartForm.Value[name][1:]
		}
	} else if r.Form != nil && len(r.Form[name]) > 0 {
		if len(r.Form[name]) <= 1 {
			if len(r.Form[name]) == 1 {
				str = r.Form[name][0]
			}
			delete(r.Form, name)
		} else {
			str, r.Form[name] =
				r.Form[name][0], r.Form[name][1:]
		}
	} else if r.PostForm != nil && len(r.PostForm[name]) > 0 {
		if len(r.PostForm[name]) <= 1 {
			if len(r.PostForm[name]) == 1 {
				str = r.PostForm[name][0]
			}
			delete(r.PostForm, name)
		} else {
			str, r.PostForm[name] =
				r.PostForm[name][0], r.PostForm[name][1:]
		}
	}
	return str
}

func (r *value) All(name string) []string {
	strs := []string{}
	if r.MultipartForm != nil && len(r.MultipartForm.Value[name]) > 0 {
		strs = r.MultipartForm.Value[name]
		delete(r.MultipartForm.Value, name)
	} else if r.Form != nil && len(r.Form[name]) > 0 {
		strs = r.Form[name]
		delete(r.Form, name)
	} else if r.PostForm != nil && len(r.PostForm[name]) > 0 {
		strs = r.PostForm[name]
		delete(r.PostForm, name)
	}
	return strs
}

func (r *value) FileShift(name string) *multipart.FileHeader {
	var fileHeader *multipart.FileHeader
	if r.MultipartForm != nil && len(r.MultipartForm.File[name]) > 0 {
		if len(r.MultipartForm.File[name]) <= 1 {
			if len(r.MultipartForm.File[name]) == 1 {
				fileHeader = r.MultipartForm.File[name][0]
			}
			delete(r.MultipartForm.File, name)
		} else {
			fileHeader, r.MultipartForm.File[name] =
				r.MultipartForm.File[name][0], r.MultipartForm.File[name][1:]
		}
	}
	return fileHeader
}
<commit_msg>Improved efficency of dealing with form values<commit_after>package form

import (
	"encoding/json"
	"mime/multipart"
	"net/http"
	"net/url"
)

type value struct {
	Form                url.Values
	PostForm            url.Values
	MultipartForm       *multipart.Form
	formCount           map[string]int
	postFormCount       map[string]int
	multipartValueCount map[string]int
	multipartFileCount  map[string]int
}

func newValue(r *http.Request) *value {
	v := &value{}
	count := 0
	if r.Form != nil {
		if len(r.Form) > 0 {
			v.Form = r.Form
			count++
		}
	}
	if r.PostForm != nil {
		if len(r.PostForm) > 0 {
			v.PostForm = r.PostForm
			count++
		}
	}
	if r.MultipartForm != nil {
		v.MultipartForm = r.MultipartForm
		count++
	}
	if count == 0 {
		return nil
	}
	v.formCount = map[string]int{}
	v.postFormCount = map[string]int{}
	v.multipartValueCount = map[string]int{}
	v.multipartFileCount = map[string]int{}
	return v
}

func newValueSerializeArray(r *http.Request) *value {
	v := &value{PostForm: url.Values{}}

	data := []struct {
		Name  string `json:"name"`
		Value string `json:"value"`
	}{}

	jDec := json.NewDecoder(r.Body)
	defer r.Body.Close()

	jDec.Decode(&data)

	for _, item := range data {
		v.PostForm[item.Name] = append(v.PostForm[item.Name], item.Value)
	}
	v.formCount = map[string]int{}
	v.postFormCount = map[string]int{}
	v.multipartValueCount = map[string]int{}
	v.multipartFileCount = map[string]int{}
	return v
}

func (r *value) Shift(name string) (str string) {
	switch {
	case r.MultipartForm != nil &&
		len(r.MultipartForm.Value[name]) > r.multipartValueCount[name]:

		str = r.MultipartForm.Value[name][r.multipartValueCount[name]]
		r.multipartValueCount[name]++

	case r.Form != nil &&
		len(r.Form[name]) > r.formCount[name]:

		str = r.Form[name][r.formCount[name]]
		r.formCount[name]++

	case r.PostForm != nil &&
		len(r.PostForm[name]) > r.postFormCount[name]:

		str = r.PostForm[name][r.postFormCount[name]]
		r.postFormCount[name]++
	}

	return
}

func (r *value) All(name string) []string {
	strs := []string{}

	switch {
	case r.MultipartForm != nil &&
		len(r.MultipartForm.Value[name]) > r.multipartValueCount[name]:

		strs = r.MultipartForm.Value[name][r.multipartValueCount[name]:]
		r.multipartValueCount[name] = len(r.MultipartForm.Value[name])

	case r.Form != nil &&
		len(r.Form[name]) > r.formCount[name]:

		strs = r.Form[name][r.formCount[name]:]
		r.formCount[name] = len(r.Form[name])

	case r.PostForm != nil &&
		len(r.PostForm[name]) > r.postFormCount[name]:

		strs = r.PostForm[name][r.postFormCount[name]:]
		r.postFormCount[name] = len(r.PostForm[name])
	}

	return strs
}

func (r *value) FileShift(name string) (fileHeader *multipart.FileHeader) {
	if r.MultipartForm != nil &&
		len(r.MultipartForm.File[name]) > r.multipartFileCount[name] {

		fileHeader = r.MultipartForm.File[name][r.multipartFileCount[name]]
		r.multipartFileCount[name]++

	}

	return
}
<|endoftext|>


<commit_before>package goose

import (
	"database/sql"
)

// SqlDialect abstracts the details of specific SQL dialects
// for goose's few SQL specific statements
type SqlDialect interface {
	createVersionTableSql() string // sql string to create the goose_db_version table
	insertVersionSql() string      // sql string to insert the initial version table row
	dbVersionQuery(db *sql.DB) (*sql.Rows, error)
}

// drivers that we don't know about can ask for a dialect by name
func dialectByName(d string) SqlDialect {
	switch d {
	case "postgres":
		return &PostgresDialect{}
	case "mysql":
		return &MySqlDialect{}
	case "redshift":
		return &RedshiftDialect{}
	}

	return nil
}

////////////////////////////
// Postgres
////////////////////////////

type PostgresDialect struct{}

func (pg PostgresDialect) createVersionTableSql() string {
	return `CREATE TABLE goose_db_version (
            	id serial NOT NULL,
                version_id bigint NOT NULL,
                is_applied boolean NOT NULL,
                tstamp timestamp NULL default now(),
                PRIMARY KEY(id)
            );`
}

func (pg PostgresDialect) insertVersionSql() string {
	return "INSERT INTO goose_db_version (version_id, is_applied) VALUES ($1, $2);"
}

func (pg PostgresDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
	rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY id DESC")

	// XXX: check for postgres specific error indicating the table doesn't exist.
	// for now, assume any error is because the table doesn't exist,
	// in which case we'll try to create it.
	if err != nil {
		return nil, ErrTableDoesNotExist
	}

	return rows, err
}

////////////////////////////
// MySQL
////////////////////////////

type MySqlDialect struct{}

func (m MySqlDialect) createVersionTableSql() string {
	return `CREATE TABLE goose_db_version (
                id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
                version_id bigint NOT NULL,
                is_applied boolean NOT NULL,
                tstamp timestamp NULL default now(),
                PRIMARY KEY(id)
            );`
}

func (m MySqlDialect) insertVersionSql() string {
	return "INSERT INTO goose_db_version (version_id, is_applied) VALUES (?, ?);"
}

func (m MySqlDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
	rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY id DESC")

	// XXX: check for mysql specific error indicating the table doesn't exist.
	// for now, assume any error is because the table doesn't exist,
	// in which case we'll try to create it.
	if err != nil {
		return nil, ErrTableDoesNotExist
	}

	return rows, err
}

////////////////////////////
// Redshift
////////////////////////////

type RedshiftDialect struct{}

func (rs RedshiftDialect) createVersionTableSql() string {
	return `CREATE TABLE goose_db_version (
                id integer NOT NULL identity(1, 1),
                version_id bigint NOT NULL,
                is_applied boolean NOT NULL,
                tstamp timestamp NULL default sysdate,
                PRIMARY KEY(id)
            );`
}

func (rs RedshiftDialect) insertVersionSql() string {
	return "INSERT INTO goose_db_version (version_id, is_applied) VALUES ($1, $2);"
}

func (rs RedshiftDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
	rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY id DESC")
	if err != nil {
		return nil, err
	}

	return rows, err
}
<commit_msg>Detect when the migration table does not exist in Redshift<commit_after>package goose

import (
	"database/sql"

	"github.com/lib/pq"
)

// SqlDialect abstracts the details of specific SQL dialects
// for goose's few SQL specific statements
type SqlDialect interface {
	createVersionTableSql() string // sql string to create the goose_db_version table
	insertVersionSql() string      // sql string to insert the initial version table row
	dbVersionQuery(db *sql.DB) (*sql.Rows, error)
}

// drivers that we don't know about can ask for a dialect by name
func dialectByName(d string) SqlDialect {
	switch d {
	case "postgres":
		return &PostgresDialect{}
	case "mysql":
		return &MySqlDialect{}
	case "redshift":
		return &RedshiftDialect{}
	}

	return nil
}

////////////////////////////
// Postgres
////////////////////////////

type PostgresDialect struct{}

func (pg PostgresDialect) createVersionTableSql() string {
	return `CREATE TABLE goose_db_version (
            	id serial NOT NULL,
                version_id bigint NOT NULL,
                is_applied boolean NOT NULL,
                tstamp timestamp NULL default now(),
                PRIMARY KEY(id)
            );`
}

func (pg PostgresDialect) insertVersionSql() string {
	return "INSERT INTO goose_db_version (version_id, is_applied) VALUES ($1, $2);"
}

func (pg PostgresDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
	rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY id DESC")

	// XXX: check for postgres specific error indicating the table doesn't exist.
	// for now, assume any error is because the table doesn't exist,
	// in which case we'll try to create it.
	if err != nil {
		return nil, ErrTableDoesNotExist
	}

	return rows, err
}

////////////////////////////
// MySQL
////////////////////////////

type MySqlDialect struct{}

func (m MySqlDialect) createVersionTableSql() string {
	return `CREATE TABLE goose_db_version (
                id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
                version_id bigint NOT NULL,
                is_applied boolean NOT NULL,
                tstamp timestamp NULL default now(),
                PRIMARY KEY(id)
            );`
}

func (m MySqlDialect) insertVersionSql() string {
	return "INSERT INTO goose_db_version (version_id, is_applied) VALUES (?, ?);"
}

func (m MySqlDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
	rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY id DESC")

	// XXX: check for mysql specific error indicating the table doesn't exist.
	// for now, assume any error is because the table doesn't exist,
	// in which case we'll try to create it.
	if err != nil {
		return nil, ErrTableDoesNotExist
	}

	return rows, err
}

////////////////////////////
// Redshift
////////////////////////////

type RedshiftDialect struct{}

func (rs RedshiftDialect) createVersionTableSql() string {
	return `CREATE TABLE goose_db_version (
                id integer NOT NULL identity(1, 1),
                version_id bigint NOT NULL,
                is_applied boolean NOT NULL,
                tstamp timestamp NULL default sysdate,
                PRIMARY KEY(id)
            );`
}

func (rs RedshiftDialect) insertVersionSql() string {
	return "INSERT INTO goose_db_version (version_id, is_applied) VALUES ($1, $2);"
}

func (rs RedshiftDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
	rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY id DESC")
	if err, ok := err.(*pq.Error); ok {
		if err.Code == "42P01" {
			// pq error: undefined_table
			return nil, ErrTableDoesNotExist
		}
	}

	if err != nil {
		return nil, err
	}

	return rows, err
}
<|endoftext|>


<commit_before>package jd

import (
	"testing"
)

func TestMultisetJson(t *testing.T) {
	checkJson(t, `[]`, `[]`, MULTISET)
	checkJson(t, ` [ ] `, `[]`, MULTISET)
	checkJson(t, `[1,2,3]`, `[1,2,3]`, MULTISET)
	checkJson(t, ` [1, 2, 3] `, `[1,2,3]`, MULTISET)
	checkJson(t, `[1,1,1]`, `[1,1,1]`, MULTISET)
}

func TestMultisetEquals(t *testing.T) {
	checkEqual(t, `[]`, `[]`, MULTISET)
	checkEqual(t, `[1,2,3]`, `[3,2,1]`, MULTISET)
	checkEqual(t, `[1,2,3]`, `[2,3,1]`, MULTISET)
	checkEqual(t, `[1,2,3]`, `[1,3,2]`, MULTISET)
	checkEqual(t, `[{},{}]`, `[{},{}]`, MULTISET)
	checkEqual(t, `[[1,2],[3,4]]`, `[[2,1],[4,3]]`, MULTISET)
}

func TestMultisetNotEquals(t *testing.T) {
	checkNotEqual(t, `[]`, `[1]`, MULTISET)
	checkNotEqual(t, `[1,2,3]`, `[1,2,2]`, MULTISET)
	checkNotEqual(t, `[1,2,3]`, `[1,2]`, MULTISET)
	checkNotEqual(t, `[[],[1]]`, `[[],[2]]`, MULTISET)
}

func TestMultisetDiff(t *testing.T) {
	checkDiffMetadata(t, MULTISET, `[]`, `[]`)
	checkDiffMetadata(t, MULTISET, `[1]`, `[1,2]`,
		`@ [{}]`,
		`+ 2`)
	checkDiffMetadata(t, MULTISET, `[1,2]`, `[1,2]`)
	checkDiffMetadata(t, MULTISET, `[1]`, `[1,2,2]`,
		`@ [{}]`,
		`+ 2`,
		`+ 2`)
	checkDiffMetadata(t, MULTISET, `[1,2,3]`, `[1,3]`,
		`@ [{}]`,
		`- 2`)
	checkDiffMetadata(t, MULTISET, `[{"a":1}]`, `[{"a":2}]`,
		`@ [{}]`,
		`- {"a":1}`,
		`+ {"a":2}`)
	checkDiffMetadata(t, MULTISET, `[{"a":1},{"a":1}]`, `[{"a":2}]`,
		`@ [{}]`,
		`- {"a":1}`,
		`- {"a":1}`,
		`+ {"a":2}`)
	checkDiffMetadata(t, MULTISET, `["foo","foo","bar"]`, `["baz"]`,
		`@ [{}]`,
		`- "bar"`,
		`- "foo"`,
		`- "foo"`,
		`+ "baz"`)
	checkDiffMetadata(t, MULTISET, `["foo"]`, `["bar","baz","bar"]`,
		`@ [{}]`,
		`- "foo"`,
		`+ "bar"`,
		`+ "bar"`,
		`+ "baz"`)
	checkDiffMetadata(t, MULTISET, `{}`, `[]`,
		`@ []`,
		`- {}`,
		`+ []`)
}

func TestMultisetPatch(t *testing.T) {
	checkPatchMetadata(t, MULTISET, `[]`, `[]`)
	checkPatchMetadata(t, MULTISET, `[1]`, `[1,2]`,
		`@ [{}]`,
		`+ 2`)
	checkPatchMetadata(t, MULTISET, `[1,2]`, `[1,2]`)
	checkPatchMetadata(t, MULTISET, `[1]`, `[1,2,2]`,
		`@ [{}]`,
		`+ 2`,
		`+ 2`)
	checkPatchMetadata(t, MULTISET, `[1,2,3]`, `[1,3]`,
		`@ [{}]`,
		`- 2`)
	checkPatchMetadata(t, MULTISET, `[{"a":1}]`, `[{"a":2}]`,
		`@ [{}]`,
		`- {"a":1}`,
		`+ {"a":2}`)
	checkPatchMetadata(t, MULTISET, `[{"a":1},{"a":1}]`, `[{"a":2}]`,
		`@ [{}]`,
		`- {"a":1}`,
		`- {"a":1}`,
		`+ {"a":2}`)
	checkPatchMetadata(t, MULTISET, `["foo","foo","bar"]`, `["baz"]`,
		`@ [{}]`,
		`- "bar"`,
		`- "foo"`,
		`- "foo"`,
		`+ "baz"`)
	checkPatchMetadata(t, MULTISET, `["foo"]`, `["bar","baz","bar"]`,
		`@ [{}]`,
		`- "foo"`,
		`+ "bar"`,
		`+ "bar"`,
		`+ "baz"`)
	checkPatchMetadata(t, MULTISET, `{}`, `[]`,
		`@ []`,
		`- {}`,
		`+ []`)
}

func TestMultisetPatchError(t *testing.T) {
	checkPatchErrorMetadata(t, MULTISET, `[]`,
		`@ [{}]`,
		`- 1`)
	checkPatchErrorMetadata(t, MULTISET, `[1]`,
		`@ [{}]`,
		`- 1`,
		`- 1`)
	checkPatchErrorMetadata(t, MULTISET, `[]`,
		`@ [{}]`,
		`- 1`,
		`+ 1`)
	checkPatchErrorMetadata(t, MULTISET, `[]`,
		`@ []`,
		`- {}`)
}
<commit_msg>Convert multiset tests to table tests.<commit_after>package jd

import (
	"testing"
)

func TestMultisetJson(t *testing.T) {
	cases := []struct {
		name     string
		metadata Metadata
		given    string
		want     string
	}{{
		name:     "empty mulitset",
		metadata: MULTISET,
		given:    `[]`,
		want:     `[]`,
	}, {
		name:     "empty multiset with space",
		metadata: MULTISET,
		given:    ` [ ] `,
		want:     `[]`,
	}, {
		name:     "ordered multiset",
		metadata: MULTISET,
		given:    `[1,2,3]`,
		want:     `[1,2,3]`,
	}, {
		name:     "ordered multiset with space",
		metadata: MULTISET,
		given:    ` [1, 2, 3] `,
		want:     `[1,2,3]`,
	}, {
		name:     "multset with multiple duplicates",
		metadata: MULTISET,
		given:    `[1,1,1]`,
		want:     `[1,1,1]`,
	}}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			ctx := newTestContext(t).
				withReadMetadata(c.metadata)
			checkJson(ctx, c.given, c.want)
			ctx := newTestContext(t).
				withApplyMetadata(c.metadata)
			checkJson(ctx, c.given, c.want)
		})
	}
}

func TestMultisetEquals(t *testing.T) {
	cases := []struct {
		name     string
		metadata Metadata
		a        string
		b        string
	}{{
		name:     "empty multisets",
		metadata: MULTISET,
		a:        `[]`,
		b:        `[]`,
	}, {
		name:     "different ordered multisets 1",
		metadata: MULTISET,
		a:        `[1,2,3]`,
		b:        `[3,2,1]`,
	}, {
		name:     "different ordered multisets 2",
		metadata: MULTISET,
		a:        `[1,2,3]`,
		b:        `[2,3,1]`,
	}, {
		name:     "different ordered multisets 2",
		metadata: MULTISET,
		a:        `[1,2,3]`,
		b:        `[1,3,2]`,
	}, {
		name:     "multsets with empty objects",
		metadata: MULTISET,
		a:        `[{},{}]`,
		b:        `[{},{}]`,
	}, {
		name:     "nested multisets",
		metadata: MULTISET,
		a:        `[[1,2],[3,4]]`,
		b:        `[[2,1],[4,3]]`,
	}}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			ctx := newTestContext(t).
				withReadMetadata(c.metadata)
			checkEqual(ctx, c.a, c.b)
			ctx = newTestContext(t).
				withApplyMetadata(c.metadata)
			checkEqual(ctx, c.a, c.b)
		})
	}
}

func TestMultisetNotEquals(t *testing.T) {
	cases := []struct {
		name     string
		metadata Metadata
		a        string
		b        string
	}{{
		name:     "empty multiset and multiset with number",
		metadata: MULTISET,
		a:        `[]`,
		b:        `[1]`,
	}, {
		name:     "multisets with different numbers",
		metadata: MULTISET,
		a:        `[1,2,3]`,
		b:        `[1,2,2]`,
	}, {
		name:     "multiset missing a number",
		metadata: MULTISET,
		a:        `[1,2,3]`,
		b:        `[1,2]`,
	}, {
		name:     "nested multisets with different numbers",
		a:        `[[],[1]]`,
		b:        `[[],[2]]`,
		metadata: MULTISET,
	}}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			ctx := newTestContext(t).
				withReadMetadata(c.metadata)
			checkNotEqual(ctx, c.a, c.b)
			ctx := newTestContext(t).
				withApplyMetadata(c.metadata)
			checkNotEqual(ctx, c.a, c.b)
		})
	}
}

func TestMultisetDiff(t *testing.T) {
	cases := []struct {
		name     string
		metadata Metadata
		a        string
		b        string
		want     []string
	}{{
		name:     "two empty multisets",
		metadata: MULTISET,
		a:        `[]`,
		b:        `[]`,
		want:     {``},
	}, {
		name:     "two multisets with different numbers",
		metadata: MULTISET,
		a:        `[1]`,
		b:        `[1,2]`,
		want: {
			`@ q[{}]`,
			`+ 2`,
		},
	}, {
		name:     "two multisets with the same number",
		metadata: MULTISET,
		a:        `[1,2]`,
		b:        `[1,2]`,
		want:     {``},
	}, {
		name:     "adding two numbers",
		metadata: MULTISET,
		a:        `[1]`,
		b:        `[1,2,2]`,
		want: {
			`@ [{}]`,
			`+ 2`,
			`+ 2`,
		},
	}, {
		name:     "removing a number",
		metadata: MULTISET,
		a:        `[1,2,3]`,
		b:        `[1,3]`,
		want: {
			`@ [{}]`,
			`- 2`,
		},
	}, {
		name:     "replacing one object with another",
		metadata: MULTISET,
		a:        `[{"a":1}]`,
		b:        `[{"a":2}]`,
		want: {
			`@ [{}]`,
			`- {"a":1}`,
			`+ {"a":2}`,
		},
	}, {
		name:     "replacing two objects with one object",
		metadata: MULTISET,
		a:        `[{"a":1},{"a":1}]`,
		b:        `[{"a":2}]`,
		want: {
			`@ [{}]`,
			`- {"a":1}`,
			`- {"a":1}`,
			`+ {"a":2}`,
		},
	}, {
		name:     "replacing three strings repeated with one string",
		metadata: MULTISET,
		a:        `["foo","foo","bar"]`,
		b:        `["baz"]`,
		want: {
			`@ [{}]`,
			`- "bar"`,
			`- "foo"`,
			`- "foo"`,
			`+ "baz"`,
		},
	}, {
		name:     "replacing one string with three repeated",
		metadata: MULTISET,
		a:        `["foo"]`,
		b:        `["bar","baz","bar"]`,
		want: {
			`@ [{}]`,
			`- "foo"`,
			`+ "bar"`,
			`+ "bar"`,
			`+ "baz"`,
		},
	}, {
		name:     "replacing multiset with array",
		metadata: MULTISET,
		a:        `{}`,
		b:        `[]`,
		want: {
			`@ []`,
			`- {}`,
			`+ []`,
		},
	}}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			ctx := newTestContext(t).
				withReadMetadata(c.metadata)
			checkDiff(ctx, c.a, c.b, c.want...)
			ctx = newTestContext(t).
				withApplyMetadata(c.metadata)
			checkDiff(ctx, c.a, c.b, c.want...)
		})
	}
}

func TestMultisetPatch(t *testing.T) {
	cases := []struct {
		name     string
		metadata Metadata
		given    string
		patch    []string
		want     string
	}{{
		name:     "empty patch on empty multiset",
		metadata: MULTISET,
		given:    `[]`,
		patch:    {``},
		want:     `[]`,
	}, {
		name:     "add a number",
		metadata: MULTISET,
		given:    `[1]`,
		patch: {
			`@ [{}]`,
			`+ 2`,
		},
		want: `[1,2]`,
	}, {
		name:     "empty patch on multiset with numbers",
		metadata: MULTISET,
		given:    `[1,2]`,
		patch:    {``},
		want:     `[1,2]`,
	}, {
		name:     "add two numbers",
		metadata: MULTISET,
		given:    `[1]`,
		patch: {
			`@ [{}]`,
			`+ 2`,
			`+ 2`,
		},
		want: `[1,2,2]`,
	}, {
		name:     "remove a number",
		metadata: MULTISET,
		given:    `[1,2,3]`,
		patch: {
			`@ [{}]`,
			`- 2`,
		},
		want: `[1,3]`,
	}, {
		want:     "replace one object with another",
		metadata: MULTISET,
		given:    `[{"a":1}]`,
		patch: {
			`@ [{}]`,
			`- {"a":1}`,
			`+ {"a":2}`,
		},
		want: `[{"a":2}]`,
	}, {
		name:     "remove two objects and add one",
		metadata: MULTISET,
		given:    `[{"a":1},{"a":1}]`,
		patch: {
			`@ [{}]`,
			`- {"a":1}`,
			`- {"a":1}`,
			`+ {"a":2}`,
		},
		want: `[{"a":2}]`,
	}, {
		name:     "remove three objects repeated and add one",
		metadata: MULTISET,
		given:    `["foo","foo","bar"]`,
		patch: {
			`@ [{}]`,
			`- "bar"`,
			`- "foo"`,
			`- "foo"`,
			`+ "baz"`,
		},
		want: `["baz"]`,
	}, {
		name:     "remove one object and add three repeated",
		metadata: MULTISET,
		given:    `["foo"]`,
		patch: {
			`@ [{}]`,
			`- "foo"`,
			`+ "bar"`,
			`+ "bar"`,
			`+ "baz"`,
		},
		want: `["bar","baz","bar"]`,
	}, {
		name:     "replace multiset with array",
		metadata: MULTISET,
		given:    `{}`,
		patch: {
			`@ []`,
			`- {}`,
			`+ []`,
		},
		want: `[]`,
	}}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			ctx := newTestContext(t).
				withReadMetadata(c.metadata)
			checkPatch(ctx, c.given, c.want, c.patch...)
			ctx = newTestContext(t).
				withApplyMetadata(c.metadata)
			checkPatch(ctx, c.given, c.want, c.patch...)
		})
	}
}

func TestMultisetPatchError(t *testing.T) {
	cases := []struct {
		name     string
		metadata Metadata
		given    string
		patch    []string
	}{{
		name:     "remove number from empty multiset",
		metadata: MULTISET,
		given:    `[]`,
		patch: {
			`@ [{}]`,
			`- 1`,
		},
	}, {
		name:     "remove a single number twice",
		metadata: MULTISET,
		given:    `[1]`,
		patch: {
			`@ [{}]`,
			`- 1`,
			`- 1`,
		},
	}, {
		name:     "remove an object when there is a multiset",
		metadata: MULTISET,
		given:    `[]`,
		patch: {
			`@ []`,
			`- {}`,
		},
	}}
}
<|endoftext|>


<commit_before>package native

var (
	pkgMap = map[string]bool{}
	pkgs   = []string{
		"archive",
		"archive/tar",
		"archive/tar/testdata",
		"archive/zip",
		"archive/zip/testdata",
		"bufio",
		"builtin",
		"bytes",
		"cmd",
		"cmd/addr2line",
		"cmd/api",
		"cmd/api/testdata",
		"cmd/api/testdata/src",
		"cmd/api/testdata/src/pkg",
		"cmd/api/testdata/src/pkg/p1",
		"cmd/api/testdata/src/pkg/p2",
		"cmd/api/testdata/src/pkg/p3",
		"cmd/asm",
		"cmd/asm/internal",
		"cmd/asm/internal/arch",
		"cmd/asm/internal/asm",
		"cmd/asm/internal/asm/testdata",
		"cmd/asm/internal/flags",
		"cmd/asm/internal/lex",
		"cmd/cgo",
		"cmd/compile",
		"cmd/compile/internal",
		"cmd/compile/internal/amd64",
		"cmd/compile/internal/arm",
		"cmd/compile/internal/arm64",
		"cmd/compile/internal/big",
		"cmd/compile/internal/gc",
		"cmd/compile/internal/gc/builtin",
		"cmd/compile/internal/ppc64",
		"cmd/compile/internal/x86",
		"cmd/cover",
		"cmd/cover/testdata",
		"cmd/dist",
		"cmd/doc",
		"cmd/doc/testdata",
		"cmd/fix",
		"cmd/go",
		"cmd/go/testdata",
		"cmd/go/testdata/cgocover",
		"cmd/go/testdata/failssh",
		"cmd/go/testdata/generate",
		"cmd/go/testdata/importcom",
		"cmd/go/testdata/importcom/src",
		"cmd/go/testdata/importcom/src/bad",
		"cmd/go/testdata/importcom/src/conflict",
		"cmd/go/testdata/importcom/src/works",
		"cmd/go/testdata/importcom/src/works/x",
		"cmd/go/testdata/importcom/src/wrongplace",
		"cmd/go/testdata/local",
		"cmd/go/testdata/local/easysub",
		"cmd/go/testdata/local/sub",
		"cmd/go/testdata/local/sub/sub",
		"cmd/go/testdata/norunexample",
		"cmd/go/testdata/rundir",
		"cmd/go/testdata/rundir/sub",
		"cmd/go/testdata/shadow",
		"cmd/go/testdata/shadow/root1",
		"cmd/go/testdata/shadow/root1/src",
		"cmd/go/testdata/shadow/root1/src/foo",
		"cmd/go/testdata/shadow/root1/src/math",
		"cmd/go/testdata/shadow/root2",
		"cmd/go/testdata/shadow/root2/src",
		"cmd/go/testdata/shadow/root2/src/foo",
		"cmd/go/testdata/src",
		"cmd/go/testdata/src/badc",
		"cmd/go/testdata/src/badpkg",
		"cmd/go/testdata/src/badtest",
		"cmd/go/testdata/src/badtest/badexec",
		"cmd/go/testdata/src/badtest/badsyntax",
		"cmd/go/testdata/src/badtest/badvar",
		"cmd/go/testdata/src/cgotest",
		"cmd/go/testdata/src/go-cmd-test",
		"cmd/go/testdata/src/main_test",
		"cmd/go/testdata/src/notest",
		"cmd/go/testdata/src/syntaxerror",
		"cmd/go/testdata/src/testcycle",
		"cmd/go/testdata/src/testcycle/p1",
		"cmd/go/testdata/src/testcycle/p2",
		"cmd/go/testdata/src/testcycle/p3",
		"cmd/go/testdata/src/testcycle/q1",
		"cmd/go/testdata/src/testdep",
		"cmd/go/testdata/src/testdep/p1",
		"cmd/go/testdata/src/testdep/p2",
		"cmd/go/testdata/src/testdep/p3",
		"cmd/go/testdata/src/vend",
		"cmd/go/testdata/src/vend/hello",
		"cmd/go/testdata/src/vend/subdir",
		"cmd/go/testdata/src/vend/vendor",
		"cmd/go/testdata/src/vend/vendor/p",
		"cmd/go/testdata/src/vend/vendor/q",
		"cmd/go/testdata/src/vend/vendor/strings",
		"cmd/go/testdata/src/vend/x",
		"cmd/go/testdata/src/vend/x/invalid",
		"cmd/go/testdata/src/vend/x/vendor",
		"cmd/go/testdata/src/vend/x/vendor/p",
		"cmd/go/testdata/src/vend/x/vendor/p/p",
		"cmd/go/testdata/src/vend/x/vendor/r",
		"cmd/go/testdata/src/vetpkg",
		"cmd/go/testdata/src/xtestonly",
		"cmd/go/testdata/testimport",
		"cmd/go/testdata/testimport/p1",
		"cmd/go/testdata/testimport/p2",
		"cmd/go/testdata/testinternal",
		"cmd/go/testdata/testinternal2",
		"cmd/go/testdata/testinternal2/x",
		"cmd/go/testdata/testinternal2/x/y",
		"cmd/go/testdata/testinternal2/x/y/z",
		"cmd/go/testdata/testinternal2/x/y/z/internal",
		"cmd/go/testdata/testinternal2/x/y/z/internal/w",
		"cmd/go/testdata/testinternal3",
		"cmd/go/testdata/testinternal4",
		"cmd/go/testdata/testinternal4/src",
		"cmd/go/testdata/testinternal4/src/p",
		"cmd/go/testdata/testinternal4/src/q",
		"cmd/go/testdata/testinternal4/src/q/internal",
		"cmd/go/testdata/testinternal4/src/q/internal/x",
		"cmd/go/testdata/testinternal4/src/q/j",
		"cmd/go/testdata/testonly",
		"cmd/go/testdata/testvendor",
		"cmd/go/testdata/testvendor/src",
		"cmd/go/testdata/testvendor/src/p",
		"cmd/go/testdata/testvendor/src/q",
		"cmd/go/testdata/testvendor/src/q/vendor",
		"cmd/go/testdata/testvendor/src/q/vendor/x",
		"cmd/go/testdata/testvendor/src/q/y",
		"cmd/go/testdata/testvendor/src/q/z",
		"cmd/go/testdata/testvendor2",
		"cmd/go/testdata/testvendor2/src",
		"cmd/go/testdata/testvendor2/src/p",
		"cmd/go/testdata/testvendor2/vendor",
		"cmd/go/testdata/testvendor2/vendor/x",
		"cmd/gofmt",
		"cmd/gofmt/testdata",
		"cmd/internal",
		"cmd/internal/gcprog",
		"cmd/internal/goobj",
		"cmd/internal/obj",
		"cmd/internal/obj/arm",
		"cmd/internal/obj/arm64",
		"cmd/internal/obj/ppc64",
		"cmd/internal/obj/x86",
		"cmd/internal/objfile",
		"cmd/internal/rsc.io",
		"cmd/internal/rsc.io/arm",
		"cmd/internal/rsc.io/arm/armasm",
		"cmd/internal/rsc.io/arm/armasm/testdata",
		"cmd/internal/rsc.io/x86",
		"cmd/internal/rsc.io/x86/x86asm",
		"cmd/internal/rsc.io/x86/x86asm/testdata",
		"cmd/link",
		"cmd/link/internal",
		"cmd/link/internal/amd64",
		"cmd/link/internal/arm",
		"cmd/link/internal/arm64",
		"cmd/link/internal/ld",
		"cmd/link/internal/ppc64",
		"cmd/link/internal/x86",
		"cmd/nm",
		"cmd/objdump",
		"cmd/objdump/testdata",
		"cmd/pack",
		"cmd/pprof",
		"cmd/pprof/internal",
		"cmd/pprof/internal/commands",
		"cmd/pprof/internal/driver",
		"cmd/pprof/internal/fetch",
		"cmd/pprof/internal/plugin",
		"cmd/pprof/internal/profile",
		"cmd/pprof/internal/report",
		"cmd/pprof/internal/svg",
		"cmd/pprof/internal/symbolizer",
		"cmd/pprof/internal/symbolz",
		"cmd/pprof/internal/tempfile",
		"cmd/trace",
		"cmd/vet",
		"cmd/vet/testdata",
		"cmd/vet/testdata/tagtest",
		"cmd/vet/whitelist",
		"cmd/yacc",
		"cmd/yacc/testdata",
		"cmd/yacc/testdata/expr",
		"compress",
		"compress/bzip2",
		"compress/bzip2/testdata",
		"compress/flate",
		"compress/gzip",
		"compress/gzip/testdata",
		"compress/lzw",
		"compress/testdata",
		"compress/zlib",
		"container",
		"container/heap",
		"container/list",
		"container/ring",
		"crypto",
		"crypto/aes",
		"crypto/cipher",
		"crypto/des",
		"crypto/dsa",
		"crypto/ecdsa",
		"crypto/ecdsa/testdata",
		"crypto/elliptic",
		"crypto/hmac",
		"crypto/md5",
		"crypto/rand",
		"crypto/rc4",
		"crypto/rsa",
		"crypto/rsa/testdata",
		"crypto/sha1",
		"crypto/sha256",
		"crypto/sha512",
		"crypto/subtle",
		"crypto/tls",
		"crypto/tls/testdata",
		"crypto/x509",
		"crypto/x509/pkix",
		"database",
		"database/sql",
		"database/sql/driver",
		"debug",
		"debug/dwarf",
		"debug/dwarf/testdata",
		"debug/elf",
		"debug/elf/testdata",
		"debug/gosym",
		"debug/macho",
		"debug/macho/testdata",
		"debug/pe",
		"debug/pe/testdata",
		"debug/plan9obj",
		"debug/plan9obj/testdata",
		"encoding",
		"encoding/ascii85",
		"encoding/asn1",
		"encoding/base32",
		"encoding/base64",
		"encoding/binary",
		"encoding/csv",
		"encoding/gob",
		"encoding/hex",
		"encoding/json",
		"encoding/json/testdata",
		"encoding/pem",
		"encoding/xml",
		"errors",
		"expvar",
		"flag",
		"fmt",
		"go",
		"go/ast",
		"go/build",
		"go/build/testdata",
		"go/build/testdata/empty",
		"go/build/testdata/multi",
		"go/build/testdata/other",
		"go/build/testdata/other/file",
		"go/constant",
		"go/doc",
		"go/doc/testdata",
		"go/format",
		"go/importer",
		"go/internal",
		"go/internal/gccgoimporter",
		"go/internal/gccgoimporter/testdata",
		"go/internal/gcimporter",
		"go/internal/gcimporter/testdata",
		"go/parser",
		"go/parser/testdata",
		"go/printer",
		"go/printer/testdata",
		"go/scanner",
		"go/token",
		"go/types",
		"go/types/testdata",
		"hash",
		"hash/adler32",
		"hash/crc32",
		"hash/crc64",
		"hash/fnv",
		"html",
		"html/template",
		"image",
		"image/color",
		"image/color/palette",
		"image/draw",
		"image/gif",
		"image/internal",
		"image/internal/imageutil",
		"image/jpeg",
		"image/png",
		"image/png/testdata",
		"image/png/testdata/pngsuite",
		"image/testdata",
		"index",
		"index/suffixarray",
		"internal",
		"internal/format",
		"internal/singleflight",
		"internal/syscall",
		"internal/syscall/unix",
		"internal/syscall/windows",
		"internal/syscall/windows/registry",
		"internal/testenv",
		"internal/trace",
		"io",
		"io/ioutil",
		"log",
		"log/syslog",
		"math",
		"math/big",
		"math/cmplx",
		"math/rand",
		"mime",
		"mime/multipart",
		"mime/multipart/testdata",
		"mime/quotedprintable",
		"mime/testdata",
		"net",
		"net/http",
		"net/http/cgi",
		"net/http/cgi/testdata",
		"net/http/cookiejar",
		"net/http/fcgi",
		"net/http/httptest",
		"net/http/httputil",
		"net/http/internal",
		"net/http/pprof",
		"net/http/testdata",
		"net/internal",
		"net/internal/socktest",
		"net/mail",
		"net/rpc",
		"net/rpc/jsonrpc",
		"net/smtp",
		"net/testdata",
		"net/textproto",
		"net/url",
		"os",
		"os/exec",
		"os/signal",
		"os/user",
		"path",
		"path/filepath",
		"reflect",
		"regexp",
		"regexp/syntax",
		"regexp/testdata",
		"runtime",
		"runtime/cgo",
		"runtime/debug",
		"runtime/pprof",
		"runtime/race",
		"runtime/race/testdata",
		"runtime/trace",
		"sort",
		"strconv",
		"strconv/testdata",
		"strings",
		"sync",
		"sync/atomic",
		"syscall",
		"testing",
		"testing/iotest",
		"testing/quick",
		"text",
		"text/scanner",
		"text/tabwriter",
		"text/template",
		"text/template/parse",
		"text/template/testdata",
		"time",
		"unicode",
		"unicode/utf16",
		"unicode/utf8",
		"unsafe",
	}
)

func init() {
	for _, name := range Packages() {
		pkgMap[name] = true
	}
}

// Packages returns an array of native packages
func Packages() []string {
	return pkgs
}

// IsNative returns whether given package name is a native package or not
func IsNative(name string) bool {
	_, ok := pkgMap[name]
	return ok
}
<commit_msg>Dynamically resolve native packages<commit_after>package native

import (
	"fmt"
	"os"
	"runtime"
	"path"
	"path/filepath"
	"io/ioutil"
)

var (
	pkgMap = map[string]bool{}
	pkgs = []string{}
)

func init() {
	root := runtime.GOROOT()
	if len(root) == 0 {
		fmt.Print("Go not installed or missing GOROOT environment value")
		os.Exit(1)
	}
	src := path.Join(root, "src")
	dirs := listDirsRecursive(src)
	for _, d := range dirs {
		rel, err := filepath.Rel(src, d)
		if err != nil {
			fmt.Print("Unable to resolve native packages with error:", err.Error())
			os.Exit(1)
		}
		pkgs = append(pkgs, rel)
	}
	for _, name := range pkgs {
		pkgMap[name] = true
	}
}

func listDirsRecursive(dir string) (r []string) {
	dirs, err := ioutil.ReadDir(dir)
	if err != nil {
		fmt.Printf("Unable to read dir %s with error: %s", dir, err.Error())
		return
	}
	for _, d := range dirs {
		if !d.IsDir() {
			continue
		}

		dir := path.Join(dir, d.Name())
		r = append(r, dir)
		r = append(r, listDirsRecursive(dir)...)
	}
	return
}

// Packages returns an array of native packages
func Packages() []string {
	return pkgs
}

// IsNative returns whether given package name is a native package or not
func IsNative(name string) bool {
	_, ok := pkgMap[name]
	return ok
}
<|endoftext|>


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

package netext

import (
	"net"
	"net/http/httptrace"
	"time"

	"github.com/loadimpact/k6/lib/metrics"
	"github.com/loadimpact/k6/stats"
)

// A Trail represents detailed information about an HTTP request.
// You'd typically get one from a Tracer.
type Trail struct {
	StartTime time.Time
	EndTime   time.Time

	// Total request duration, excluding DNS lookup and connect time.
	Duration time.Duration

	Blocked    time.Duration // Waiting to acquire a connection.
	LookingUp  time.Duration // Looking up DNS records.
	Connecting time.Duration // Connecting to remote host.
	Sending    time.Duration // Writing request.
	Waiting    time.Duration // Waiting for first byte.
	Receiving  time.Duration // Receiving response.

	// Detailed connection information.
	ConnReused     bool
	ConnRemoteAddr net.Addr

	// Bandwidth usage.
	BytesRead, BytesWritten int64
}

func (tr Trail) Samples(tags map[string]string) []stats.Sample {
	return []stats.Sample{
		{Metric: metrics.HTTPReqs, Time: tr.EndTime, Tags: tags, Value: 1},
		{Metric: metrics.HTTPReqDuration, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Duration)},
		{Metric: metrics.HTTPReqBlocked, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Blocked)},
		{Metric: metrics.HTTPReqLookingUp, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.LookingUp)},
		{Metric: metrics.HTTPReqConnecting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Connecting)},
		{Metric: metrics.HTTPReqSending, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Sending)},
		{Metric: metrics.HTTPReqWaiting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Waiting)},
		{Metric: metrics.HTTPReqReceiving, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Receiving)},
		{Metric: metrics.DataReceived, Time: tr.EndTime, Tags: tags, Value: float64(tr.BytesRead)},
		{Metric: metrics.DataSent, Time: tr.EndTime, Tags: tags, Value: float64(tr.BytesWritten)},
	}
}

// A Tracer wraps "net/http/httptrace" to collect granular timings for HTTP requests.
// Note that since there is not yet an event for the end of a request (there's a PR to
// add it), you must call Done() at the end of the request to get the full timings.
// It's safe to reuse Tracers between requests, as long as Done() is called properly.
// Cheers, love, the cavalry's here.
type Tracer struct {
	getConn              time.Time
	gotConn              time.Time
	gotFirstResponseByte time.Time
	dnsStart             time.Time
	dnsDone              time.Time
	connectStart         time.Time
	connectDone          time.Time
	wroteRequest         time.Time

	connReused     bool
	connRemoteAddr net.Addr

	bytesRead, bytesWritten int64
}

// Trace() returns a premade ClientTrace that calls all of the Tracer's hooks.
func (t *Tracer) Trace() *httptrace.ClientTrace {
	return &httptrace.ClientTrace{
		GetConn:              t.GetConn,
		GotConn:              t.GotConn,
		GotFirstResponseByte: t.GotFirstResponseByte,
		DNSStart:             t.DNSStart,
		DNSDone:              t.DNSDone,
		ConnectStart:         t.ConnectStart,
		ConnectDone:          t.ConnectDone,
		WroteRequest:         t.WroteRequest,
	}
}

// Call when the request is finished. Calculates metrics and resets the tracer.
func (t *Tracer) Done() Trail {
	done := time.Now()
	trail := Trail{
		StartTime:  t.getConn,
		EndTime:    done,
		Duration:   done.Sub(t.getConn),
		Blocked:    t.gotConn.Sub(t.getConn),
		LookingUp:  t.dnsDone.Sub(t.dnsStart),
		Connecting: t.connectDone.Sub(t.connectStart),
		Sending:    t.wroteRequest.Sub(t.connectDone),
		Waiting:    t.gotFirstResponseByte.Sub(t.wroteRequest),
		Receiving:  done.Sub(t.gotFirstResponseByte),

		ConnReused:     t.connReused,
		ConnRemoteAddr: t.connRemoteAddr,

		BytesRead:    t.bytesRead,
		BytesWritten: t.bytesWritten,
	}

	*t = Tracer{}
	return trail
}

// GetConn event hook.
func (t *Tracer) GetConn(hostPort string) {
	t.getConn = time.Now()
}

// GotConn event hook.
func (t *Tracer) GotConn(info httptrace.GotConnInfo) {
	t.gotConn = time.Now()
	t.connReused = info.Reused
	t.connRemoteAddr = info.Conn.RemoteAddr()

	if t.connReused {
		t.connectStart = t.gotConn
		t.connectDone = t.gotConn

		// If the connection was reused, patch it to use this tracer's data counters.
		if conn, ok := info.Conn.(*Conn); ok {
			conn.BytesRead = &t.bytesRead
			conn.BytesWritten = &t.bytesWritten
		}
	}
}

// GotFirstResponseByte hook.
func (t *Tracer) GotFirstResponseByte() {
	t.gotFirstResponseByte = time.Now()
}

// DNSStart hook.
func (t *Tracer) DNSStart(info httptrace.DNSStartInfo) {
	t.dnsStart = time.Now()
	t.dnsDone = t.dnsStart
}

// DNSDone hook.
func (t *Tracer) DNSDone(info httptrace.DNSDoneInfo) {
	t.dnsDone = time.Now()
	if t.dnsStart.IsZero() {
		t.dnsStart = t.dnsDone
	}
}

// ConnectStart hook.
func (t *Tracer) ConnectStart(network, addr string) {
	// If using dual-stack dialing, it's possible to get this multiple times.
	if !t.connectStart.IsZero() {
		return
	}
	t.connectStart = time.Now()
}

// ConnectDone hook.
func (t *Tracer) ConnectDone(network, addr string, err error) {
	// If using dual-stack dialing, it's possible to get this multiple times.
	if !t.connectDone.IsZero() {
		return
	}
	t.connectDone = time.Now()
}

// WroteRequest hook.
func (t *Tracer) WroteRequest(info httptrace.WroteRequestInfo) {
	t.wroteRequest = time.Now()
}
<commit_msg>No more negatives in trail values<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package netext

import (
	"net"
	"net/http/httptrace"
	"time"

	"github.com/loadimpact/k6/lib/metrics"
	"github.com/loadimpact/k6/stats"
)

// A Trail represents detailed information about an HTTP request.
// You'd typically get one from a Tracer.
type Trail struct {
	StartTime time.Time
	EndTime   time.Time

	// Total request duration, excluding DNS lookup and connect time.
	Duration time.Duration

	Blocked    time.Duration // Waiting to acquire a connection.
	LookingUp  time.Duration // Looking up DNS records.
	Connecting time.Duration // Connecting to remote host.
	Sending    time.Duration // Writing request.
	Waiting    time.Duration // Waiting for first byte.
	Receiving  time.Duration // Receiving response.

	// Detailed connection information.
	ConnReused     bool
	ConnRemoteAddr net.Addr

	// Bandwidth usage.
	BytesRead, BytesWritten int64
}

func (tr Trail) Samples(tags map[string]string) []stats.Sample {
	return []stats.Sample{
		{Metric: metrics.HTTPReqs, Time: tr.EndTime, Tags: tags, Value: 1},
		{Metric: metrics.HTTPReqDuration, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Duration)},
		{Metric: metrics.HTTPReqBlocked, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Blocked)},
		{Metric: metrics.HTTPReqLookingUp, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.LookingUp)},
		{Metric: metrics.HTTPReqConnecting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Connecting)},
		{Metric: metrics.HTTPReqSending, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Sending)},
		{Metric: metrics.HTTPReqWaiting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Waiting)},
		{Metric: metrics.HTTPReqReceiving, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Receiving)},
		{Metric: metrics.DataReceived, Time: tr.EndTime, Tags: tags, Value: float64(tr.BytesRead)},
		{Metric: metrics.DataSent, Time: tr.EndTime, Tags: tags, Value: float64(tr.BytesWritten)},
	}
}

// A Tracer wraps "net/http/httptrace" to collect granular timings for HTTP requests.
// Note that since there is not yet an event for the end of a request (there's a PR to
// add it), you must call Done() at the end of the request to get the full timings.
// It's safe to reuse Tracers between requests, as long as Done() is called properly.
// Cheers, love, the cavalry's here.
type Tracer struct {
	getConn              time.Time
	gotConn              time.Time
	gotFirstResponseByte time.Time
	dnsStart             time.Time
	dnsDone              time.Time
	connectStart         time.Time
	connectDone          time.Time
	wroteRequest         time.Time

	connReused     bool
	connRemoteAddr net.Addr

	protoError error

	bytesRead, bytesWritten int64
}

// Trace() returns a premade ClientTrace that calls all of the Tracer's hooks.
func (t *Tracer) Trace() *httptrace.ClientTrace {
	return &httptrace.ClientTrace{
		GetConn:              t.GetConn,
		GotConn:              t.GotConn,
		GotFirstResponseByte: t.GotFirstResponseByte,
		DNSStart:             t.DNSStart,
		DNSDone:              t.DNSDone,
		ConnectStart:         t.ConnectStart,
		ConnectDone:          t.ConnectDone,
		WroteRequest:         t.WroteRequest,
	}
}

// Call when the request is finished. Calculates metrics and resets the tracer.
func (t *Tracer) Done() Trail {
	done := time.Now()

	// Cover for if the server closed the connection without a response.
	if t.gotFirstResponseByte.IsZero() {
		t.gotFirstResponseByte = done
	}

	trail := Trail{
		StartTime:  t.getConn,
		EndTime:    done,
		Duration:   done.Sub(t.getConn),
		Blocked:    t.gotConn.Sub(t.getConn),
		LookingUp:  t.dnsDone.Sub(t.dnsStart),
		Connecting: t.connectDone.Sub(t.connectStart),
		Sending:    t.wroteRequest.Sub(t.connectDone),
		Waiting:    t.gotFirstResponseByte.Sub(t.wroteRequest),
		Receiving:  done.Sub(t.gotFirstResponseByte),

		ConnReused:     t.connReused,
		ConnRemoteAddr: t.connRemoteAddr,

		BytesRead:    t.bytesRead,
		BytesWritten: t.bytesWritten,
	}

	// If the connection failed, we'll never get any data for these.
	if t.protoError != nil {
		trail.Sending = 0
		trail.Waiting = 0
		trail.Receiving = 0
	}

	if trail.StartTime.IsZero() {
		panic("no start time")
	}
	if trail.EndTime.IsZero() {
		panic("no end time")
	}
	if trail.Duration < 0 {
		panic("impossible duration")
	}
	if trail.Blocked < 0 {
		panic("impossible block time")
	}
	if trail.LookingUp < 0 {
		panic("impossible lookup time")
	}
	if trail.Connecting < 0 {
		panic("impossible connection time")
	}
	if trail.Sending < 0 {
		panic("impossible send time")
	}
	if trail.Waiting < 0 {
		panic("impossible wait time")
	}
	if trail.Receiving < 0 {
		panic("impossible read time time")
	}
	if trail.BytesRead <= 0 && trail.Receiving > 0 {
		panic("impossible read bytes")
	}
	if trail.BytesWritten <= 0 && t.protoError == nil {
		panic("impossible written bytes")
	}

	*t = Tracer{}
	return trail
}

// GetConn event hook.
func (t *Tracer) GetConn(hostPort string) {
	t.getConn = time.Now()
}

// GotConn event hook.
func (t *Tracer) GotConn(info httptrace.GotConnInfo) {
	t.gotConn = time.Now()
	t.connReused = info.Reused
	t.connRemoteAddr = info.Conn.RemoteAddr()

	if t.connReused {
		t.connectStart = t.gotConn
		t.connectDone = t.gotConn

		// If the connection was reused, patch it to use this tracer's data counters.
		if conn, ok := info.Conn.(*Conn); ok {
			conn.BytesRead = &t.bytesRead
			conn.BytesWritten = &t.bytesWritten
		}
	}
}

// GotFirstResponseByte hook.
func (t *Tracer) GotFirstResponseByte() {
	t.gotFirstResponseByte = time.Now()
}

// DNSStart hook.
func (t *Tracer) DNSStart(info httptrace.DNSStartInfo) {
	t.dnsStart = time.Now()
	t.dnsDone = t.dnsStart
}

// DNSDone hook.
func (t *Tracer) DNSDone(info httptrace.DNSDoneInfo) {
	t.dnsDone = time.Now()
	if t.dnsStart.IsZero() {
		t.dnsStart = t.dnsDone
	}
	if info.Err != nil {
		t.protoError = info.Err
	}
}

// ConnectStart hook.
func (t *Tracer) ConnectStart(network, addr string) {
	// If using dual-stack dialing, it's possible to get this multiple times.
	if !t.connectStart.IsZero() {
		return
	}
	t.connectStart = time.Now()
}

// ConnectDone hook.
func (t *Tracer) ConnectDone(network, addr string, err error) {
	// If using dual-stack dialing, it's possible to get this multiple times.
	if !t.connectDone.IsZero() {
		return
	}

	t.connectDone = time.Now()
	if t.gotConn.IsZero() {
		t.gotConn = t.connectDone
	}

	if err != nil {
		t.protoError = err
	}
}

// WroteRequest hook.
func (t *Tracer) WroteRequest(info httptrace.WroteRequestInfo) {
	t.wroteRequest = time.Now()
	if info.Err != nil {
		t.protoError = info.Err
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"strconv"
	"strings"
)

type stack []int

func (s *stack) Push(v int) {
	*s = append(*s, v)
}

func (s *stack) Pop() int {
	res := (*s)[len(*s)-1]
	*s = (*s)[:len(*s)-1]
	return res
}

//ReadEdges reads adjency list from file and returns (adjency list, vertex index) pair
func ReadEdges(path string) (*[][]int, *[]int, *map[int]int) {
	var file, err = os.Open(path)

	if err != nil {
		fmt.Println("Failed to open file")
		os.Exit(1)
	}

	vertexIndexMap := make(map[int]int)
	indices := []int{}
	adjacencyMap := make(map[int][]int)
	vertices := []int{}

	graph := [][]int{}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		//Read and split line
		lineStr := scanner.Text()
		numbers := strings.Split(lineStr, " ")

		edge := []int{}

		for _, str := range numbers {
			number, err := strconv.Atoi(str)
			if err != nil {
				continue
			}

			edge = append(edge, number)
		}

		addVertex(edge[0], &indices, &vertexIndexMap, &adjacencyMap, &vertices)
		addVertex(edge[1], &indices, &vertexIndexMap, &adjacencyMap, &vertices)

		adjacencyMap[edge[0]] = append(adjacencyMap[edge[0]], edge[1])
		if edge[0] != edge[1] {
			adjacencyMap[edge[1]] = append(adjacencyMap[edge[1]], -edge[0])
		}
	}

	for _, v := range vertices {
		graph = append(graph, adjacencyMap[v])
	}

	return &graph, &indices, &vertexIndexMap
}

func addVertex(v int, indices *[]int, vertexIndexMap *map[int]int, adjacencyMap *map[int][]int, vertices *[]int) {
	//Init map for edge tail
	if _, ok := (*vertexIndexMap)[v]; !ok {
		//Save vertex index to the map thus mark it as initialized
		currentIndex := len(*vertices)
		(*vertexIndexMap)[v] = currentIndex
		//Save index to indices array
		*indices = append(*indices, currentIndex)
		//Init adjacency list for vertex v
		(*adjacencyMap)[v] = []int{v}
		//Save key of adjaceny list
		*vertices = append(*vertices, v)
	}
}

func main() {
	graph, indices, vertexIndexMap := ReadEdges("./data/SCC.txt")
	fmt.Println("Finished reading edges")

	//Map of explored nodes
	explored := make(map[int]bool)
	//Array of list indices sorted by finishing times of the first pass of dfsLoop
	finishingTimes := make(map[int]int)
	//Number of processed nodes
	var numProcessed int

	//First pass on inverted graph`
	dfsLoop(graph, indices, vertexIndexMap, -1, &explored, &finishingTimes, &numProcessed)

	fmt.Println("Finished inverted pass")

	//TODO: collect finishing times and rebuild vertexIndexMap

	//Second pass on the original graph in order defined by reversed finishing times
	//dfsLoop(graph, indices, vertexIndexMap, false, &explored, &finishingTimes, &numProcessed)
}

func dfsLoop(graph *[][]int, indices *[]int, vertexIndexMap *map[int]int, factor int, explored *map[int]bool, finishingTimes *map[int]int, numProcessed *int) {
	//Indices graph loop ordering
	for _, index := range *indices {
		i := (*graph)[index][0]
		//if i not yet explored
		if _, ok := (*explored)[i]; !ok {
			//TODO: assign s
			fmt.Printf("Vertex %d not explored\n", i)
			dfs(graph, vertexIndexMap, index, factor, explored, finishingTimes, numProcessed)
		}
	}
}

func dfs(graph *[][]int, vertexIndexMap *map[int]int, index int, factor int, explored *map[int]bool, finishingTimes *map[int]int, numProcessed *int) {
	//We are executing DFS for vertex defined by adjacency list graph[index]

	//Get adjacency list
	list := (*graph)[index]
	//Vertex for which we run DFS
	i := list[0]

	fmt.Printf("Started DFS on vertex %d (explored)\n", i)

	//Mark i as explored
	(*explored)[i] = true

	//for each (i, j) from G ...
	for _, j := range list {
		//We don't consider edges incompatible with current direction
		if j == i || (factor == -1 && j > 0) || (factor == 1 && j < 0) {
			continue
		}

		absJ := factor * j

		//if j not yet explored
		if _, ok := (*explored)[absJ]; !ok {
			fmt.Printf("%d DFS recurses on vertex %d\n", i, j)
			dfs(graph, vertexIndexMap, (*vertexIndexMap)[int(math.Abs(float64(j)))], factor, explored, finishingTimes, numProcessed)
		}
	}
	(*numProcessed)++
	(*finishingTimes)[i] = *numProcessed
	fmt.Printf("Finished DFS on vertex %d\n", i)
}
<commit_msg>More debug logs<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type stack []int

func (s *stack) Push(v int) {
	*s = append(*s, v)
}

func (s *stack) Pop() int {
	res := (*s)[len(*s)-1]
	*s = (*s)[:len(*s)-1]
	return res
}

//ReadEdges reads adjency list from file and returns (adjency list, vertex index) pair
func ReadEdges(path string) (*[][]int, *[]int, *map[int]int) {
	var file, err = os.Open(path)

	if err != nil {
		fmt.Println("Failed to open file")
		os.Exit(1)
	}

	vertexIndexMap := make(map[int]int)
	indices := []int{}
	adjacencyMap := make(map[int][]int)
	vertices := []int{}

	graph := [][]int{}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		//Read and split line
		lineStr := scanner.Text()
		numbers := strings.Split(lineStr, " ")

		edge := []int{}

		for _, str := range numbers {
			number, err := strconv.Atoi(str)
			if err != nil {
				continue
			}

			edge = append(edge, number)
		}

		addVertex(edge[0], &indices, &vertexIndexMap, &adjacencyMap, &vertices)
		addVertex(edge[1], &indices, &vertexIndexMap, &adjacencyMap, &vertices)

		adjacencyMap[edge[0]] = append(adjacencyMap[edge[0]], edge[1])
		if edge[0] != edge[1] {
			adjacencyMap[edge[1]] = append(adjacencyMap[edge[1]], -edge[0])
		}
	}

	for _, v := range vertices {
		graph = append(graph, adjacencyMap[v])
	}

	return &graph, &indices, &vertexIndexMap
}

func addVertex(v int, indices *[]int, vertexIndexMap *map[int]int, adjacencyMap *map[int][]int, vertices *[]int) {
	//Init map for edge tail
	if _, ok := (*vertexIndexMap)[v]; !ok {
		//Save vertex index to the map thus mark it as initialized
		currentIndex := len(*vertices)
		(*vertexIndexMap)[v] = currentIndex
		//Save index to indices array
		*indices = append(*indices, currentIndex)
		//Init adjacency list for vertex v
		(*adjacencyMap)[v] = []int{v}
		//Save key of adjaceny list
		*vertices = append(*vertices, v)
	}
}

func main() {
	graph, indices, vertexIndexMap := ReadEdges("./data/SCC.txt")
	fmt.Println("Finished reading edges")

	//Map of explored nodes
	explored := make(map[int]bool)
	//Array of list indices sorted by finishing times of the first pass of dfsLoop
	finishingTimes := make(map[int]int)
	//Number of processed nodes
	var numProcessed int

	//First pass on inverted graph`
	dfsLoop(graph, indices, vertexIndexMap, -1, &explored, &finishingTimes, &numProcessed)

	fmt.Println("Finished inverted pass")

	fmt.Printf("Finishing time of the %d vertex: %d and of the %d: %d\n", 1, finishingTimes[1], 875709, finishingTimes[875709])
	fmt.Printf("Processed in total: %d\n", numProcessed)

	//TODO: collect finishing times and rebuild vertexIndexMap

	//Second pass on the original graph in order defined by reversed finishing times
	//dfsLoop(graph, indices, vertexIndexMap, false, &explored, &finishingTimes, &numProcessed)
}

func dfsLoop(graph *[][]int, indices *[]int, vertexIndexMap *map[int]int, factor int, explored *map[int]bool, finishingTimes *map[int]int, numProcessed *int) {
	//Indices graph loop ordering
	for _, index := range *indices {
		i := (*graph)[index][0]
		//if i not yet explored
		if _, ok := (*explored)[i]; !ok {
			//TODO: assign s
			fmt.Printf("Vertex %d not explored\n", i)
			dfs(graph, vertexIndexMap, index, factor, explored, finishingTimes, numProcessed)
		}
	}
}

func dfs(graph *[][]int, vertexIndexMap *map[int]int, index int, factor int, explored *map[int]bool, finishingTimes *map[int]int, numProcessed *int) {
	//We are executing DFS for vertex defined by adjacency list graph[index]

	//Get adjacency list
	list := (*graph)[index]
	//Vertex for which we run DFS
	i := list[0]

	fmt.Printf("Started DFS on vertex %d\n", i)

	//Mark i as explored
	(*explored)[i] = true

	//for each (i, j) from G ...
	for _, j := range list {
		//We don't consider edges incompatible with current direction
		if j == i || (factor == -1 && j > 0) || (factor == 1 && j < 0) {
			continue
		}

		absJ := factor * j

		//if j not yet explored
		if _, ok := (*explored)[absJ]; !ok {
			fmt.Printf("%d DFS recurses on vertex %d\n", i, j)
			dfs(graph, vertexIndexMap, (*vertexIndexMap)[absJ], factor, explored, finishingTimes, numProcessed)
		}
	}
	(*numProcessed)++
	(*finishingTimes)[i] = *numProcessed
	fmt.Printf("Finished DFS on vertex %d\n", i)
}
<|endoftext|>


<commit_before>package randomtext

import (
	"fmt"
	"strings"
	"math/rand"
)

// WordGenerator returns random words
func WordGenerator() func() string {
	data, err := Asset("assets/words.list")
	fmt.Println("err", err)
	if err != nil {
		panic(err)
	}
	wordsStr := string(data)
	wordsList := strings.Split(wordsStr, "\n")
	totalNumberOfWords := len(wordsList)
	return func() string {
		return wordsList[rand.Intn(totalNumberOfWords)]
	}
}<commit_msg>Newline addition to words<commit_after>package randomtext

import (
	"fmt"
	"strings"
	"math/rand"
)

// WordGenerator returns random words
func WordGenerator() func() string {
	data, err := Asset("assets/words.list")
	fmt.Println("err", err)
	if err != nil {
		panic(err)
	}
	wordsStr := string(data)
	wordsList := strings.Split(wordsStr, "\n")
	totalNumberOfWords := len(wordsList)
	return func() string {
		return wordsList[rand.Intn(totalNumberOfWords)] + "\n"
	}
}<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains low level functions for interacting with the Discord
// data websocket interface.

package discordgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/gorilla/websocket"
)

var GATEWAY_VERSION int = 4

type handshakeProperties struct {
	OS              string `json:"$os"`
	Browser         string `json:"$browser"`
	Device          string `json:"$device"`
	Referer         string `json:"$referer"`
	ReferringDomain string `json:"$referring_domain"`
}

type handshakeData struct {
	Token          string              `json:"token"`
	Properties     handshakeProperties `json:"properties"`
	LargeThreshold int                 `json:"large_threshold"`
	Compress       bool                `json:"compress"`
}

type handshakeOp struct {
	Op   int           `json:"op"`
	Data handshakeData `json:"d"`
}

// Open opens a websocket connection to Discord.
func (s *Session) Open() (err error) {
	s.Lock()
	defer func() {
		if err != nil {
			s.Unlock()
		}
	}()

	s.VoiceConnections = make(map[string]*VoiceConnection)

	if s.wsConn != nil {
		err = errors.New("Web socket already opened.")
		return
	}

	// Get the gateway to use for the Websocket connection
	g, err := s.Gateway()
	if err != nil {
		return
	}

	// Add the version and encoding to the URL
	g = g + fmt.Sprintf("?v=%v&encoding=json", GATEWAY_VERSION)

	header := http.Header{}
	header.Add("accept-encoding", "zlib")

	// TODO: See if there's a use for the http response.
	// conn, response, err := websocket.DefaultDialer.Dial(session.Gateway, nil)
	s.wsConn, _, err = websocket.DefaultDialer.Dial(g, header)
	if err != nil {
		return
	}

	err = s.wsConn.WriteJSON(handshakeOp{2, handshakeData{s.Token, handshakeProperties{runtime.GOOS, "Discordgo v" + VERSION, "", "", ""}, 250, s.Compress}})
	if err != nil {
		return
	}

	// Create listening outside of listen, as it needs to happen inside the mutex
	// lock.
	s.listening = make(chan interface{})
	go s.listen(s.wsConn, s.listening)

	s.Unlock()

	s.initialize()
	s.handle(&Connect{})

	return
}

// Close closes a websocket and stops all listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP connections
func (s *Session) Close() (err error) {
	s.Lock()

	s.DataReady = false

	if s.listening != nil {
		close(s.listening)
		s.listening = nil
	}

	if s.wsConn != nil {
		err = s.wsConn.Close()
		s.wsConn = nil
	}

	s.Unlock()

	s.handle(&Disconnect{})

	return
}

// listen polls the websocket connection for events, it will stop when
// the listening channel is closed, or an error occurs.
func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
	for {
		messageType, message, err := wsConn.ReadMessage()
		if err != nil {
			// Detect if we have been closed manually. If a Close() has already
			// happened, the websocket we are listening on will be different to the
			// current session.
			s.RLock()
			sameConnection := s.wsConn == wsConn
			s.RUnlock()
			if sameConnection {
				// There has been an error reading, Close() the websocket so that
				// OnDisconnect is fired.
				err := s.Close()
				if err != nil {
					log.Println("error closing session connection: ", err)
				}

				// Attempt to reconnect, with expenonential backoff up to 10 minutes.
				if s.ShouldReconnectOnError {
					wait := time.Duration(1)
					for {
						if s.Open() == nil {
							return
						}
						<-time.After(wait * time.Second)
						wait *= 2
						if wait > 600 {
							wait = 600
						}
					}
				}
			}
			return
		}

		select {
		case <-listening:
			return
		default:
			go s.event(messageType, message)
		}
	}
}

type heartbeatOp struct {
	Op   int `json:"op"`
	Data int `json:"d"`
}

// heartbeat sends regular heartbeats to Discord so it knows the client
// is still connected.  If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds.
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {

	if listening == nil || wsConn == nil {
		return
	}

	s.Lock()
	s.DataReady = true
	s.Unlock()

	var err error
	ticker := time.NewTicker(i * time.Millisecond)
	for {
		err = wsConn.WriteJSON(heartbeatOp{1, int(time.Now().Unix())})
		if err != nil {
			log.Println("Error sending heartbeat:", err)
			return
		}

		select {
		case <-ticker.C:
			// continue loop and send heartbeat
		case <-listening:
			return
		}
	}
}

type updateStatusGame struct {
	Name string `json:"name"`
}

type updateStatusData struct {
	IdleSince *int              `json:"idle_since"`
	Game      *updateStatusGame `json:"game"`
}

type updateStatusOp struct {
	Op   int              `json:"op"`
	Data updateStatusData `json:"d"`
}

// UpdateStatus is used to update the authenticated user's status.
// If idle>0 then set status to idle.  If game>0 then set game.
// if otherwise, set status to active, and no game.
func (s *Session) UpdateStatus(idle int, game string) (err error) {
	s.RLock()
	defer s.RUnlock()
	if s.wsConn == nil {
		return errors.New("No websocket connection exists.")
	}

	var usd updateStatusData
	if idle > 0 {
		usd.IdleSince = &idle
	}
	if game != "" {
		usd.Game = &updateStatusGame{game}
	}

	err = s.wsConn.WriteJSON(updateStatusOp{3, usd})

	return
}

// Front line handler for all Websocket Events.  Determines the
// event type and passes the message along to the next handler.

// event is the front line handler for all events.  This needs to be
// broken up into smaller functions to be more idiomatic Go.
// Events will be handled by any implemented handler in Session.
// All unhandled events will then be handled by OnEvent.
func (s *Session) event(messageType int, message []byte) {
	var err error
	var reader io.Reader

	reader = bytes.NewBuffer(message)

	if messageType == 2 {
		z, err1 := zlib.NewReader(reader)
		if err1 != nil {
			log.Println(fmt.Sprintf("Error uncompressing message type %d: %s", messageType, err1))
			return
		}
		defer func() {
			err := z.Close()
			if err != nil {
				log.Println("error closing zlib:", err)
			}
		}()
		reader = z
	}

	var e *Event
	decoder := json.NewDecoder(reader)
	if err = decoder.Decode(&e); err != nil {
		log.Println(fmt.Sprintf("Error decoding message type %d: %s", messageType, err))
		return
	}

	if s.Debug {
		printEvent(e)
	}

	i := eventToInterface[e.Type]
	if i != nil {
		// Create a new instance of the event type.
		i = reflect.New(reflect.TypeOf(i)).Interface()

		// Attempt to unmarshal our event.
		// If there is an error we should handle the event itself.
		if err = json.Unmarshal(e.RawData, i); err != nil {
			log.Printf("error unmarshalling %s event, %s\n", e.Type, err)
			// Ready events must fire, even if they are empty.
			if e.Type != "READY" {
				i = nil
			}

		}
	} else {
		log.Println("Unknown event.")
		i = nil
	}

	if i != nil {
		s.handle(i)
	}

	e.Struct = i
	s.handle(e)

	return
}

// ------------------------------------------------------------------------------------------------
// Code related to voice connections that initiate over the data websocket
// ------------------------------------------------------------------------------------------------

// A VoiceServerUpdate stores the data received during the Voice Server Update
// data websocket event. This data is used during the initial Voice Channel
// join handshaking.
type VoiceServerUpdate struct {
	Token    string `json:"token"`
	GuildID  string `json:"guild_id"`
	Endpoint string `json:"endpoint"`
}

type voiceChannelJoinData struct {
	GuildID   *string `json:"guild_id"`
	ChannelID *string `json:"channel_id"`
	SelfMute  bool    `json:"self_mute"`
	SelfDeaf  bool    `json:"self_deaf"`
}

type voiceChannelJoinOp struct {
	Op   int                  `json:"op"`
	Data voiceChannelJoinData `json:"d"`
}

// ChannelVoiceJoin joins the session user to a voice channel.
//
//    gID     : Guild ID of the channel to join.
//    cID     : Channel ID of the channel to join.
//    mute    : If true, you will be set to muted upon joining.
//    deaf    : If true, you will be set to deafened upon joining.
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *VoiceConnection, err error) {

	// If a voice connection already exists for this guild then
	// return that connection. If the channel differs, also change channels.
	var ok bool
	if voice, ok = s.VoiceConnections[gID]; ok && voice.GuildID != "" {
		//TODO: consider a better variable than GuildID in the above check
		// to verify if this connection is valid or not.

		if voice.ChannelID != cID {
			err = voice.ChangeChannel(cID, mute, deaf)
		}
		return
	}

	// Create a new voice session
	// TODO review what all these things are for....
	voice = &VoiceConnection{
		GuildID:     gID,
		ChannelID:   cID,
		deaf:        deaf,
		mute:        mute,
		session:     s,
		connected:   make(chan bool),
		sessionRecv: make(chan string),
	}

	// Store voice in VoiceConnections map for this GuildID
	s.VoiceConnections[gID] = voice

	// Send the request to Discord that we want to join the voice channel
	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
	err = s.wsConn.WriteJSON(data)
	if err != nil {
		delete(s.VoiceConnections, gID)
		return
	}

	// doesn't exactly work perfect yet.. TODO
	err = voice.waitUntilConnected()
	if err != nil {
		voice.Close()
		delete(s.VoiceConnections, gID)
		return
	}

	return
}

// onVoiceStateUpdate handles Voice State Update events on the data websocket.
func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) {

	// If we don't have a connection for the channel, don't bother
	if st.ChannelID == "" {
		return
	}

	// Check if we have a voice connection to update
	voice, exists := s.VoiceConnections[st.GuildID]
	if !exists {
		return
	}

	// Need to have this happen at login and store it in the Session
	// TODO : This should be done upon connecting to Discord, or
	// be moved to a small helper function
	self, err := s.User("@me") // TODO: move to Login/New
	if err != nil {
		log.Println(err)
		return
	}

	// We only care about events that are about us
	if st.UserID != self.ID {
		return
	}

	// Store the SessionID for later use.
	voice.UserID = self.ID // TODO: Review
	voice.sessionID = st.SessionID

	// TODO: Consider this...
	// voice.sessionRecv <- st.SessionID
}

// onVoiceServerUpdate handles the Voice Server Update data websocket event.
//
// This is also fired if the Guild's voice region changes while connected
// to a voice channel.  In that case, need to re-establish connection to
// the new region endpoint.
func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) {

	voice, exists := s.VoiceConnections[st.GuildID]

	// If no VoiceConnection exists, just skip this
	if !exists {
		return
	}

	// Store values for later use
	voice.token = st.Token
	voice.endpoint = st.Endpoint
	voice.GuildID = st.GuildID

	// If currently connected to voice ws/udp, then disconnect.
	// Has no effect if not connected.
	// voice.Close()

	// Wait for the sessionID from onVoiceStateUpdate
	// voice.sessionID = <-voice.sessionRecv
	// TODO review above
	// wouldn't this cause a huge problem, if it's just a guild server
	// update.. ?
	// I could add a timeout loop of some sort and also check if the
	// sessionID doesn't or does exist already...
	// something.. a bit smarter.

	// We now have enough information to open a voice websocket conenction
	// so, that's what the next call does.
	err := voice.open()
	if err != nil {
		log.Println("onVoiceServerUpdate Voice.Open error: ", err)
		// TODO better logging
	}
}
<commit_msg>Fix incorrect handling of VOICE_SERVER_UPDATE<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains low level functions for interacting with the Discord
// data websocket interface.

package discordgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/gorilla/websocket"
)

var GATEWAY_VERSION int = 4

type handshakeProperties struct {
	OS              string `json:"$os"`
	Browser         string `json:"$browser"`
	Device          string `json:"$device"`
	Referer         string `json:"$referer"`
	ReferringDomain string `json:"$referring_domain"`
}

type handshakeData struct {
	Token          string              `json:"token"`
	Properties     handshakeProperties `json:"properties"`
	LargeThreshold int                 `json:"large_threshold"`
	Compress       bool                `json:"compress"`
}

type handshakeOp struct {
	Op   int           `json:"op"`
	Data handshakeData `json:"d"`
}

// Open opens a websocket connection to Discord.
func (s *Session) Open() (err error) {
	s.Lock()
	defer func() {
		if err != nil {
			s.Unlock()
		}
	}()

	s.VoiceConnections = make(map[string]*VoiceConnection)

	if s.wsConn != nil {
		err = errors.New("Web socket already opened.")
		return
	}

	// Get the gateway to use for the Websocket connection
	g, err := s.Gateway()
	if err != nil {
		return
	}

	// Add the version and encoding to the URL
	g = g + fmt.Sprintf("?v=%v&encoding=json", GATEWAY_VERSION)

	header := http.Header{}
	header.Add("accept-encoding", "zlib")

	// TODO: See if there's a use for the http response.
	// conn, response, err := websocket.DefaultDialer.Dial(session.Gateway, nil)
	s.wsConn, _, err = websocket.DefaultDialer.Dial(g, header)
	if err != nil {
		return
	}

	err = s.wsConn.WriteJSON(handshakeOp{2, handshakeData{s.Token, handshakeProperties{runtime.GOOS, "Discordgo v" + VERSION, "", "", ""}, 250, s.Compress}})
	if err != nil {
		return
	}

	// Create listening outside of listen, as it needs to happen inside the mutex
	// lock.
	s.listening = make(chan interface{})
	go s.listen(s.wsConn, s.listening)

	s.Unlock()

	s.initialize()
	s.handle(&Connect{})

	return
}

// Close closes a websocket and stops all listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP connections
func (s *Session) Close() (err error) {
	s.Lock()

	s.DataReady = false

	if s.listening != nil {
		close(s.listening)
		s.listening = nil
	}

	if s.wsConn != nil {
		err = s.wsConn.Close()
		s.wsConn = nil
	}

	s.Unlock()

	s.handle(&Disconnect{})

	return
}

// listen polls the websocket connection for events, it will stop when
// the listening channel is closed, or an error occurs.
func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
	for {
		messageType, message, err := wsConn.ReadMessage()
		if err != nil {
			// Detect if we have been closed manually. If a Close() has already
			// happened, the websocket we are listening on will be different to the
			// current session.
			s.RLock()
			sameConnection := s.wsConn == wsConn
			s.RUnlock()
			if sameConnection {
				// There has been an error reading, Close() the websocket so that
				// OnDisconnect is fired.
				err := s.Close()
				if err != nil {
					log.Println("error closing session connection: ", err)
				}

				// Attempt to reconnect, with expenonential backoff up to 10 minutes.
				if s.ShouldReconnectOnError {
					wait := time.Duration(1)
					for {
						if s.Open() == nil {
							return
						}
						<-time.After(wait * time.Second)
						wait *= 2
						if wait > 600 {
							wait = 600
						}
					}
				}
			}
			return
		}

		select {
		case <-listening:
			return
		default:
			go s.event(messageType, message)
		}
	}
}

type heartbeatOp struct {
	Op   int `json:"op"`
	Data int `json:"d"`
}

// heartbeat sends regular heartbeats to Discord so it knows the client
// is still connected.  If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds.
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {

	if listening == nil || wsConn == nil {
		return
	}

	s.Lock()
	s.DataReady = true
	s.Unlock()

	var err error
	ticker := time.NewTicker(i * time.Millisecond)
	for {
		err = wsConn.WriteJSON(heartbeatOp{1, int(time.Now().Unix())})
		if err != nil {
			log.Println("Error sending heartbeat:", err)
			return
		}

		select {
		case <-ticker.C:
			// continue loop and send heartbeat
		case <-listening:
			return
		}
	}
}

type updateStatusGame struct {
	Name string `json:"name"`
}

type updateStatusData struct {
	IdleSince *int              `json:"idle_since"`
	Game      *updateStatusGame `json:"game"`
}

type updateStatusOp struct {
	Op   int              `json:"op"`
	Data updateStatusData `json:"d"`
}

// UpdateStatus is used to update the authenticated user's status.
// If idle>0 then set status to idle.  If game>0 then set game.
// if otherwise, set status to active, and no game.
func (s *Session) UpdateStatus(idle int, game string) (err error) {
	s.RLock()
	defer s.RUnlock()
	if s.wsConn == nil {
		return errors.New("No websocket connection exists.")
	}

	var usd updateStatusData
	if idle > 0 {
		usd.IdleSince = &idle
	}
	if game != "" {
		usd.Game = &updateStatusGame{game}
	}

	err = s.wsConn.WriteJSON(updateStatusOp{3, usd})

	return
}

// Front line handler for all Websocket Events.  Determines the
// event type and passes the message along to the next handler.

// event is the front line handler for all events.  This needs to be
// broken up into smaller functions to be more idiomatic Go.
// Events will be handled by any implemented handler in Session.
// All unhandled events will then be handled by OnEvent.
func (s *Session) event(messageType int, message []byte) {
	var err error
	var reader io.Reader

	reader = bytes.NewBuffer(message)

	if messageType == 2 {
		z, err1 := zlib.NewReader(reader)
		if err1 != nil {
			log.Println(fmt.Sprintf("Error uncompressing message type %d: %s", messageType, err1))
			return
		}
		defer func() {
			err := z.Close()
			if err != nil {
				log.Println("error closing zlib:", err)
			}
		}()
		reader = z
	}

	var e *Event
	decoder := json.NewDecoder(reader)
	if err = decoder.Decode(&e); err != nil {
		log.Println(fmt.Sprintf("Error decoding message type %d: %s", messageType, err))
		return
	}

	if s.Debug {
		printEvent(e)
	}

	i := eventToInterface[e.Type]
	if i != nil {
		// Create a new instance of the event type.
		i = reflect.New(reflect.TypeOf(i)).Interface()

		// Attempt to unmarshal our event.
		// If there is an error we should handle the event itself.
		if err = json.Unmarshal(e.RawData, i); err != nil {
			log.Printf("error unmarshalling %s event, %s\n", e.Type, err)
			// Ready events must fire, even if they are empty.
			if e.Type != "READY" {
				i = nil
			}

		}
	} else {
		log.Println("Unknown event.")
		i = nil
	}

	if i != nil {
		s.handle(i)
	}

	e.Struct = i
	s.handle(e)

	return
}

// ------------------------------------------------------------------------------------------------
// Code related to voice connections that initiate over the data websocket
// ------------------------------------------------------------------------------------------------

// A VoiceServerUpdate stores the data received during the Voice Server Update
// data websocket event. This data is used during the initial Voice Channel
// join handshaking.
type VoiceServerUpdate struct {
	Token    string `json:"token"`
	GuildID  string `json:"guild_id"`
	Endpoint string `json:"endpoint"`
}

type voiceChannelJoinData struct {
	GuildID   *string `json:"guild_id"`
	ChannelID *string `json:"channel_id"`
	SelfMute  bool    `json:"self_mute"`
	SelfDeaf  bool    `json:"self_deaf"`
}

type voiceChannelJoinOp struct {
	Op   int                  `json:"op"`
	Data voiceChannelJoinData `json:"d"`
}

// ChannelVoiceJoin joins the session user to a voice channel.
//
//    gID     : Guild ID of the channel to join.
//    cID     : Channel ID of the channel to join.
//    mute    : If true, you will be set to muted upon joining.
//    deaf    : If true, you will be set to deafened upon joining.
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *VoiceConnection, err error) {

	// If a voice connection already exists for this guild then
	// return that connection. If the channel differs, also change channels.
	var ok bool
	if voice, ok = s.VoiceConnections[gID]; ok && voice.GuildID != "" {
		//TODO: consider a better variable than GuildID in the above check
		// to verify if this connection is valid or not.

		if voice.ChannelID != cID {
			err = voice.ChangeChannel(cID, mute, deaf)
		}
		return
	}

	// Create a new voice session
	// TODO review what all these things are for....
	voice = &VoiceConnection{
		GuildID:   gID,
		ChannelID: cID,
		deaf:      deaf,
		mute:      mute,
		session:   s,
	}

	// Store voice in VoiceConnections map for this GuildID
	s.VoiceConnections[gID] = voice

	// Send the request to Discord that we want to join the voice channel
	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
	err = s.wsConn.WriteJSON(data)
	if err != nil {
		delete(s.VoiceConnections, gID)
		return
	}

	// doesn't exactly work perfect yet.. TODO
	err = voice.waitUntilConnected()
	if err != nil {
		voice.Close()
		delete(s.VoiceConnections, gID)
		return
	}

	return
}

// onVoiceStateUpdate handles Voice State Update events on the data websocket.
func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) {

	// If we don't have a connection for the channel, don't bother
	if st.ChannelID == "" {
		return
	}

	// Check if we have a voice connection to update
	voice, exists := s.VoiceConnections[st.GuildID]
	if !exists {
		return
	}

	// Need to have this happen at login and store it in the Session
	// TODO : This should be done upon connecting to Discord, or
	// be moved to a small helper function
	self, err := s.User("@me") // TODO: move to Login/New
	if err != nil {
		log.Println(err)
		return
	}

	// We only care about events that are about us
	if st.UserID != self.ID {
		return
	}

	// Store the SessionID for later use.
	voice.UserID = self.ID // TODO: Review
	voice.sessionID = st.SessionID
}

// onVoiceServerUpdate handles the Voice Server Update data websocket event.
//
// This is also fired if the Guild's voice region changes while connected
// to a voice channel.  In that case, need to re-establish connection to
// the new region endpoint.
func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) {

	voice, exists := s.VoiceConnections[st.GuildID]

	// If no VoiceConnection exists, just skip this
	if !exists {
		return
	}

	// If currently connected to voice ws/udp, then disconnect.
	// Has no effect if not connected.
	voice.Close()

	// Store values for later use
	voice.token = st.Token
	voice.endpoint = st.Endpoint
	voice.GuildID = st.GuildID

	// Open a conenction to the voice server
	err := voice.open()
	if err != nil {
		s.log(LogError, "onVoiceServerUpdate voice.open, ", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"net"
	"os"
)

func main() {
	service := ":8080"
	tcpAddr := net.ResolveTCPAddr("tcp4", service)
	log.Info("Listening on TCP Addess:" + tcpAddr.IP + ":" + tcpAddr.Port)
	listener := net.ListenTCP("tcp4", tcpAddr)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			continue
		}
		handleRequests(conn)
	}
}

func handleRequests(conn net.Conn) {
	var buffer [512]byte

	streamlength, err := conn.Read(buffer[0:])
	if err != nil {
		return
	}
	log.info("Reading Request Input:" + string(buffer[0:]))

	_, err2 := conn.Write(buffer[0:streamlength])
	if err2 != nil {
		return
	}
}
<commit_msg>Adding go routine call for request handler<commit_after>package main

import (
	log "github.com/Sirupsen/logrus"
	"net"
	"os"
)

func main() {
	service := ":8080"
	tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
	checkError(err)

	log.Info("Listening on TCP Port:", tcpAddr.Port)
	listener, err := net.ListenTCP("tcp4", tcpAddr)
	checkError(err)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			continue
		}
		go handleRequests(conn)
	}
}

func handleRequests(conn net.Conn) {
	defer conn.Close()
	var buffer [512]byte

	streamlength, err := conn.Read(buffer[0:])
	if err != nil {
		return
	}
	log.Info("Reading Request Input:" + string(buffer[0:]))

	_, err2 := conn.Write(buffer[0:streamlength])
	if err2 != nil {
		return
	}
}

func checkError(err error) {
	if err != nil {
		log.Error("Fatal error: " + err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package cloudca

import (
	"github.com/cloud-ca/go-cloudca/services"
	"github.com/cloud-ca/go-cloudca/api"
	"encoding/json"
)

type Service struct {
	Name string `json:"name,omitempty"`
	Capabilities map[string]interface{} `json:"capabilities,omitempty"`
}

type Tier struct {
	Id string `json:"id,omitempty"`
	Name string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	VpcId string `json:"vpcId,omitempty"`
	NetworkOfferingId string `json:"networkOfferingId,omitempty"`
	NetworkAclId string `json:"networkACLId,omitempty"`
	ZoneId string `json:"zoneid,omitempty"`
	ZoneName string `json:"zonename,omitempty"`
	Cidr string `json:"cidr,omitempty"`
	Type string `json:"type,omitempty"`
	State string `json:"state,omitempty"`
	Gateway string `json:"gateway,omitempty"`
	IsSystem bool `json:"issystem,omitempty"`
	Domain string `json:"domain,omitempty"`
	DomainId string `json:"domainid,omitempty"`
	Project string `json:"project,omitempty"`
	ProjectId string `json:"projectid,omitempty"`
	Services []Service `json:"service,omitempty"`
}

type TierService interface {
	Get(id string) (*Tier, error)
	List() ([]Tier, error)
	ListOfVpc(vpcId string) ([]Tier, error)
	ListWithOptions(options map[string]string) ([]Tier, error)
	Create(tier Tier) (*Tier, error)
	Update(id string, tier Tier) (*Tier, error)
	Delete(id string) (bool, error)
	ChangeAcl(id string, aclId string) (bool, error)
}

type TierApi struct {
	entityService services.EntityService
}

func NewTierService(apiClient api.ApiClient, serviceCode string, environmentName string) TierService {
	return &TierApi{
		entityService: services.NewEntityService(apiClient, serviceCode, environmentName, TIER_ENTITY_TYPE),
	}
}

func parseTier(data []byte) *Tier {
	tier := Tier{}
	json.Unmarshal(data, &tier)
	return &tier
}

func parseTierList(data []byte) []Tier {
	tiers := []Tier{}
	json.Unmarshal(data, &tiers)
	return tiers
}

//Get tier with the specified id for the current environment
func (tierApi *TierApi) Get(id string) (*Tier, error) {
	data, err := tierApi.entityService.Get(id, map[string]string{})
	if err != nil {
		return nil, err
	}
	return parseTier(data), nil
}

//List all tiers for the current environment
func (tierApi *TierApi) List() ([]Tier, error) {
	return tierApi.ListWithOptions(map[string]string{})
}

//List all tiers of a vpc for the current environment
func (tierApi *TierApi) ListOfVpc(vpcId string) ([]Tier, error) {
	return tierApi.ListWithOptions(map[string]string{
			vpcId: vpcId,
		})
}

//List all tiers for the current environment. Can use options to do sorting and paging.
func (tierApi *TierApi) ListWithOptions(options map[string]string) ([]Tier, error) {
	data, err := tierApi.entityService.List(options)
	if err != nil {
		return nil, err
	}
	return parseTierList(data), nil
}

func (tierApi *TierApi) Create(tier Tier) (*Tier, error) {
	send, merr := json.Marshal(tier)
	if merr != nil {
		return nil, merr
	}
	body, err := tierApi.entityService.Create(send, map[string]string{})
	if err != nil {
		return nil, err
	}
	return parseTier(body), nil
}

func (tierApi *TierApi) Update(id string, tier Tier) (*Tier, error) {
	send, merr := json.Marshal(tier)
	if merr != nil {
		return nil, merr
	}
	body, err := tierApi.entityService.Update(id, send, map[string]string{})
	if err != nil {
		return nil, err
	}
	return parseTier(body), nil
}

func (tierApi *TierApi) Delete(id string) (bool, error) {
	_, err := tierApi.entityService.Delete(id, []byte{}, map[string]string{})
	return err == nil, err
}

func (tierApi *TierApi) ChangeAcl(id string, aclId string) (bool, error){
	send, merr := json.Marshal(Tier{
			NetworkAclId: aclId,
	});
	if merr != nil {
		return false, merr
	}
	_, err := tierApi.entityService.Execute(id, "replace", send, map[string]string{})
	return err == nil, err
}
<commit_msg>Changed casing of tier field<commit_after>package cloudca

import (
	"github.com/cloud-ca/go-cloudca/services"
	"github.com/cloud-ca/go-cloudca/api"
	"encoding/json"
)

type Service struct {
	Name string `json:"name,omitempty"`
	Capabilities map[string]interface{} `json:"capabilities,omitempty"`
}

type Tier struct {
	Id string `json:"id,omitempty"`
	Name string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	VpcId string `json:"vpcId,omitempty"`
	NetworkOfferingId string `json:"networkOfferingId,omitempty"`
	NetworkAclId string `json:"networkAclId,omitempty"`
	ZoneId string `json:"zoneid,omitempty"`
	ZoneName string `json:"zonename,omitempty"`
	Cidr string `json:"cidr,omitempty"`
	Type string `json:"type,omitempty"`
	State string `json:"state,omitempty"`
	Gateway string `json:"gateway,omitempty"`
	IsSystem bool `json:"issystem,omitempty"`
	Domain string `json:"domain,omitempty"`
	DomainId string `json:"domainid,omitempty"`
	Project string `json:"project,omitempty"`
	ProjectId string `json:"projectid,omitempty"`
	Services []Service `json:"service,omitempty"`
}

type TierService interface {
	Get(id string) (*Tier, error)
	List() ([]Tier, error)
	ListOfVpc(vpcId string) ([]Tier, error)
	ListWithOptions(options map[string]string) ([]Tier, error)
	Create(tier Tier) (*Tier, error)
	Update(id string, tier Tier) (*Tier, error)
	Delete(id string) (bool, error)
	ChangeAcl(id string, aclId string) (bool, error)
}

type TierApi struct {
	entityService services.EntityService
}

func NewTierService(apiClient api.ApiClient, serviceCode string, environmentName string) TierService {
	return &TierApi{
		entityService: services.NewEntityService(apiClient, serviceCode, environmentName, TIER_ENTITY_TYPE),
	}
}

func parseTier(data []byte) *Tier {
	tier := Tier{}
	json.Unmarshal(data, &tier)
	return &tier
}

func parseTierList(data []byte) []Tier {
	tiers := []Tier{}
	json.Unmarshal(data, &tiers)
	return tiers
}

//Get tier with the specified id for the current environment
func (tierApi *TierApi) Get(id string) (*Tier, error) {
	data, err := tierApi.entityService.Get(id, map[string]string{})
	if err != nil {
		return nil, err
	}
	return parseTier(data), nil
}

//List all tiers for the current environment
func (tierApi *TierApi) List() ([]Tier, error) {
	return tierApi.ListWithOptions(map[string]string{})
}

//List all tiers of a vpc for the current environment
func (tierApi *TierApi) ListOfVpc(vpcId string) ([]Tier, error) {
	return tierApi.ListWithOptions(map[string]string{
			vpcId: vpcId,
		})
}

//List all tiers for the current environment. Can use options to do sorting and paging.
func (tierApi *TierApi) ListWithOptions(options map[string]string) ([]Tier, error) {
	data, err := tierApi.entityService.List(options)
	if err != nil {
		return nil, err
	}
	return parseTierList(data), nil
}

func (tierApi *TierApi) Create(tier Tier) (*Tier, error) {
	send, merr := json.Marshal(tier)
	if merr != nil {
		return nil, merr
	}
	body, err := tierApi.entityService.Create(send, map[string]string{})
	if err != nil {
		return nil, err
	}
	return parseTier(body), nil
}

func (tierApi *TierApi) Update(id string, tier Tier) (*Tier, error) {
	send, merr := json.Marshal(tier)
	if merr != nil {
		return nil, merr
	}
	body, err := tierApi.entityService.Update(id, send, map[string]string{})
	if err != nil {
		return nil, err
	}
	return parseTier(body), nil
}

func (tierApi *TierApi) Delete(id string) (bool, error) {
	_, err := tierApi.entityService.Delete(id, []byte{}, map[string]string{})
	return err == nil, err
}

func (tierApi *TierApi) ChangeAcl(id string, aclId string) (bool, error){
	send, merr := json.Marshal(Tier{
			NetworkAclId: aclId,
	});
	if merr != nil {
		return false, merr
	}
	_, err := tierApi.entityService.Execute(id, "replace", send, map[string]string{})
	return err == nil, err
}
<|endoftext|>