<commit_before>package glacier

import (
	"bytes"
	"encoding/json"
	"github.com/rdwilliamson/aws"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)

type jobRequest struct {
	Type        string
	ArchiveId   string `json:",omitempty"` // archive retrieval only
	Description string
	Format      string `json:",omitempty"` // inventory retrieval only
	SNSTopic    string
}

type Archive struct {
	ArchiveId          string
	ArchiveDescription string
	CreationDate       time.Time
	Size               uint64
	SHA256TreeHash     string
}

type Inventory struct {
	VaultARN      string
	InventoryDate time.Time
	ArchiveList   []Archive
}

// TODO write unmarshaler instead of using these structs
type archive struct {
	ArchiveId          string
	ArchiveDescription string
	CreationDate       string
	Size               uint64
	SHA256TreeHash     string
}
type inventory struct {
	VaultARN      string
	InventoryDate string
	ArchiveList   []archive
}

type Job struct {
	Action               string
	ArchiveId            string
	ArchiveSizeInBytes   uint64
	Completed            bool
	CompletionDate       time.Time
	CreationDate         time.Time
	InventorySizeInBytes uint
	JobDescription       string
	JobId                string
	SHA256TreeHash       string
	SNSTopic             string
	StatusCode           string
	StatusMessage        string
	VaultARN             string
}

// TODO write unmarshaler instead of using these structs
type job struct {
	Action               string
	ArchiveId            *string
	ArchiveSizeInBytes   *uint64
	Completed            bool
	CompletionDate       string
	CreationDate         string
	InventorySizeInBytes *uint
	JobDescription       string
	JobId                string
	SHA256TreeHash       *string
	SNSTopic             string
	StatusCode           string
	StatusMessage        string
	VaultARN             string
}
type jobList struct {
	Marker  *string
	JobList []job
}

func (c *Connection) InitiateRetrievalJob(vault, archive, topic,
	description string) (string, error) {
	j := jobRequest{Type: "archive-retrieval", ArchiveId: archive,
		Description: description, SNSTopic: topic}
	rawBody, _ := json.Marshal(j)
	body := bytes.NewReader(rawBody)

	request, err := http.NewRequest("POST",
		"https://"+c.Signature.Region.Glacier+"/-/vaults/"+vault+"/jobs", body)
	if err != nil {
		return "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	err = c.Signature.Sign(request, body, nil)
	if err != nil {
		return "", err
	}

	response, err := c.Client.Do(request)
	if err != nil {
		return "", err
	}

	if response.StatusCode != 202 {
		body, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return "", err
		}
		err = response.Body.Close()
		if err != nil {
			return "", err
		}
		var e aws.Error
		err = json.Unmarshal(body, &e)
		if err != nil {
			return "", err
		}
		return "", e
	}

	return response.Header.Get("x-amz-job-id"), nil
}

func (c *Connection) InitiateInventoryJob(vault, description,
	topic string) (string, error) {
	j := jobRequest{Type: "inventory-retrieval", Description: description,
		SNSTopic: topic}
	rawBody, err := json.Marshal(j)
	if err != nil {
		return "", err
	}
	body := bytes.NewReader(rawBody)

	request, err := http.NewRequest("POST",
		"https://"+c.Signature.Region.Glacier+"/-/vaults/"+vault+"/jobs", body)
	if err != nil {
		return "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	err = c.Signature.Sign(request, body, nil)
	if err != nil {
		return "", err
	}

	response, err := c.Client.Do(request)
	if err != nil {
		return "", err
	}

	if response.StatusCode != 202 {
		body, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return "", err
		}
		err = response.Body.Close()
		if err != nil {
			return "", err
		}
		var e aws.Error
		err = json.Unmarshal(body, &e)
		if err != nil {
			return "", err
		}
		return "", e
	}

	return response.Header.Get("x-amz-job-id"), nil
}

func (c *Connection) DescribeJob() error {
	return nil
}

func (c *Connection) GetRetrievalJob(vault, job string, start, end uint) error {
	return nil
}

func (c *Connection) GetInventoryJob(vault, job string) (Inventory, error) {
	request, err := http.NewRequest("GET", "https://"+
		c.Signature.Region.Glacier+"/-/vaults/"+vault+"/jobs/"+job+"/output",
		nil)
	if err != nil {
		return Inventory{}, err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	err = c.Signature.Sign(request, nil, nil)
	if err != nil {
		return Inventory{}, err
	}

	response, err := c.Client.Do(request)
	if err != nil {
		return Inventory{}, err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return Inventory{}, err
	}
	err = response.Body.Close()
	if err != nil {
		return Inventory{}, err
	}

	if response.StatusCode != 200 {
		var e aws.Error
		err = json.Unmarshal(body, &e)
		if err != nil {
			return Inventory{}, err
		}
		return Inventory{}, e
	}

	var i inventory
	err = json.Unmarshal(body, &i)
	if err != nil {
		return Inventory{}, err
	}

	var result Inventory
	result.VaultARN = i.VaultARN
	result.InventoryDate, err = time.Parse(time.RFC3339, i.InventoryDate)
	if err != nil {
		return Inventory{}, err
	}
	result.ArchiveList = make([]Archive, len(i.ArchiveList))
	for j, v := range i.ArchiveList {
		result.ArchiveList[j].ArchiveId = v.ArchiveId
		result.ArchiveList[j].ArchiveDescription = v.ArchiveDescription
		result.ArchiveList[j].CreationDate, err = time.Parse(time.RFC3339,
			v.CreationDate)
		if err != nil {
			return Inventory{}, err
		}
		result.ArchiveList[j].Size = v.Size
		result.ArchiveList[j].SHA256TreeHash = v.SHA256TreeHash
	}

	return result, nil
}

func (c *Connection) ListJobs(vault, completed, limit, marker,
	statusCode string) ([]Job, string, error) {
	get, err := url.Parse("https://" + c.Signature.Region.Glacier +
		"/-/vaults/" + vault + "/jobs")
	if err != nil {
		return nil, "", err
	}

	query := get.Query()
	if completed != "" {
		// TODO validate, true or false
		query.Add("completed", completed)
	}
	if limit != "" {
		// TODO validate, 1 - 1000
		query.Add("limit", limit)
	}
	if marker != "" {
		// TODO validate
		query.Add("marker", marker)
	}
	if statusCode != "" {
		// TODO validate, InProgress, Succeeded, or Failed
		query.Add("statuscode", statusCode)
	}
	get.RawQuery = query.Encode()

	request, err := http.NewRequest("GET", get.String(), nil)
	if err != nil {
		return nil, "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	err = c.Signature.Sign(request, nil, nil)
	if err != nil {
		return nil, "", err
	}

	response, err := c.Client.Do(request)
	if err != nil {
		return nil, "", err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, "", err
	}
	err = response.Body.Close()
	if err != nil {
		return nil, "", err
	}

	if response.StatusCode != 200 {
		var e aws.Error
		err = json.Unmarshal(body, &e)
		if err != nil {
			return nil, "", err
		}
		return nil, "", e
	}

	var jl jobList
	err = json.Unmarshal(body, &jl)
	if err != nil {
		return nil, "", err
	}

	jobs := make([]Job, len(jl.JobList))
	for i, v := range jl.JobList {
		jobs[i].Action = v.Action
		if v.ArchiveId != nil {
			jobs[i].ArchiveId = *v.ArchiveId
		}
		if v.ArchiveSizeInBytes != nil {
			jobs[i].ArchiveSizeInBytes = *v.ArchiveSizeInBytes
		}
		jobs[i].Completed = v.Completed
		jobs[i].CompletionDate, err = time.Parse(time.RFC3339, v.CompletionDate)
		if err != nil {
			return nil, "", err
		}
		jobs[i].CreationDate, err = time.Parse(time.RFC3339, v.CreationDate)
		if err != nil {
			return nil, "", err
		}
		if v.InventorySizeInBytes != nil {
			jobs[i].InventorySizeInBytes = *v.InventorySizeInBytes
		}
		jobs[i].JobDescription = v.JobDescription
		jobs[i].JobId = v.JobId
		if v.SHA256TreeHash != nil {
			jobs[i].SHA256TreeHash = *v.SHA256TreeHash
		}
		jobs[i].SNSTopic = v.SNSTopic
		jobs[i].StatusCode = v.StatusCode
		jobs[i].StatusMessage = v.StatusMessage
		jobs[i].VaultARN = v.VaultARN
	}

	var m string
	if jl.Marker != nil {
		m = *jl.Marker
	}

	return jobs, m, nil
}
<commit_msg>Added retrieval code, but untested.<commit_after>package glacier

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/rdwilliamson/aws"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)

type jobRequest struct {
	Type        string
	ArchiveId   string `json:",omitempty"` // archive retrieval only
	Description string
	Format      string `json:",omitempty"` // inventory retrieval only
	SNSTopic    string
}

type Archive struct {
	ArchiveId          string
	ArchiveDescription string
	CreationDate       time.Time
	Size               uint64
	SHA256TreeHash     string
}

type Inventory struct {
	VaultARN      string
	InventoryDate time.Time
	ArchiveList   []Archive
}

// TODO write unmarshaler instead of using these structs
type archive struct {
	ArchiveId          string
	ArchiveDescription string
	CreationDate       string
	Size               uint64
	SHA256TreeHash     string
}
type inventory struct {
	VaultARN      string
	InventoryDate string
	ArchiveList   []archive
}

type Job struct {
	Action               string
	ArchiveId            string
	ArchiveSizeInBytes   uint64
	Completed            bool
	CompletionDate       time.Time
	CreationDate         time.Time
	InventorySizeInBytes uint
	JobDescription       string
	JobId                string
	SHA256TreeHash       string
	SNSTopic             string
	StatusCode           string
	StatusMessage        string
	VaultARN             string
}

// TODO write unmarshaler instead of using these structs
type job struct {
	Action               string
	ArchiveId            *string
	ArchiveSizeInBytes   *uint64
	Completed            bool
	CompletionDate       string
	CreationDate         string
	InventorySizeInBytes *uint
	JobDescription       string
	JobId                string
	SHA256TreeHash       *string
	SNSTopic             string
	StatusCode           string
	StatusMessage        string
	VaultARN             string
}
type jobList struct {
	Marker  *string
	JobList []job
}

func (c *Connection) InitiateRetrievalJob(vault, archive, topic,
	description string) (string, error) {
	j := jobRequest{Type: "archive-retrieval", ArchiveId: archive,
		Description: description, SNSTopic: topic}
	rawBody, _ := json.Marshal(j)
	body := bytes.NewReader(rawBody)

	request, err := http.NewRequest("POST",
		"https://"+c.Signature.Region.Glacier+"/-/vaults/"+vault+"/jobs", body)
	if err != nil {
		return "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	err = c.Signature.Sign(request, body, nil)
	if err != nil {
		return "", err
	}

	response, err := c.Client.Do(request)
	if err != nil {
		return "", err
	}

	if response.StatusCode != 202 {
		body, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return "", err
		}
		err = response.Body.Close()
		if err != nil {
			return "", err
		}
		var e aws.Error
		err = json.Unmarshal(body, &e)
		if err != nil {
			return "", err
		}
		return "", e
	}

	return response.Header.Get("x-amz-job-id"), nil
}

func (c *Connection) InitiateInventoryJob(vault, description,
	topic string) (string, error) {
	j := jobRequest{Type: "inventory-retrieval", Description: description,
		SNSTopic: topic}
	rawBody, err := json.Marshal(j)
	if err != nil {
		return "", err
	}
	body := bytes.NewReader(rawBody)

	request, err := http.NewRequest("POST",
		"https://"+c.Signature.Region.Glacier+"/-/vaults/"+vault+"/jobs", body)
	if err != nil {
		return "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	err = c.Signature.Sign(request, body, nil)
	if err != nil {
		return "", err
	}

	response, err := c.Client.Do(request)
	if err != nil {
		return "", err
	}

	if response.StatusCode != 202 {
		body, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return "", err
		}
		err = response.Body.Close()
		if err != nil {
			return "", err
		}
		var e aws.Error
		err = json.Unmarshal(body, &e)
		if err != nil {
			return "", err
		}
		return "", e
	}

	return response.Header.Get("x-amz-job-id"), nil
}

func (c *Connection) DescribeJob() error {
	return nil
}

func (c *Connection) GetRetrievalJob(vault, job string, start,
	end uint) (io.ReadCloser, error) {
	request, err := http.NewRequest("GET", "https://"+
		c.Signature.Region.Glacier+"/-/vaults/"+vault+"/jobs/"+job+"/output",
		nil)
	if err != nil {
		return nil, err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	if end > 0 {
		request.Header.Add("Range", fmt.Sprintf("bytes %d-%d/*", start, end))
	}

	response, err := c.Client.Do(request)
	if err != nil {
		return nil, err
	}

	if response.StatusCode != 200 {
		body, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return nil, err
		}
		err = response.Body.Close()
		if err != nil {
			return nil, err
		}
		var e aws.Error
		err = json.Unmarshal(body, &e)
		if err != nil {
			return nil, err
		}
		return nil, e
	}

	// TODO return content range and x-amz-sha256-tree-hash
	return nil, err
}

func (c *Connection) GetInventoryJob(vault, job string) (Inventory, error) {
	request, err := http.NewRequest("GET", "https://"+
		c.Signature.Region.Glacier+"/-/vaults/"+vault+"/jobs/"+job+"/output",
		nil)
	if err != nil {
		return Inventory{}, err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	err = c.Signature.Sign(request, nil, nil)
	if err != nil {
		return Inventory{}, err
	}

	response, err := c.Client.Do(request)
	if err != nil {
		return Inventory{}, err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return Inventory{}, err
	}
	err = response.Body.Close()
	if err != nil {
		return Inventory{}, err
	}

	if response.StatusCode != 200 {
		var e aws.Error
		err = json.Unmarshal(body, &e)
		if err != nil {
			return Inventory{}, err
		}
		return Inventory{}, e
	}

	var i inventory
	err = json.Unmarshal(body, &i)
	if err != nil {
		return Inventory{}, err
	}

	var result Inventory
	result.VaultARN = i.VaultARN
	result.InventoryDate, err = time.Parse(time.RFC3339, i.InventoryDate)
	if err != nil {
		return Inventory{}, err
	}
	result.ArchiveList = make([]Archive, len(i.ArchiveList))
	for j, v := range i.ArchiveList {
		result.ArchiveList[j].ArchiveId = v.ArchiveId
		result.ArchiveList[j].ArchiveDescription = v.ArchiveDescription
		result.ArchiveList[j].CreationDate, err = time.Parse(time.RFC3339,
			v.CreationDate)
		if err != nil {
			return Inventory{}, err
		}
		result.ArchiveList[j].Size = v.Size
		result.ArchiveList[j].SHA256TreeHash = v.SHA256TreeHash
	}

	return result, nil
}

func (c *Connection) ListJobs(vault, completed, limit, marker,
	statusCode string) ([]Job, string, error) {
	get, err := url.Parse("https://" + c.Signature.Region.Glacier +
		"/-/vaults/" + vault + "/jobs")
	if err != nil {
		return nil, "", err
	}

	query := get.Query()
	if completed != "" {
		// TODO validate, true or false
		query.Add("completed", completed)
	}
	if limit != "" {
		// TODO validate, 1 - 1000
		query.Add("limit", limit)
	}
	if marker != "" {
		// TODO validate
		query.Add("marker", marker)
	}
	if statusCode != "" {
		// TODO validate, InProgress, Succeeded, or Failed
		query.Add("statuscode", statusCode)
	}
	get.RawQuery = query.Encode()

	request, err := http.NewRequest("GET", get.String(), nil)
	if err != nil {
		return nil, "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	err = c.Signature.Sign(request, nil, nil)
	if err != nil {
		return nil, "", err
	}

	response, err := c.Client.Do(request)
	if err != nil {
		return nil, "", err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, "", err
	}
	err = response.Body.Close()
	if err != nil {
		return nil, "", err
	}

	if response.StatusCode != 200 {
		var e aws.Error
		err = json.Unmarshal(body, &e)
		if err != nil {
			return nil, "", err
		}
		return nil, "", e
	}

	var jl jobList
	err = json.Unmarshal(body, &jl)
	if err != nil {
		return nil, "", err
	}

	jobs := make([]Job, len(jl.JobList))
	for i, v := range jl.JobList {
		jobs[i].Action = v.Action
		if v.ArchiveId != nil {
			jobs[i].ArchiveId = *v.ArchiveId
		}
		if v.ArchiveSizeInBytes != nil {
			jobs[i].ArchiveSizeInBytes = *v.ArchiveSizeInBytes
		}
		jobs[i].Completed = v.Completed
		jobs[i].CompletionDate, err = time.Parse(time.RFC3339, v.CompletionDate)
		if err != nil {
			return nil, "", err
		}
		jobs[i].CreationDate, err = time.Parse(time.RFC3339, v.CreationDate)
		if err != nil {
			return nil, "", err
		}
		if v.InventorySizeInBytes != nil {
			jobs[i].InventorySizeInBytes = *v.InventorySizeInBytes
		}
		jobs[i].JobDescription = v.JobDescription
		jobs[i].JobId = v.JobId
		if v.SHA256TreeHash != nil {
			jobs[i].SHA256TreeHash = *v.SHA256TreeHash
		}
		jobs[i].SNSTopic = v.SNSTopic
		jobs[i].StatusCode = v.StatusCode
		jobs[i].StatusMessage = v.StatusMessage
		jobs[i].VaultARN = v.VaultARN
	}

	var m string
	if jl.Marker != nil {
		m = *jl.Marker
	}

	return jobs, m, nil
}
<|endoftext|>


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

package snappy

import (
	"encoding/binary"
	"errors"
	"io"
)

var (
	// ErrCorrupt reports that the input is invalid.
	ErrCorrupt = errors.New("snappy: corrupt input")
	// ErrTooLarge reports that the uncompressed length is too large.
	ErrTooLarge = errors.New("snappy: decoded block is too large")
	// ErrUnsupported reports that the input isn't supported.
	ErrUnsupported = errors.New("snappy: unsupported input")

	errUnsupportedCopy4Tag      = errors.New("snappy: unsupported COPY_4 tag")
	errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
)

// DecodedLen returns the length of the decoded block.
func DecodedLen(src []byte) (int, error) {
	v, _, err := decodedLen(src)
	return v, err
}

// decodedLen returns the length of the decoded block and the number of bytes
// that the length header occupied.
func decodedLen(src []byte) (blockLen, headerLen int, err error) {
	v, n := binary.Uvarint(src)
	if n <= 0 || v > 0xffffffff {
		return 0, 0, ErrCorrupt
	}

	const wordSize = 32 << (^uint(0) >> 32 & 1)
	if wordSize == 32 && v > 0x7fffffff {
		return 0, 0, ErrTooLarge
	}
	return int(v), n, nil
}

// Decode returns the decoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire decoded block.
// Otherwise, a newly allocated slice will be returned.
//
// It is valid to pass a nil dst.
func Decode(dst, src []byte) ([]byte, error) {
	dLen, s, err := decodedLen(src)
	if err != nil {
		return nil, err
	}
	if dLen <= len(dst) {
		dst = dst[:dLen]
	} else {
		dst = make([]byte, dLen)
	}

	var d, offset, length int
	for s < len(src) {
		switch src[s] & 0x03 {
		case tagLiteral:
			x := uint32(src[s] >> 2)
			switch {
			case x < 60:
				s++
			case x == 60:
				s += 2
				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
					return nil, ErrCorrupt
				}
				x = uint32(src[s-1])
			case x == 61:
				s += 3
				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
					return nil, ErrCorrupt
				}
				x = uint32(src[s-2]) | uint32(src[s-1])<<8
			case x == 62:
				s += 4
				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
					return nil, ErrCorrupt
				}
				x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
			case x == 63:
				s += 5
				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
					return nil, ErrCorrupt
				}
				x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
			}
			length = int(x) + 1
			if length <= 0 {
				return nil, errUnsupportedLiteralLength
			}
			if length > len(dst)-d || length > len(src)-s {
				return nil, ErrCorrupt
			}
			copy(dst[d:], src[s:s+length])
			d += length
			s += length
			continue

		case tagCopy1:
			s += 2
			if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
				return nil, ErrCorrupt
			}
			length = 4 + int(src[s-2])>>2&0x7
			offset = int(src[s-2])&0xe0<<3 | int(src[s-1])

		case tagCopy2:
			s += 3
			if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
				return nil, ErrCorrupt
			}
			length = 1 + int(src[s-3])>>2
			offset = int(src[s-2]) | int(src[s-1])<<8

		case tagCopy4:
			return nil, errUnsupportedCopy4Tag
		}

		if offset <= 0 || d < offset || length > len(dst)-d {
			return nil, ErrCorrupt
		}
		for end := d + length; d != end; d++ {
			dst[d] = dst[d-offset]
		}
	}
	if d != dLen {
		return nil, ErrCorrupt
	}
	return dst[:d], nil
}

// NewReader returns a new Reader that decompresses from r, using the framing
// format described at
// https://github.com/google/snappy/blob/master/framing_format.txt
func NewReader(r io.Reader) *Reader {
	return &Reader{
		r:       r,
		decoded: make([]byte, maxBlockSize),
		buf:     make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize),
	}
}

// Reader is an io.Reader that can read Snappy-compressed bytes.
type Reader struct {
	r       io.Reader
	err     error
	decoded []byte
	buf     []byte
	// decoded[i:j] contains decoded bytes that have not yet been passed on.
	i, j       int
	readHeader bool
}

// Reset discards any buffered data, resets all state, and switches the Snappy
// reader to read from r. This permits reusing a Reader rather than allocating
// a new one.
func (r *Reader) Reset(reader io.Reader) {
	r.r = reader
	r.err = nil
	r.i = 0
	r.j = 0
	r.readHeader = false
}

func (r *Reader) readFull(p []byte) (ok bool) {
	if _, r.err = io.ReadFull(r.r, p); r.err != nil {
		if r.err == io.ErrUnexpectedEOF {
			r.err = ErrCorrupt
		}
		return false
	}
	return true
}

// Read satisfies the io.Reader interface.
func (r *Reader) Read(p []byte) (int, error) {
	if r.err != nil {
		return 0, r.err
	}
	for {
		if r.i < r.j {
			n := copy(p, r.decoded[r.i:r.j])
			r.i += n
			return n, nil
		}
		if !r.readFull(r.buf[:4]) {
			return 0, r.err
		}
		chunkType := r.buf[0]
		if !r.readHeader {
			if chunkType != chunkTypeStreamIdentifier {
				r.err = ErrCorrupt
				return 0, r.err
			}
			r.readHeader = true
		}
		chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
		if chunkLen > len(r.buf) {
			r.err = ErrUnsupported
			return 0, r.err
		}

		// The chunk types are specified at
		// https://github.com/google/snappy/blob/master/framing_format.txt
		switch chunkType {
		case chunkTypeCompressedData:
			// Section 4.2. Compressed data (chunk type 0x00).
			if chunkLen < checksumSize {
				r.err = ErrCorrupt
				return 0, r.err
			}
			buf := r.buf[:chunkLen]
			if !r.readFull(buf) {
				return 0, r.err
			}
			checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
			buf = buf[checksumSize:]

			n, err := DecodedLen(buf)
			if err != nil {
				r.err = err
				return 0, r.err
			}
			if n > len(r.decoded) {
				r.err = ErrCorrupt
				return 0, r.err
			}
			if _, err := Decode(r.decoded, buf); err != nil {
				r.err = err
				return 0, r.err
			}
			if crc(r.decoded[:n]) != checksum {
				r.err = ErrCorrupt
				return 0, r.err
			}
			r.i, r.j = 0, n
			continue

		case chunkTypeUncompressedData:
			// Section 4.3. Uncompressed data (chunk type 0x01).
			if chunkLen < checksumSize {
				r.err = ErrCorrupt
				return 0, r.err
			}
			buf := r.buf[:checksumSize]
			if !r.readFull(buf) {
				return 0, r.err
			}
			checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
			// Read directly into r.decoded instead of via r.buf.
			n := chunkLen - checksumSize
			if !r.readFull(r.decoded[:n]) {
				return 0, r.err
			}
			if crc(r.decoded[:n]) != checksum {
				r.err = ErrCorrupt
				return 0, r.err
			}
			r.i, r.j = 0, n
			continue

		case chunkTypeStreamIdentifier:
			// Section 4.1. Stream identifier (chunk type 0xff).
			if chunkLen != len(magicBody) {
				r.err = ErrCorrupt
				return 0, r.err
			}
			if !r.readFull(r.buf[:len(magicBody)]) {
				return 0, r.err
			}
			for i := 0; i < len(magicBody); i++ {
				if r.buf[i] != magicBody[i] {
					r.err = ErrCorrupt
					return 0, r.err
				}
			}
			continue
		}

		if chunkType <= 0x7f {
			// Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
			r.err = ErrUnsupported
			return 0, r.err
		}
		// Section 4.4 Padding (chunk type 0xfe).
		// Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
		if !r.readFull(r.buf[:chunkLen]) {
			return 0, r.err
		}
	}
}
<commit_msg>Note that Decode's dst and src must not overlap.<commit_after>// Copyright 2011 The Snappy-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package snappy

import (
	"encoding/binary"
	"errors"
	"io"
)

var (
	// ErrCorrupt reports that the input is invalid.
	ErrCorrupt = errors.New("snappy: corrupt input")
	// ErrTooLarge reports that the uncompressed length is too large.
	ErrTooLarge = errors.New("snappy: decoded block is too large")
	// ErrUnsupported reports that the input isn't supported.
	ErrUnsupported = errors.New("snappy: unsupported input")

	errUnsupportedCopy4Tag      = errors.New("snappy: unsupported COPY_4 tag")
	errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
)

// DecodedLen returns the length of the decoded block.
func DecodedLen(src []byte) (int, error) {
	v, _, err := decodedLen(src)
	return v, err
}

// decodedLen returns the length of the decoded block and the number of bytes
// that the length header occupied.
func decodedLen(src []byte) (blockLen, headerLen int, err error) {
	v, n := binary.Uvarint(src)
	if n <= 0 || v > 0xffffffff {
		return 0, 0, ErrCorrupt
	}

	const wordSize = 32 << (^uint(0) >> 32 & 1)
	if wordSize == 32 && v > 0x7fffffff {
		return 0, 0, ErrTooLarge
	}
	return int(v), n, nil
}

// Decode returns the decoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire decoded block.
// Otherwise, a newly allocated slice will be returned.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
func Decode(dst, src []byte) ([]byte, error) {
	dLen, s, err := decodedLen(src)
	if err != nil {
		return nil, err
	}
	if dLen <= len(dst) {
		dst = dst[:dLen]
	} else {
		dst = make([]byte, dLen)
	}

	var d, offset, length int
	for s < len(src) {
		switch src[s] & 0x03 {
		case tagLiteral:
			x := uint32(src[s] >> 2)
			switch {
			case x < 60:
				s++
			case x == 60:
				s += 2
				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
					return nil, ErrCorrupt
				}
				x = uint32(src[s-1])
			case x == 61:
				s += 3
				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
					return nil, ErrCorrupt
				}
				x = uint32(src[s-2]) | uint32(src[s-1])<<8
			case x == 62:
				s += 4
				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
					return nil, ErrCorrupt
				}
				x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
			case x == 63:
				s += 5
				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
					return nil, ErrCorrupt
				}
				x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
			}
			length = int(x) + 1
			if length <= 0 {
				return nil, errUnsupportedLiteralLength
			}
			if length > len(dst)-d || length > len(src)-s {
				return nil, ErrCorrupt
			}
			copy(dst[d:], src[s:s+length])
			d += length
			s += length
			continue

		case tagCopy1:
			s += 2
			if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
				return nil, ErrCorrupt
			}
			length = 4 + int(src[s-2])>>2&0x7
			offset = int(src[s-2])&0xe0<<3 | int(src[s-1])

		case tagCopy2:
			s += 3
			if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
				return nil, ErrCorrupt
			}
			length = 1 + int(src[s-3])>>2
			offset = int(src[s-2]) | int(src[s-1])<<8

		case tagCopy4:
			return nil, errUnsupportedCopy4Tag
		}

		if offset <= 0 || d < offset || length > len(dst)-d {
			return nil, ErrCorrupt
		}
		for end := d + length; d != end; d++ {
			dst[d] = dst[d-offset]
		}
	}
	if d != dLen {
		return nil, ErrCorrupt
	}
	return dst[:d], nil
}

// NewReader returns a new Reader that decompresses from r, using the framing
// format described at
// https://github.com/google/snappy/blob/master/framing_format.txt
func NewReader(r io.Reader) *Reader {
	return &Reader{
		r:       r,
		decoded: make([]byte, maxBlockSize),
		buf:     make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize),
	}
}

// Reader is an io.Reader that can read Snappy-compressed bytes.
type Reader struct {
	r       io.Reader
	err     error
	decoded []byte
	buf     []byte
	// decoded[i:j] contains decoded bytes that have not yet been passed on.
	i, j       int
	readHeader bool
}

// Reset discards any buffered data, resets all state, and switches the Snappy
// reader to read from r. This permits reusing a Reader rather than allocating
// a new one.
func (r *Reader) Reset(reader io.Reader) {
	r.r = reader
	r.err = nil
	r.i = 0
	r.j = 0
	r.readHeader = false
}

func (r *Reader) readFull(p []byte) (ok bool) {
	if _, r.err = io.ReadFull(r.r, p); r.err != nil {
		if r.err == io.ErrUnexpectedEOF {
			r.err = ErrCorrupt
		}
		return false
	}
	return true
}

// Read satisfies the io.Reader interface.
func (r *Reader) Read(p []byte) (int, error) {
	if r.err != nil {
		return 0, r.err
	}
	for {
		if r.i < r.j {
			n := copy(p, r.decoded[r.i:r.j])
			r.i += n
			return n, nil
		}
		if !r.readFull(r.buf[:4]) {
			return 0, r.err
		}
		chunkType := r.buf[0]
		if !r.readHeader {
			if chunkType != chunkTypeStreamIdentifier {
				r.err = ErrCorrupt
				return 0, r.err
			}
			r.readHeader = true
		}
		chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
		if chunkLen > len(r.buf) {
			r.err = ErrUnsupported
			return 0, r.err
		}

		// The chunk types are specified at
		// https://github.com/google/snappy/blob/master/framing_format.txt
		switch chunkType {
		case chunkTypeCompressedData:
			// Section 4.2. Compressed data (chunk type 0x00).
			if chunkLen < checksumSize {
				r.err = ErrCorrupt
				return 0, r.err
			}
			buf := r.buf[:chunkLen]
			if !r.readFull(buf) {
				return 0, r.err
			}
			checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
			buf = buf[checksumSize:]

			n, err := DecodedLen(buf)
			if err != nil {
				r.err = err
				return 0, r.err
			}
			if n > len(r.decoded) {
				r.err = ErrCorrupt
				return 0, r.err
			}
			if _, err := Decode(r.decoded, buf); err != nil {
				r.err = err
				return 0, r.err
			}
			if crc(r.decoded[:n]) != checksum {
				r.err = ErrCorrupt
				return 0, r.err
			}
			r.i, r.j = 0, n
			continue

		case chunkTypeUncompressedData:
			// Section 4.3. Uncompressed data (chunk type 0x01).
			if chunkLen < checksumSize {
				r.err = ErrCorrupt
				return 0, r.err
			}
			buf := r.buf[:checksumSize]
			if !r.readFull(buf) {
				return 0, r.err
			}
			checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
			// Read directly into r.decoded instead of via r.buf.
			n := chunkLen - checksumSize
			if !r.readFull(r.decoded[:n]) {
				return 0, r.err
			}
			if crc(r.decoded[:n]) != checksum {
				r.err = ErrCorrupt
				return 0, r.err
			}
			r.i, r.j = 0, n
			continue

		case chunkTypeStreamIdentifier:
			// Section 4.1. Stream identifier (chunk type 0xff).
			if chunkLen != len(magicBody) {
				r.err = ErrCorrupt
				return 0, r.err
			}
			if !r.readFull(r.buf[:len(magicBody)]) {
				return 0, r.err
			}
			for i := 0; i < len(magicBody); i++ {
				if r.buf[i] != magicBody[i] {
					r.err = ErrCorrupt
					return 0, r.err
				}
			}
			continue
		}

		if chunkType <= 0x7f {
			// Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
			r.err = ErrUnsupported
			return 0, r.err
		}
		// Section 4.4 Padding (chunk type 0xfe).
		// Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
		if !r.readFull(r.buf[:chunkLen]) {
			return 0, r.err
		}
	}
}
<|endoftext|>


<commit_before>package signals

import "encoding/gob"

func init() {
	gob.Register(Shifted{})
	gob.Register(Spedup{})
	gob.Register(SpedupProgressive{})
	gob.Register(Looped{})
	gob.Register(Inverted{})
	gob.Register(Reversed{})
	gob.Register(Reflected{})
	gob.Register(RateModulated{})
	gob.Register(Triggered{})
	gob.Register(Segmented{})
}

// a Signal that shifts the x of another Signal
type Shifted struct {
	Signal
	Shift x
}

func (s Shifted) property(t x) y {
	return s.Signal.property(t - s.Shift)
}

// a Signal that scales the x of another Signal
type Spedup struct {
	Signal
	Factor float32
}

func (s Spedup) property(t x) y {
	return s.Signal.property(x(float32(t) * s.Factor))
}

/*
// TODO spedup tone should have MaxX and period changed
// a Signal that scales the x of another Signal
type Squeeze struct {
	LimitedSignal
	Factor float32
}

func (s Squeeze) Call(t x) y {
	return s.LimitedSignal.Call(x(float32(t) * s.Factor))
}

func (s Squeeze) MaxX() x {
	return x(float32(s.LimitedSignal.MaxX())*s.Factor)
}

*/

type SpedupProgressive struct {
	Signal
	Rate x
}

func (s SpedupProgressive) property(t x) y {
	return s.Signal.property(t + t*t/s.Rate)
}

// a PeriodicSignal that is a Signal repeated with Loop length x.
type Looped struct {
	Signal
	Loop x
}

func (s Looped) property(t x) y {
	return s.Signal.property(t % s.Loop)
}

func (s Looped) Period() x {
	return s.Loop
}

// a PeriodicSignal that is repeating loop of Cycle repeats of another PeriodicSignal.
// if the PeriodicSignal is actually precisely repeating, then an integer value of Cycles, results in no change.
type Repeated struct {
	PeriodicSignal
	Cycles float32
}

func (s Repeated) Period() x {
	return x(float32(s.PeriodicSignal.Period()) * s.Cycles)
}

func (s Repeated) property(t x) y {
	return s.PeriodicSignal.property((t % s.Period()) % s.PeriodicSignal.Period())
}

// a Signal that produces y values that are the negative of another Signals y values
type Inverted struct {
	Signal
}

func (s Inverted) property(t x) y {
	return -s.Signal.property(t)
}

// a Signal that returns y's that are for the -ve x of another Signal
type Reversed struct {
	Signal
}

func (s Reversed) property(t x) y {
	return s.Signal.property(-t)
}

// a Signal that produces values that are flipped over, (Maxy<->zero) of another Signal
type Reflected struct {
	Signal
}

func (s Reflected) property(t x) y {
	if r := s.Signal.property(t); r < 0 {
		return -unitY - r
	} else {
		return unitY - r
	}
}

// a Signal that stretches the x values of another Signal, in proportion to the value of a modulation Signal
type RateModulated struct {
	Signal
	Modulation Signal
	Factor     x
}

func (s RateModulated) property(t x) y {
	return s.Signal.property(t + MultiplyX(float64(s.Modulation.property(t))/maxyfloat64, s.Factor))
}

// Segmented is a Signal that has equal width uniform gradients that can approximate another Signal.
type Segmented struct {
	Signal
	Width x
	cache *segmentCache // by being a pointer this is mutable in methods, without needing a pointer receiver.

}

type segmentCache struct {
	x1, x2 x
	l1, l2 x
}

func NewSegmented(s Signal, w x) Segmented {
	return Segmented{s, w, &segmentCache{}}
}

// repeated calls within the same segment, are generated from cached end values, so avoids calls to the embedded Signal.
func (s Segmented) property(t x) y {
	temp := t % s.Width
	if t-temp != s.cache.x1 || t+s.Width-temp != s.cache.x2 {
		// TODO reuse by swap ends
		s.cache.x1 = t - temp
		s.cache.x2 = t + s.Width - temp
		s.cache.l1 = x(s.Signal.property(s.cache.x1)) / s.Width
		s.cache.l2 = x(s.Signal.property(s.cache.x2))/s.Width - s.cache.l1
	}
	return y(s.cache.l1*s.Width + s.cache.l2*temp)
}

// Triggered shifts a Signal's x so the Signal crosses a trigger y at zero x.
// it searches with a Resolution, from Shift+Resolution to MaxShift, then from 0 to Shift.
// Delay is set to last found trigger, so subsequent uses finds new crossing, and wraps round.
// Rising can be alternated to find either way crossing
type Triggered struct {
	Signal
	Trigger    y
	Rising     bool
	Resolution x
	MaxShift   x
	Found      *searchInfo // by being a pointer this is mutable in methods, without needing a pointer receiver.
}

type searchInfo struct {
	Shift   x
	trigger y
	rising  bool
}

func NewTriggered(s Signal, trigger y, rising bool, res, max x) Triggered {
	return Triggered{s, trigger, rising, res, max, &searchInfo{}}
}

func (s Triggered) property(t x) y {
	if s.Trigger != s.Found.trigger || s.Found.rising != s.Rising {
		s.Found.trigger = s.Trigger
		s.Found.rising = s.Rising
		if s.Rising && s.Signal.property(s.Found.Shift) > s.Trigger || !s.Rising && s.Signal.property(s.Found.Shift) < s.Trigger {
			s.Found.Shift += s.Resolution
		}
		for t := s.Found.Shift; t <= s.MaxShift; t += s.Resolution {
			if s.Rising && s.Signal.property(t) > s.Trigger || !s.Rising && s.Signal.property(t) < s.Trigger {
				s.Found.Shift = t
				return s.Signal.property(t)
			}
		}
		for t := x(0); t < s.Found.Shift; t += s.Resolution {
			if s.Rising && s.Signal.property(t) > s.Trigger || !s.Rising && s.Signal.property(t) < s.Trigger {
				s.Found.Shift = t
				return s.Signal.property(t)
			}
		}
		s.Found.Shift = 0
	}
	return s.Signal.property(t + s.Found.Shift)
}
<commit_msg>comments<commit_after>package signals

import "encoding/gob"

func init() {
	gob.Register(Shifted{})
	gob.Register(Spedup{})
	gob.Register(SpedupProgressive{})
	gob.Register(Looped{})
	gob.Register(Inverted{})
	gob.Register(Reversed{})
	gob.Register(Reflected{})
	gob.Register(RateModulated{})
	gob.Register(Triggered{})
	gob.Register(Segmented{})
}

// a Signal that shifts the x of another Signal
type Shifted struct {
	Signal
	Shift x
}

func (s Shifted) property(t x) y {
	return s.Signal.property(t - s.Shift)
}

// a Signal that scales the x of another Signal
type Spedup struct {
	Signal
	Factor float32
}

func (s Spedup) property(t x) y {
	return s.Signal.property(x(float32(t) * s.Factor))
}

/*
// TODO spedup tone should have MaxX and period changed
// a Signal that scales the x of another Signal
type Squeeze struct {
	LimitedSignal
	Factor float32
}

func (s Squeeze) Call(t x) y {
	return s.LimitedSignal.Call(x(float32(t) * s.Factor))
}

func (s Squeeze) MaxX() x {
	return x(float32(s.LimitedSignal.MaxX())*s.Factor)
}

*/

type SpedupProgressive struct {
	Signal
	Rate x
}

func (s SpedupProgressive) property(t x) y {
	return s.Signal.property(t + t*t/s.Rate)
}

// a PeriodicSignal that is a Signal repeated with Loop length x.
type Looped struct {
	Signal
	Loop x
}

func (s Looped) property(t x) y {
	return s.Signal.property(t % s.Loop)
}

func (s Looped) Period() x {
	return s.Loop
}

// a PeriodicSignal that is repeating loop of Cycle repeats of another PeriodicSignal.
// if the PeriodicSignal is actually precisely repeating, then an integer value of Cycles, results in no change.
type Repeated struct {
	PeriodicSignal
	Cycles float32
}

func (s Repeated) Period() x {
	return x(float32(s.PeriodicSignal.Period()) * s.Cycles)
}

func (s Repeated) property(t x) y {
	return s.PeriodicSignal.property((t % s.Period()) % s.PeriodicSignal.Period())
}

// a Signal that produces y values that are the negative of another Signals y values
type Inverted struct {
	Signal
}

func (s Inverted) property(t x) y {
	return -s.Signal.property(t)
}

// a Signal that returns y's that are for the -ve x of another Signal
type Reversed struct {
	Signal
}

func (s Reversed) property(t x) y {
	return s.Signal.property(-t)
}

// a Signal that produces values that are flipped over, (Maxy<->zero) of another Signal
type Reflected struct {
	Signal
}

func (s Reflected) property(t x) y {
	if r := s.Signal.property(t); r < 0 {
		return -unitY - r
	} else {
		return unitY - r
	}
}

// a Signal that stretches the x values of another Signal, in proportion to the value of a modulation Signal
type RateModulated struct {
	Signal
	Modulation Signal
	Factor     x
}

func (s RateModulated) property(t x) y {
	return s.Signal.property(t + MultiplyX(float64(s.Modulation.property(t))/maxyfloat64, s.Factor))
}

// Segmented is a Signal that is a sequence of equal width, uniform gradient, segments, that approximate another Signal.
// repeated calls within the same segment, are generated from cached end values, so avoiding calls to the embedded Signal.
type Segmented struct {
	Signal
	Width x
	cache *segmentCache // by being a pointer this is mutable in methods, without needing a pointer receiver.

}

type segmentCache struct {
	x1, x2 x
	l1, l2 x
}

func NewSegmented(s Signal, w x) Segmented {
	return Segmented{s, w, &segmentCache{}}
}

func (s Segmented) property(t x) y {
	temp := t % s.Width
	if t-temp != s.cache.x1 || t+s.Width-temp != s.cache.x2 {
		// TODO reuse by swap ends
		s.cache.x1 = t - temp
		s.cache.x2 = t + s.Width - temp
		s.cache.l1 = x(s.Signal.property(s.cache.x1)) / s.Width
		s.cache.l2 = x(s.Signal.property(s.cache.x2))/s.Width - s.cache.l1
	}
	return y(s.cache.l1*s.Width + s.cache.l2*temp)
}

// Triggered shifts a Signal's x so the Signal crosses a trigger y at zero x.
// it searches with a Resolution, from Shift+Resolution to MaxShift, then from 0 to Shift.
// Shift can be set initially, then is set to the last found trigger, so subsequent uses find new crossings, and wraps round.
// Rising can be alternated to find either way crossing
type Triggered struct {
	Signal
	Trigger    y
	Rising     bool
	Resolution x
	MaxShift   x
	Found      *searchInfo // by being a pointer this is mutable in methods, without needing a pointer receiver.
}

type searchInfo struct {
	Shift   x
	trigger y
	rising  bool
}

func NewTriggered(s Signal, trigger y, rising bool, res, max x) Triggered {
	return Triggered{s, trigger, rising, res, max, &searchInfo{}}
}

func (s Triggered) property(t x) y {
	if s.Trigger != s.Found.trigger || s.Found.rising != s.Rising {
		s.Found.trigger = s.Trigger
		s.Found.rising = s.Rising
		if s.Rising && s.Signal.property(s.Found.Shift) > s.Trigger || !s.Rising && s.Signal.property(s.Found.Shift) < s.Trigger {
			s.Found.Shift += s.Resolution
		}
		for t := s.Found.Shift; t <= s.MaxShift; t += s.Resolution {
			if s.Rising && s.Signal.property(t) > s.Trigger || !s.Rising && s.Signal.property(t) < s.Trigger {
				s.Found.Shift = t
				return s.Signal.property(t)
			}
		}
		for t := x(0); t < s.Found.Shift; t += s.Resolution {
			if s.Rising && s.Signal.property(t) > s.Trigger || !s.Rising && s.Signal.property(t) < s.Trigger {
				s.Found.Shift = t
				return s.Signal.property(t)
			}
		}
		s.Found.Shift = 0
	}
	return s.Signal.property(t + s.Found.Shift)
}
<|endoftext|>


<commit_before>// Package math provides math helper functions.
package math

// IntAbs returns the absolute value of n.
func IntAbs(n int) int {
	if n < 0 {
		return -n
	}
	return n
}

// IntMax returns the larger of a and b.
func IntMax(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<commit_msg>Add permutation function to math package<commit_after>// Package math provides math helper functions.
package math

// IntAbs returns the absolute value of n.
func IntAbs(n int) int {
	if n < 0 {
		return -n
	}
	return n
}

// IntMax returns the larger of a and b.
func IntMax(a, b int) int {
	if a > b {
		return a
	}
	return b
}

// Factorial returns n!.
func Factorial(n int) int {
	if n == 0 {
		return 1
	}

	res := 1
	for i := 2; i <= n; i++ {
		res *= i
	}
	return res
}

// IntPermutations returns a slice of integer slices with all permutations of
// the input slice s.
func IntPermutations(s []int) [][]int {
	results := make(chan []int)
	permutations := make([][]int, Factorial(len(s)))

	go generateIntPermutation(len(s), s, results)
	for i := 0; i < len(permutations); i++ {
		permutations[i] = <-results
	}
	return permutations
}

// generateIntPermutation implements a variant of Heap's algorithm as shown in
// Sedgewicks's slides at https://www.cs.princeton.edu/~rs/talks/perms.pdf. It
// is not ideal in that the number of swaps performed is larger than the
// factorial of len(s), but it is simpler than the suggested implementation on
// Wikipedia.
func generateIntPermutation(n int, s []int, out chan<- []int) {
	if n == 1 {
		perm := make([]int, len(s))
		copy(perm, s)
		out <- perm
		return
	}

	for c := 0; c < n; c++ {
		generateIntPermutation(n-1, s, out)
		if n%2 == 1 {
			s[0], s[n-1] = s[n-1], s[0]
		} else {
			s[c], s[n-1] = s[n-1], s[c]
		}
	}
}
<|endoftext|>


<commit_before>package target

import (
	"errors"
	"fmt"
	"log"
	"math"

	"github.com/ready-steady/adapt"
	"github.com/turing-complete/laboratory/src/internal/config"
	"github.com/turing-complete/laboratory/src/internal/system"
)

type base struct {
	system *system.System
	config *config.Target

	ni uint
	no uint
}

func newBase(system *system.System, config *config.Target, ni, no uint) (base, error) {
	nm, nj, nf := len(config.Importance), len(config.Rejection), len(config.Refinement)
	if nm == 0 || nm != nj || nj != nf {
		return base{}, errors.New("the importance, refinement, and rejection " +
			"should not be empty and should have the same number of elements")
	}
	return base{system: system, config: config, ni: ni, no: no}, nil
}

func (self *base) Dimensions() (uint, uint) {
	return self.ni, self.no
}

func (_ *base) Monitor(progress *adapt.Progress) {
	if progress.Iteration == 0 {
		log.Printf("%5s %10s %15s %15s %15s\n", "Level", "Iteration",
			"Accepted Nodes", "Rejected Nodes", "Current Nodes")
	}
	log.Printf("%5d %10d %15d %15d %15d\n", progress.Level, progress.Iteration,
		progress.Accepted, progress.Rejected, progress.Current)
}

func (self *base) Score(location *adapt.Location, progress *adapt.Progress) float64 {
	config := self.config

	nj := uint(len(config.Importance))

	score, reject, refine := 0.0, true, false
	for i := uint(0); i < self.no; i++ {
		j := i % nj

		if config.Importance[j] == 0 {
			continue
		}

		s := math.Abs(location.Surplus[i])
		if s >= config.Rejection[j] {
			reject = false
		}
		if s > config.Refinement[j] {
			refine = true
		}

		score += config.Importance[j] * s
	}

	if reject {
		return -1
	}
	if !refine {
		return 0
	}

	return score
}

func (self *base) String() string {
	return fmt.Sprintf(`{"inputs": %d, "outputs": %d}`, self.ni, self.no)
}
<commit_msg>i/target: hide an unused argument<commit_after>package target

import (
	"errors"
	"fmt"
	"log"
	"math"

	"github.com/ready-steady/adapt"
	"github.com/turing-complete/laboratory/src/internal/config"
	"github.com/turing-complete/laboratory/src/internal/system"
)

type base struct {
	system *system.System
	config *config.Target

	ni uint
	no uint
}

func newBase(system *system.System, config *config.Target, ni, no uint) (base, error) {
	nm, nj, nf := len(config.Importance), len(config.Rejection), len(config.Refinement)
	if nm == 0 || nm != nj || nj != nf {
		return base{}, errors.New("the importance, refinement, and rejection " +
			"should not be empty and should have the same number of elements")
	}
	return base{system: system, config: config, ni: ni, no: no}, nil
}

func (self *base) Dimensions() (uint, uint) {
	return self.ni, self.no
}

func (_ *base) Monitor(progress *adapt.Progress) {
	if progress.Iteration == 0 {
		log.Printf("%5s %10s %15s %15s %15s\n", "Level", "Iteration",
			"Accepted Nodes", "Rejected Nodes", "Current Nodes")
	}
	log.Printf("%5d %10d %15d %15d %15d\n", progress.Level, progress.Iteration,
		progress.Accepted, progress.Rejected, progress.Current)
}

func (self *base) Score(location *adapt.Location, _ *adapt.Progress) float64 {
	config := self.config

	nj := uint(len(config.Importance))

	score, reject, refine := 0.0, true, false
	for i := uint(0); i < self.no; i++ {
		j := i % nj

		if config.Importance[j] == 0 {
			continue
		}

		s := math.Abs(location.Surplus[i])
		if s >= config.Rejection[j] {
			reject = false
		}
		if s > config.Refinement[j] {
			refine = true
		}

		score += config.Importance[j] * s
	}

	if reject {
		return -1
	}
	if !refine {
		return 0
	}

	return score
}

func (self *base) String() string {
	return fmt.Sprintf(`{"inputs": %d, "outputs": %d}`, self.ni, self.no)
}
<|endoftext|>


<commit_before>package mol2

import (
	"strconv"
)

type Atom struct {
	id int
	name string
	x, y, z float64
	atype int
	subst *AtomSubStructure
}

type AtomSubStructure struct {
	id int
	name string
	charge float64
	status AtomSubStatus
}

type AtomSubStatus byte

const (
	DSPMOD    AtomSubStatus = 1 << iota
	TYPECOL   AtomSubStatus = 1<< iota
	CAP       AtomSubStatus = 1 << iota
	BACKBONE  AtomSubStatus = 1 << iota
	DICT      AtomSubStatus = 1 << iota
	ESSENTIAL AtomSubStatus = 1 << iota
	WATER     AtomSubStatus = 1 << iota
	DIRECT    AtomSubStatus = 1 << iota
)

func NewAtomSubStructure(id int,
                         name string,
                         charge float64,
                         status AtomSubStatus) *AtomSubStructure {
	sub := new(AtomSubStructure)
	sub.status = status
	sub.name = name
	sub.charge = charge
	sub.id = id

	return sub
}

func (subst *AtomSubStructure) String() string {
	if subst == nil {
			return "none"
	}
	buffer := ""
	buffer += "{id = " + strconv.FormatInt(int64(subst.id), 10) + ";"
	buffer += "name = " + subst.name + ";"
	buffer += "charge = " + strconv.FormatFloat(subst.charge, 'e', -1, 64) + ";"
	// TODO: add status to display
	buffer += "}"

	return buffer
}

func (atom Atom) String() string {
	buffer := ""
	buffer += "id = " + strconv.FormatInt(int64(atom.id), 10) + "\n"
	buffer += "name = " + atom.name + "\n"
	buffer += "coords = (" + strconv.FormatFloat(atom.x, 'e', -1, 64) + ","
	buffer += strconv.FormatFloat(atom.y, 'e', -1, 64) + ","
	buffer += strconv.FormatFloat(atom.z, 'e', -1, 64) + ")\n"
	buffer += "type = " + AtomTypeToString(atom.atype) + "\n"
	buffer += "subst = " + atom.subst.String() + "\n"

	return buffer
}

func AtomParse(lex *Lexer) *Atom {
	atom := new(Atom)
	ok, err := lex.NextAtom()
	if err != nil {
		panic(err)
	}
	if ok {
		ok, id, err := lex.nextInt()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		atom.id = id
		ok, name, err := lex.nextId()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		atom.name = name
		ok, f, err := lex.nextReal()
		if err != nil {
			panic(err)
		}
		if !ok {
				return nil
		}
		atom.x = f;
		ok, f, err = lex.nextReal()
		if err != nil {
			panic(err)
		}
		if !ok {
				return nil
		}
		atom.y = f;
		ok, f, err = lex.nextReal()
		if err != nil {
			panic(err)
		}
		if !ok {
				return nil
		}
		atom.z = f;
		ok, atype, err := lex.nextId()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		atom.atype = AtomTypeGetByString(atype)
		atom.subst = AtomSubStructureParse(lex)

		return atom
	}

	return nil
}

func AtomSubStructureParse(lex *Lexer) *AtomSubStructure {
		ok, err := lex.nextNL()
		if !ok {
			return nil
		}
		ok, id, err := lex.nextInt()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		ok, name, err := lex.nextId()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		ok, charge, err := lex.nextReal()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		// TODO: add status parsing

		return NewAtomSubStructure(id, name, charge, 0)
}
<commit_msg>fix nil error<commit_after>package mol2

import (
	"strconv"
)

type Atom struct {
	id int
	name string
	x, y, z float64
	atype int
	subst *AtomSubStructure
}

type AtomSubStructure struct {
	id int
	name string
	charge float64
	status AtomSubStatus
}

type AtomSubStatus byte

const (
	DSPMOD    AtomSubStatus = 1 << iota
	TYPECOL   AtomSubStatus = 1<< iota
	CAP       AtomSubStatus = 1 << iota
	BACKBONE  AtomSubStatus = 1 << iota
	DICT      AtomSubStatus = 1 << iota
	ESSENTIAL AtomSubStatus = 1 << iota
	WATER     AtomSubStatus = 1 << iota
	DIRECT    AtomSubStatus = 1 << iota
)

func NewAtomSubStructure(id int,
                         name string,
                         charge float64,
                         status AtomSubStatus) *AtomSubStructure {
	sub := new(AtomSubStructure)
	sub.status = status
	sub.name = name
	sub.charge = charge
	sub.id = id

	return sub
}

func (subst *AtomSubStructure) String() string {
	if subst == nil {
			return "none"
	}
	buffer := ""
	buffer += "{id = " + strconv.FormatInt(int64(subst.id), 10) + ";"
	buffer += "name = " + subst.name + ";"
	buffer += "charge = " + strconv.FormatFloat(subst.charge, 'e', -1, 64) + ";"
	// TODO: add status to display
	buffer += "}"

	return buffer
}

func (atom Atom) String() string {
	buffer := ""
	buffer += "id = " + strconv.FormatInt(int64(atom.id), 10) + "\n"
	buffer += "name = " + atom.name + "\n"
	buffer += "coords = (" + strconv.FormatFloat(atom.x, 'e', -1, 64) + ","
	buffer += strconv.FormatFloat(atom.y, 'e', -1, 64) + ","
	buffer += strconv.FormatFloat(atom.z, 'e', -1, 64) + ")\n"
	buffer += "type = " + AtomTypeToString(atom.atype) + "\n"
	buffer += "subst = " + atom.subst.String() + "\n"

	return buffer
}

func AtomParse(lex *Lexer) *Atom {
	atom := new(Atom)
	ok, err := lex.NextAtom()
	if err != nil {
		panic(err)
	}
	if ok {
		ok, id, err := lex.nextInt()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		atom.id = id
		ok, name, err := lex.nextId()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		atom.name = name
		ok, f, err := lex.nextReal()
		if err != nil {
			panic(err)
		}
		if !ok {
				return nil
		}
		atom.x = f;
		ok, f, err = lex.nextReal()
		if err != nil {
			panic(err)
		}
		if !ok {
				return nil
		}
		atom.y = f;
		ok, f, err = lex.nextReal()
		if err != nil {
			panic(err)
		}
		if !ok {
				return nil
		}
		atom.z = f;
		ok, atype, err := lex.nextId()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		atom.atype = AtomTypeGetByString(atype)
		atom.subst = AtomSubStructureParse(lex)

		return atom
	}

	return nil
}

func AtomSubStructureParse(lex *Lexer) *AtomSubStructure {
		ok, err := lex.nextNL()
		if ok {
			return nil
		}
		ok, id, err := lex.nextInt()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		ok, name, err := lex.nextId()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		ok, charge, err := lex.nextReal()
		if err != nil {
			panic(err)
		}
		if !ok {
			return nil
		}
		// TODO: add status parsing

		return NewAtomSubStructure(id, name, charge, 0)
}
<|endoftext|>


<commit_before>package komanda

const KomandaLogo = `

  ██╗  ██╗ ██████╗ ███╗   ███╗ █████╗ ███╗   ██╗██████╗  █████╗
  ██║ ██╔╝██╔═══██╗████╗ ████║██╔══██╗████╗  ██║██╔══██╗██╔══██╗
  █████╔╝ ██║   ██║██╔████╔██║███████║██╔██╗ ██║██║  ██║███████║
  ██╔═██╗ ██║   ██║██║╚██╔╝██║██╔══██║██║╚██╗██║██║  ██║██╔══██║
  ██║  ██╗╚██████╔╝██║ ╚═╝ ██║██║  ██║██║ ╚████║██████╔╝██║  ██║
  ╚═╝  ╚═╝ ╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝╚═════╝ ╚═╝  ╚═╝`

// Name of application
const Name = "komanda"

// Description of application
const Description = "IRC Client"

// Version number
const Version = "0.4.0"

// Website number
const Website = "github.com/mephux/komanda"
<commit_msg>version gump<commit_after>package komanda

const KomandaLogo = `

  ██╗  ██╗ ██████╗ ███╗   ███╗ █████╗ ███╗   ██╗██████╗  █████╗
  ██║ ██╔╝██╔═══██╗████╗ ████║██╔══██╗████╗  ██║██╔══██╗██╔══██╗
  █████╔╝ ██║   ██║██╔████╔██║███████║██╔██╗ ██║██║  ██║███████║
  ██╔═██╗ ██║   ██║██║╚██╔╝██║██╔══██║██║╚██╗██║██║  ██║██╔══██║
  ██║  ██╗╚██████╔╝██║ ╚═╝ ██║██║  ██║██║ ╚████║██████╔╝██║  ██║
  ╚═╝  ╚═╝ ╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝╚═════╝ ╚═╝  ╚═╝`

// Name of application
const Name = "komanda"

// Description of application
const Description = "IRC Client"

// Version number
const Version = "0.4.1"

// Website number
const Website = "github.com/mephux/komanda"
<|endoftext|>


<commit_before>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package gobuild

import (
	"runtime"
	"strings"
	"testing"

	"github.com/issue9/assert"
)

func TestGetExts(t *testing.T) {
	a := assert.New(t)

	a.Equal(getExts(""), []string{})
	a.Equal(getExts(",, ,"), []string{})
	a.Equal(getExts(",.go, ,.php,"), []string{".go", ".php"})
	a.Equal(getExts(",go,.php,"), []string{".go", ".php"})
	a.Equal(getExts(",go , .php,"), []string{".go", ".php"})
}

func TestRecursivePath(t *testing.T) {
	a := assert.New(t)

	paths, err := recursivePaths(false, []string{"./testdir"})
	a.NotError(err).
		Equal(paths, []string{
			"./testdir",
		})

	paths, err = recursivePaths(true, []string{"./testdir"})
	a.NotError(err).Equal(paths, []string{
		"./testdir",
		"testdir/testdir1",
		"testdir/testdir2",
		"testdir/testdir2/testdir3",
	})

	paths, err = recursivePaths(true, []string{"./testdir/testdir1", "./testdir/testdir2"})
	a.NotError(err).
		Equal(paths, []string{
			"./testdir/testdir1",
			"./testdir/testdir2",
			"testdir/testdir2/testdir3",
		})

	paths, err = recursivePaths(true, []string{"./testdir/testdir2"})
	a.NotError(err).Equal(paths, []string{
		"./testdir/testdir2",
		"testdir/testdir2/testdir3",
	})
}

func TestSplitArgs(t *testing.T) {
	a := assert.New(t)

	a.Equal(splitArgs("x=5 y=6"), []string{"x", "5", "y", "6"})
	a.Equal(splitArgs("xxx=5 -yy=6 -bool"), []string{"xxx", "5", "-yy", "6", "-bool"})
	a.Equal(splitArgs("xxx=5 yy=6 bool="), []string{"xxx", "5", "yy", "6", "bool"})
}

func TestGetAppName(t *testing.T) {
	a := assert.New(t)

	name, err := getAppName("", "./testdir")
	a.NotError(err)
	if runtime.GOOS != "windows" {
		a.True(strings.HasSuffix(name, "testdir"), name)
	} else {
		a.True(strings.HasSuffix(name, "testdir.exe"), name)
	}

	name, err = getAppName("a", "./testdir")
	a.NotError(err)
	if runtime.GOOS != "windows" {
		a.True(strings.HasSuffix(name, "testdir/a"), name)
	} else {
		a.True(strings.HasSuffix(name, "testdir/a.exe"), name)
	}

	name, err = getAppName("a.exe", "./testdir")
	a.NotError(err).
		True(strings.HasSuffix(name, "testdir/a.exe"), name)
}
<commit_msg>修正 windows 测试错误<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package gobuild

import (
	"runtime"
	"strings"
	"testing"

	"github.com/issue9/assert"
)

func TestGetExts(t *testing.T) {
	a := assert.New(t)

	a.Equal(getExts(""), []string{})
	a.Equal(getExts(",, ,"), []string{})
	a.Equal(getExts(",.go, ,.php,"), []string{".go", ".php"})
	a.Equal(getExts(",go,.php,"), []string{".go", ".php"})
	a.Equal(getExts(",go , .php,"), []string{".go", ".php"})
}

func TestRecursivePath(t *testing.T) {
	a := assert.New(t)

	if runtime.GOOS != "windows" {
		paths, err := recursivePaths(false, []string{"./testdir"})
		a.NotError(err).
			Equal(paths, []string{
				"./testdir",
			})

		paths, err = recursivePaths(true, []string{"./testdir"})
		a.NotError(err).Equal(paths, []string{
			"./testdir",
			"testdir/testdir1",
			"testdir/testdir2",
			"testdir/testdir2/testdir3",
		})

		paths, err = recursivePaths(true, []string{"./testdir/testdir1", "./testdir/testdir2"})
		a.NotError(err).
			Equal(paths, []string{
				"./testdir/testdir1",
				"./testdir/testdir2",
				"testdir/testdir2/testdir3",
			})

		paths, err = recursivePaths(true, []string{"./testdir/testdir2"})
		a.NotError(err).Equal(paths, []string{
			"./testdir/testdir2",
			"testdir/testdir2/testdir3",
		})
	} else {
		paths, err := recursivePaths(false, []string{"./testdir"})
		a.NotError(err).
			Equal(paths, []string{
				"./testdir",
			})

		paths, err = recursivePaths(true, []string{"./testdir"})
		a.NotError(err).Equal(paths, []string{
			"./testdir",
			"testdir\\testdir1",
			"testdir\\testdir2",
			"testdir\\testdir2\\testdir3",
		})

		paths, err = recursivePaths(true, []string{"./testdir/testdir1", "./testdir/testdir2"})
		a.NotError(err).
			Equal(paths, []string{
				".\\testdir\\testdir1",
				".\\testdir\\testdir2",
				"testdir\\testdir2\\testdir3",
			})

		paths, err = recursivePaths(true, []string{"./testdir/testdir2"})
		a.NotError(err).Equal(paths, []string{
			".\\testdir\\testdir2",
			"testdir\\testdir2\\testdir3",
		})
	}
}

func TestSplitArgs(t *testing.T) {
	a := assert.New(t)

	a.Equal(splitArgs("x=5 y=6"), []string{"x", "5", "y", "6"})
	a.Equal(splitArgs("xxx=5 -yy=6 -bool"), []string{"xxx", "5", "-yy", "6", "-bool"})
	a.Equal(splitArgs("xxx=5 yy=6 bool="), []string{"xxx", "5", "yy", "6", "bool"})
}

func TestGetAppName(t *testing.T) {
	a := assert.New(t)

	name, err := getAppName("", "./testdir")
	a.NotError(err)
	if runtime.GOOS != "windows" {
		a.True(strings.HasSuffix(name, "testdir"), name)
	} else {
		a.True(strings.HasSuffix(name, "testdir.exe"), name)
	}

	name, err = getAppName("a", "./testdir")
	a.NotError(err)
	if runtime.GOOS != "windows" {
		a.True(strings.HasSuffix(name, "testdir/a"), name)
	} else {
		a.True(strings.HasSuffix(name, "testdir\\a.exe"), name)
	}

	name, err = getAppName("a.exe", "./testdir")
	a.NotError(err).
		True(strings.HasSuffix(name, "testdir\\a.exe"), name)
}
<|endoftext|>


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

package rpc

import (
	"errors"
	"fmt"
	"net"
	"strings"
	"testing"
)

type shutdownCodec struct {
	responded chan int
	closed    bool
}

func (c *shutdownCodec) WriteRequest(*Request, interface{}) error { return nil }
func (c *shutdownCodec) ReadResponseBody(interface{}) error       { return nil }
func (c *shutdownCodec) ReadResponseHeader(*Response) error {
	c.responded <- 1
	return errors.New("shutdownCodec ReadResponseHeader")
}
func (c *shutdownCodec) Close() error {
	c.closed = true
	return nil
}

func TestCloseCodec(t *testing.T) {
	codec := &shutdownCodec{responded: make(chan int)}
	client := NewClientWithCodec(codec)
	<-codec.responded
	client.Close()
	if !codec.closed {
		t.Error("client.Close did not close codec")
	}
}

// Test that errors in gob shut down the connection. Issue 7689.

type R struct {
	msg []byte // Not exported, so R does not work with gob.
}

type S struct{}

func (s *S) Recv(nul *struct{}, reply *R) error {
	*reply = R{[]byte("foo")}
	return nil
}

func TestGobError(t *testing.T) {
	defer func() {
		err := recover()
		if err == nil {
			t.Fatal("no error")
		}
		if !strings.Contains("reading body EOF", err.(error).Error()) {
			t.Fatal("expected `reading body EOF', got", err)
		}
	}()
	Register(new(S))

	listen, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		panic(err)
	}
	go Accept(listen)

	client, err := Dial("tcp", listen.Addr().String())
	if err != nil {
		panic(err)
	}

	var reply Reply
	err = client.Call("S.Recv", &struct{}{}, &reply)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", reply)
	client.Close()

	listen.Close()
}
<commit_msg>net/rpc: fix args order in strings.Contains call<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rpc

import (
	"errors"
	"fmt"
	"net"
	"strings"
	"testing"
)

type shutdownCodec struct {
	responded chan int
	closed    bool
}

func (c *shutdownCodec) WriteRequest(*Request, interface{}) error { return nil }
func (c *shutdownCodec) ReadResponseBody(interface{}) error       { return nil }
func (c *shutdownCodec) ReadResponseHeader(*Response) error {
	c.responded <- 1
	return errors.New("shutdownCodec ReadResponseHeader")
}
func (c *shutdownCodec) Close() error {
	c.closed = true
	return nil
}

func TestCloseCodec(t *testing.T) {
	codec := &shutdownCodec{responded: make(chan int)}
	client := NewClientWithCodec(codec)
	<-codec.responded
	client.Close()
	if !codec.closed {
		t.Error("client.Close did not close codec")
	}
}

// Test that errors in gob shut down the connection. Issue 7689.

type R struct {
	msg []byte // Not exported, so R does not work with gob.
}

type S struct{}

func (s *S) Recv(nul *struct{}, reply *R) error {
	*reply = R{[]byte("foo")}
	return nil
}

func TestGobError(t *testing.T) {
	defer func() {
		err := recover()
		if err == nil {
			t.Fatal("no error")
		}
		if !strings.Contains(err.(error).Error(), "reading body EOF") {
			t.Fatal("expected `reading body EOF', got", err)
		}
	}()
	Register(new(S))

	listen, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		panic(err)
	}
	go Accept(listen)

	client, err := Dial("tcp", listen.Addr().String())
	if err != nil {
		panic(err)
	}

	var reply Reply
	err = client.Call("S.Recv", &struct{}{}, &reply)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", reply)
	client.Close()

	listen.Close()
}
<|endoftext|>


<commit_before>package main

// #include "bridge.h"
import "C"
import "net/http"

//export ListenAndServe
func ListenAndServe(caddr *C.char) {
	addr := C.GoString(caddr)
	http.ListenAndServe(addr, nil)
}

//export HandleFunc
func HandleFunc(cpattern *C.char, cfn *C.FuncPtr) {
}

func main() {}
<commit_msg>Dont need a separate file for typedef<commit_after>package main

// typedef char * FuncPtr();
import "C"
import "net/http"

//export ListenAndServe
func ListenAndServe(caddr *C.char) {
	addr := C.GoString(caddr)
	http.ListenAndServe(addr, nil)
}

//export HandleFunc
func HandleFunc(cpattern *C.char, cfn *C.FuncPtr) {
}

func main() {}
<|endoftext|>


<commit_before>package aws

import (
	"bytes"
	"fmt"
	"log"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/elb"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsLBSSLNegotiationPolicy() *schema.Resource {
	return &schema.Resource{
		// There is no concept of "updating" an LB policy in
		// the AWS API.
		Create: resourceAwsLBSSLNegotiationPolicyCreate,
		Read:   resourceAwsLBSSLNegotiationPolicyRead,
		Delete: resourceAwsLBSSLNegotiationPolicyDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"load_balancer": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"lb_port": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"attribute": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"value": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
				Set: func(v interface{}) int {
					var buf bytes.Buffer
					m := v.(map[string]interface{})
					buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
					return hashcode.String(buf.String())
				},
			},
		},
	}
}

func resourceAwsLBSSLNegotiationPolicyCreate(d *schema.ResourceData, meta interface{}) error {
	elbconn := meta.(*AWSClient).elbconn

	// Provision the SSLNegotiationPolicy
	lbspOpts := &elb.CreateLoadBalancerPolicyInput{
		LoadBalancerName: aws.String(d.Get("load_balancer").(string)),
		PolicyName:       aws.String(d.Get("name").(string)),
		PolicyTypeName:   aws.String("SSLNegotiationPolicyType"),
	}

	// Check for Policy Attributes
	if v, ok := d.GetOk("attribute"); ok {
		// Expand the "attribute" set to aws-sdk-go compat []*elb.PolicyAttribute
		lbspOpts.PolicyAttributes = expandPolicyAttributes(v.(*schema.Set).List())
	}

	log.Printf("[DEBUG] Load Balancer Policy opts: %#v", lbspOpts)
	if _, err := elbconn.CreateLoadBalancerPolicy(lbspOpts); err != nil {
		return fmt.Errorf("Error creating Load Balancer Policy: %s", err)
	}

	setLoadBalancerOpts := &elb.SetLoadBalancerPoliciesOfListenerInput{
		LoadBalancerName: aws.String(d.Get("load_balancer").(string)),
		LoadBalancerPort: aws.Int64(int64(d.Get("lb_port").(int))),
		PolicyNames:      []*string{aws.String(d.Get("name").(string))},
	}

	log.Printf("[DEBUG] SSL Negotiation create configuration: %#v", setLoadBalancerOpts)
	if _, err := elbconn.SetLoadBalancerPoliciesOfListener(setLoadBalancerOpts); err != nil {
		return fmt.Errorf("Error setting SSLNegotiationPolicy: %s", err)
	}

	d.SetId(fmt.Sprintf("%s:%d:%s",
		*lbspOpts.LoadBalancerName,
		*setLoadBalancerOpts.LoadBalancerPort,
		*lbspOpts.PolicyName))
	return nil
}

func resourceAwsLBSSLNegotiationPolicyRead(d *schema.ResourceData, meta interface{}) error {
	elbconn := meta.(*AWSClient).elbconn

	lbName, lbPort, policyName := resourceAwsLBSSLNegotiationPolicyParseId(d.Id())

	request := &elb.DescribeLoadBalancerPoliciesInput{
		LoadBalancerName: aws.String(lbName),
		PolicyNames:      []*string{aws.String(policyName)},
	}

	getResp, err := elbconn.DescribeLoadBalancerPolicies(request)
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "PolicyNotFound" {
			// The policy is gone.
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error retrieving policy: %s", err)
	}

	if len(getResp.PolicyDescriptions) != 1 {
		return fmt.Errorf("Unable to find policy %#v", getResp.PolicyDescriptions)
	}

	// We can get away with this because there's only one policy returned
	policyDesc := getResp.PolicyDescriptions[0]
	attributes := flattenPolicyAttributes(policyDesc.PolicyAttributeDescriptions)
	d.Set("attributes", attributes)

	d.Set("name", policyName)
	d.Set("load_balancer", lbName)
	d.Set("lb_port", lbPort)

	return nil
}

func resourceAwsLBSSLNegotiationPolicyDelete(d *schema.ResourceData, meta interface{}) error {
	elbconn := meta.(*AWSClient).elbconn

	lbName, _, policyName := resourceAwsLBSSLNegotiationPolicyParseId(d.Id())

	// Perversely, if we Set an empty list of PolicyNames, we detach the
	// policies attached to a listener, which is required to delete the
	// policy itself.
	setLoadBalancerOpts := &elb.SetLoadBalancerPoliciesOfListenerInput{
		LoadBalancerName: aws.String(d.Get("load_balancer").(string)),
		LoadBalancerPort: aws.Int64(int64(d.Get("lb_port").(int))),
		PolicyNames:      []*string{},
	}

	if _, err := elbconn.SetLoadBalancerPoliciesOfListener(setLoadBalancerOpts); err != nil {
		return fmt.Errorf("Error removing SSLNegotiationPolicy: %s", err)
	}

	request := &elb.DeleteLoadBalancerPolicyInput{
		LoadBalancerName: aws.String(lbName),
		PolicyName:       aws.String(policyName),
	}

	if _, err := elbconn.DeleteLoadBalancerPolicy(request); err != nil {
		return fmt.Errorf("Error deleting SSL negotiation policy %s: %s", d.Id(), err)
	}
	return nil
}

// resourceAwsLBSSLNegotiationPolicyParseId takes an ID and parses it into
// it's constituent parts. You need three axes (LB name, policy name, and LB
// port) to create or identify an SSL negotiation policy in AWS's API.
func resourceAwsLBSSLNegotiationPolicyParseId(id string) (string, string, string) {
	parts := strings.SplitN(id, ":", 3)
	return parts[0], parts[1], parts[2]
}
<commit_msg>Changed `attribute` argument to be optional.<commit_after>package aws

import (
	"bytes"
	"fmt"
	"log"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/elb"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsLBSSLNegotiationPolicy() *schema.Resource {
	return &schema.Resource{
		// There is no concept of "updating" an LB policy in
		// the AWS API.
		Create: resourceAwsLBSSLNegotiationPolicyCreate,
		Read:   resourceAwsLBSSLNegotiationPolicyRead,
		Delete: resourceAwsLBSSLNegotiationPolicyDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"load_balancer": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"lb_port": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"attribute": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"value": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
				Set: func(v interface{}) int {
					var buf bytes.Buffer
					m := v.(map[string]interface{})
					buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
					return hashcode.String(buf.String())
				},
			},
		},
	}
}

func resourceAwsLBSSLNegotiationPolicyCreate(d *schema.ResourceData, meta interface{}) error {
	elbconn := meta.(*AWSClient).elbconn

	// Provision the SSLNegotiationPolicy
	lbspOpts := &elb.CreateLoadBalancerPolicyInput{
		LoadBalancerName: aws.String(d.Get("load_balancer").(string)),
		PolicyName:       aws.String(d.Get("name").(string)),
		PolicyTypeName:   aws.String("SSLNegotiationPolicyType"),
	}

	// Check for Policy Attributes
	if v, ok := d.GetOk("attribute"); ok {
		// Expand the "attribute" set to aws-sdk-go compat []*elb.PolicyAttribute
		lbspOpts.PolicyAttributes = expandPolicyAttributes(v.(*schema.Set).List())
	}

	log.Printf("[DEBUG] Load Balancer Policy opts: %#v", lbspOpts)
	if _, err := elbconn.CreateLoadBalancerPolicy(lbspOpts); err != nil {
		return fmt.Errorf("Error creating Load Balancer Policy: %s", err)
	}

	setLoadBalancerOpts := &elb.SetLoadBalancerPoliciesOfListenerInput{
		LoadBalancerName: aws.String(d.Get("load_balancer").(string)),
		LoadBalancerPort: aws.Int64(int64(d.Get("lb_port").(int))),
		PolicyNames:      []*string{aws.String(d.Get("name").(string))},
	}

	log.Printf("[DEBUG] SSL Negotiation create configuration: %#v", setLoadBalancerOpts)
	if _, err := elbconn.SetLoadBalancerPoliciesOfListener(setLoadBalancerOpts); err != nil {
		return fmt.Errorf("Error setting SSLNegotiationPolicy: %s", err)
	}

	d.SetId(fmt.Sprintf("%s:%d:%s",
		*lbspOpts.LoadBalancerName,
		*setLoadBalancerOpts.LoadBalancerPort,
		*lbspOpts.PolicyName))
	return nil
}

func resourceAwsLBSSLNegotiationPolicyRead(d *schema.ResourceData, meta interface{}) error {
	elbconn := meta.(*AWSClient).elbconn

	lbName, lbPort, policyName := resourceAwsLBSSLNegotiationPolicyParseId(d.Id())

	request := &elb.DescribeLoadBalancerPoliciesInput{
		LoadBalancerName: aws.String(lbName),
		PolicyNames:      []*string{aws.String(policyName)},
	}

	getResp, err := elbconn.DescribeLoadBalancerPolicies(request)
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "PolicyNotFound" {
			// The policy is gone.
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error retrieving policy: %s", err)
	}

	if len(getResp.PolicyDescriptions) != 1 {
		return fmt.Errorf("Unable to find policy %#v", getResp.PolicyDescriptions)
	}

	// We can get away with this because there's only one policy returned
	policyDesc := getResp.PolicyDescriptions[0]
	attributes := flattenPolicyAttributes(policyDesc.PolicyAttributeDescriptions)
	d.Set("attributes", attributes)

	d.Set("name", policyName)
	d.Set("load_balancer", lbName)
	d.Set("lb_port", lbPort)

	return nil
}

func resourceAwsLBSSLNegotiationPolicyDelete(d *schema.ResourceData, meta interface{}) error {
	elbconn := meta.(*AWSClient).elbconn

	lbName, _, policyName := resourceAwsLBSSLNegotiationPolicyParseId(d.Id())

	// Perversely, if we Set an empty list of PolicyNames, we detach the
	// policies attached to a listener, which is required to delete the
	// policy itself.
	setLoadBalancerOpts := &elb.SetLoadBalancerPoliciesOfListenerInput{
		LoadBalancerName: aws.String(d.Get("load_balancer").(string)),
		LoadBalancerPort: aws.Int64(int64(d.Get("lb_port").(int))),
		PolicyNames:      []*string{},
	}

	if _, err := elbconn.SetLoadBalancerPoliciesOfListener(setLoadBalancerOpts); err != nil {
		return fmt.Errorf("Error removing SSLNegotiationPolicy: %s", err)
	}

	request := &elb.DeleteLoadBalancerPolicyInput{
		LoadBalancerName: aws.String(lbName),
		PolicyName:       aws.String(policyName),
	}

	if _, err := elbconn.DeleteLoadBalancerPolicy(request); err != nil {
		return fmt.Errorf("Error deleting SSL negotiation policy %s: %s", d.Id(), err)
	}
	return nil
}

// resourceAwsLBSSLNegotiationPolicyParseId takes an ID and parses it into
// it's constituent parts. You need three axes (LB name, policy name, and LB
// port) to create or identify an SSL negotiation policy in AWS's API.
func resourceAwsLBSSLNegotiationPolicyParseId(id string) (string, string, string) {
	parts := strings.SplitN(id, ":", 3)
	return parts[0], parts[1], parts[2]
}
<|endoftext|>


<commit_before>package openstack

import (
	"bytes"
	"fmt"
	"log"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/racker/perigee"
	"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
)

func resourceComputeSecGroupV2() *schema.Resource {
	return &schema.Resource{
		Create: resourceComputeSecGroupV2Create,
		Read:   resourceComputeSecGroupV2Read,
		Update: resourceComputeSecGroupV2Update,
		Delete: resourceComputeSecGroupV2Delete,

		Schema: map[string]*schema.Schema{
			"region": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				DefaultFunc: envDefaultFunc("OS_REGION_NAME"),
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},
			"description": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},
			"rule": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"id": &schema.Schema{
							Type:     schema.TypeString,
							Computed: true,
						},
						"from_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
							ForceNew: false,
						},
						"to_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
							ForceNew: false,
						},
						"ip_protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: false,
						},
						"cidr": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: false,
						},
						"from_group_id": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: false,
						},
					},
				},
			},
		},
	}
}

func resourceComputeSecGroupV2Create(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	createOpts := secgroups.CreateOpts{
		Name:        d.Get("name").(string),
		Description: d.Get("description").(string),
	}

	sg, err := secgroups.Create(computeClient, createOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error creating OpenStack security group: %s", err)
	}

	d.SetId(sg.ID)

	createRuleOptsList := resourceSecGroupRulesV2(d)
	for _, createRuleOpts := range createRuleOptsList {
		_, err := secgroups.CreateRule(computeClient, createRuleOpts).Extract()
		if err != nil {
			return fmt.Errorf("Error creating OpenStack security group rule: %s", err)
		}
	}

	return resourceComputeSecGroupV2Read(d, meta)
}

func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	sg, err := secgroups.Get(computeClient, d.Id()).Extract()
	if err != nil {
		return CheckDeleted(d, err, "security group")
	}

	d.Set("region", d.Get("region").(string))
	d.Set("name", sg.Name)
	d.Set("description", sg.Description)
	log.Printf("[DEBUG] rulesToMap(sg.Rules): %+v", rulesToMap(sg.Rules))
	d.Set("rule", rulesToMap(sg.Rules))

	return nil
}

func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	updateOpts := secgroups.UpdateOpts{
		Name:        d.Get("name").(string),
		Description: d.Get("description").(string),
	}

	log.Printf("[DEBUG] Updating Security Group (%s) with options: %+v", d.Id(), updateOpts)

	_, err = secgroups.Update(computeClient, d.Id(), updateOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error updating OpenStack security group (%s): %s", d.Id(), err)
	}

	if d.HasChange("rule") {
		oldSGRaw, newSGRaw := d.GetChange("rule")
		oldSGRSlice, newSGRSlice := oldSGRaw.([]interface{}), newSGRaw.([]interface{})
		oldSGRSet := schema.NewSet(secgroupRuleV2Hash, oldSGRSlice)
		newSGRSet := schema.NewSet(secgroupRuleV2Hash, newSGRSlice)
		secgrouprulesToAdd := newSGRSet.Difference(oldSGRSet)
		secgrouprulesToRemove := oldSGRSet.Difference(newSGRSet)

		log.Printf("[DEBUG] Security group rules to add: %v", secgrouprulesToAdd)

		log.Printf("[DEBUG] Security groups rules to remove: %v", secgrouprulesToRemove)

		for _, rawRule := range secgrouprulesToAdd.List() {
			createRuleOpts := resourceSecGroupRuleCreateOptsV2(d, rawRule)
			rule, err := secgroups.CreateRule(computeClient, createRuleOpts).Extract()
			if err != nil {
				return fmt.Errorf("Error adding rule to OpenStack security group (%s): %s", d.Id(), err)
			}
			log.Printf("[DEBUG] Added rule (%s) to OpenStack security group (%s) ", rule.ID, d.Id())
		}

		for _, r := range secgrouprulesToRemove.List() {
			rule := resourceSecGroupRuleV2(d, r)
			err := secgroups.DeleteRule(computeClient, rule.ID).ExtractErr()
			if err != nil {
				errCode, ok := err.(*perigee.UnexpectedResponseCodeError)
				if !ok {
					return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err)
				}
				if errCode.Actual == 404 {
					continue
				} else {
					return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s)", rule.ID, d.Id())
				}
			} else {
				log.Printf("[DEBUG] Removed rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err)
			}
		}
	}

	return resourceComputeSecGroupV2Read(d, meta)
}

func resourceComputeSecGroupV2Delete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	err = secgroups.Delete(computeClient, d.Id()).ExtractErr()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack security group: %s", err)
	}
	d.SetId("")
	return nil
}

func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts {
	rawRules := (d.Get("rule")).([]interface{})
	createRuleOptsList := make([]secgroups.CreateRuleOpts, len(rawRules))
	for i, raw := range rawRules {
		rawMap := raw.(map[string]interface{})
		createRuleOptsList[i] = secgroups.CreateRuleOpts{
			ParentGroupID: d.Id(),
			FromPort:      rawMap["from_port"].(int),
			ToPort:        rawMap["to_port"].(int),
			IPProtocol:    rawMap["ip_protocol"].(string),
			CIDR:          rawMap["cidr"].(string),
			FromGroupID:   rawMap["from_group_id"].(string),
		}
	}
	return createRuleOptsList
}

func resourceSecGroupRuleCreateOptsV2(d *schema.ResourceData, raw interface{}) secgroups.CreateRuleOpts {
	rawMap := raw.(map[string]interface{})
	return secgroups.CreateRuleOpts{
		ParentGroupID: d.Id(),
		FromPort:      rawMap["from_port"].(int),
		ToPort:        rawMap["to_port"].(int),
		IPProtocol:    rawMap["ip_protocol"].(string),
		CIDR:          rawMap["cidr"].(string),
		FromGroupID:   rawMap["from_group_id"].(string),
	}
}

func resourceSecGroupRuleV2(d *schema.ResourceData, raw interface{}) secgroups.Rule {
	rawMap := raw.(map[string]interface{})
	return secgroups.Rule{
		ID:            rawMap["id"].(string),
		ParentGroupID: d.Id(),
		FromPort:      rawMap["from_port"].(int),
		ToPort:        rawMap["to_port"].(int),
		IPProtocol:    rawMap["ip_protocol"].(string),
		IPRange:       secgroups.IPRange{CIDR: rawMap["cidr"].(string)},
	}
}

func rulesToMap(sgrs []secgroups.Rule) []map[string]interface{} {
	sgrMap := make([]map[string]interface{}, len(sgrs))
	for i, sgr := range sgrs {
		sgrMap[i] = map[string]interface{}{
			"id":          sgr.ID,
			"from_port":   sgr.FromPort,
			"to_port":     sgr.ToPort,
			"ip_protocol": sgr.IPProtocol,
			"cidr":        sgr.IPRange.CIDR,
		}
	}
	return sgrMap
}

func secgroupRuleV2Hash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int)))
	buf.WriteString(fmt.Sprintf("%s-", m["ip_protocol"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["cidr"].(string)))

	return hashcode.String(buf.String())
}
<commit_msg>Added self option to security groups<commit_after>package openstack

import (
	"bytes"
	"fmt"
	"log"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/racker/perigee"
	"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
)

func resourceComputeSecGroupV2() *schema.Resource {
	return &schema.Resource{
		Create: resourceComputeSecGroupV2Create,
		Read:   resourceComputeSecGroupV2Read,
		Update: resourceComputeSecGroupV2Update,
		Delete: resourceComputeSecGroupV2Delete,

		Schema: map[string]*schema.Schema{
			"region": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				DefaultFunc: envDefaultFunc("OS_REGION_NAME"),
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},
			"description": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},
			"rule": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"id": &schema.Schema{
							Type:     schema.TypeString,
							Computed: true,
						},
						"from_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
							ForceNew: false,
						},
						"to_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
							ForceNew: false,
						},
						"ip_protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: false,
						},
						"cidr": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: false,
						},
						"from_group_id": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: false,
						},
						"self": &schema.Schema{
							Type:     schema.TypeBool,
							Optional: true,
							ForceNew: false,
						},
					},
				},
			},
		},
	}
}

func resourceComputeSecGroupV2Create(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	createOpts := secgroups.CreateOpts{
		Name:        d.Get("name").(string),
		Description: d.Get("description").(string),
	}

	sg, err := secgroups.Create(computeClient, createOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error creating OpenStack security group: %s", err)
	}

	d.SetId(sg.ID)

	createRuleOptsList := resourceSecGroupRulesV2(d)
	for _, createRuleOpts := range createRuleOptsList {
		_, err := secgroups.CreateRule(computeClient, createRuleOpts).Extract()
		if err != nil {
			return fmt.Errorf("Error creating OpenStack security group rule: %s", err)
		}
	}

	return resourceComputeSecGroupV2Read(d, meta)
}

func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	sg, err := secgroups.Get(computeClient, d.Id()).Extract()
	if err != nil {
		return CheckDeleted(d, err, "security group")
	}

	d.Set("region", d.Get("region").(string))
	d.Set("name", sg.Name)
	d.Set("description", sg.Description)
	log.Printf("[DEBUG] rulesToMap(sg.Rules): %+v", rulesToMap(sg.Rules))
	d.Set("rule", rulesToMap(sg.Rules))

	return nil
}

func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	updateOpts := secgroups.UpdateOpts{
		Name:        d.Get("name").(string),
		Description: d.Get("description").(string),
	}

	log.Printf("[DEBUG] Updating Security Group (%s) with options: %+v", d.Id(), updateOpts)

	_, err = secgroups.Update(computeClient, d.Id(), updateOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error updating OpenStack security group (%s): %s", d.Id(), err)
	}

	if d.HasChange("rule") {
		oldSGRaw, newSGRaw := d.GetChange("rule")
		oldSGRSlice, newSGRSlice := oldSGRaw.([]interface{}), newSGRaw.([]interface{})
		oldSGRSet := schema.NewSet(secgroupRuleV2Hash, oldSGRSlice)
		newSGRSet := schema.NewSet(secgroupRuleV2Hash, newSGRSlice)
		secgrouprulesToAdd := newSGRSet.Difference(oldSGRSet)
		secgrouprulesToRemove := oldSGRSet.Difference(newSGRSet)

		log.Printf("[DEBUG] Security group rules to add: %v", secgrouprulesToAdd)

		log.Printf("[DEBUG] Security groups rules to remove: %v", secgrouprulesToRemove)

		for _, rawRule := range secgrouprulesToAdd.List() {
			createRuleOpts := resourceSecGroupRuleCreateOptsV2(d, rawRule)
			rule, err := secgroups.CreateRule(computeClient, createRuleOpts).Extract()
			if err != nil {
				return fmt.Errorf("Error adding rule to OpenStack security group (%s): %s", d.Id(), err)
			}
			log.Printf("[DEBUG] Added rule (%s) to OpenStack security group (%s) ", rule.ID, d.Id())
		}

		for _, r := range secgrouprulesToRemove.List() {
			rule := resourceSecGroupRuleV2(d, r)
			err := secgroups.DeleteRule(computeClient, rule.ID).ExtractErr()
			if err != nil {
				errCode, ok := err.(*perigee.UnexpectedResponseCodeError)
				if !ok {
					return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err)
				}
				if errCode.Actual == 404 {
					continue
				} else {
					return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s)", rule.ID, d.Id())
				}
			} else {
				log.Printf("[DEBUG] Removed rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err)
			}
		}
	}

	return resourceComputeSecGroupV2Read(d, meta)
}

func resourceComputeSecGroupV2Delete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	err = secgroups.Delete(computeClient, d.Id()).ExtractErr()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack security group: %s", err)
	}
	d.SetId("")
	return nil
}

func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts {
	rawRules := (d.Get("rule")).([]interface{})
	createRuleOptsList := make([]secgroups.CreateRuleOpts, len(rawRules))
	for i, raw := range rawRules {
		rawMap := raw.(map[string]interface{})
		groupId := rawMap["from_group_id"].(string)
		if rawMap["self"].(bool) {
			groupId = d.Id()
		}
		createRuleOptsList[i] = secgroups.CreateRuleOpts{
			ParentGroupID: d.Id(),
			FromPort:      rawMap["from_port"].(int),
			ToPort:        rawMap["to_port"].(int),
			IPProtocol:    rawMap["ip_protocol"].(string),
			CIDR:          rawMap["cidr"].(string),
			FromGroupID:   groupId,
		}
	}
	return createRuleOptsList
}

func resourceSecGroupRuleCreateOptsV2(d *schema.ResourceData, raw interface{}) secgroups.CreateRuleOpts {
	rawMap := raw.(map[string]interface{})
	groupId := rawMap["from_group_id"].(string)
	if rawMap["self"].(bool) {
		groupId = d.Id()
	}
	return secgroups.CreateRuleOpts{
		ParentGroupID: d.Id(),
		FromPort:      rawMap["from_port"].(int),
		ToPort:        rawMap["to_port"].(int),
		IPProtocol:    rawMap["ip_protocol"].(string),
		CIDR:          rawMap["cidr"].(string),
		FromGroupID:   groupId,
	}
}

func resourceSecGroupRuleV2(d *schema.ResourceData, raw interface{}) secgroups.Rule {
	rawMap := raw.(map[string]interface{})
	return secgroups.Rule{
		ID:            rawMap["id"].(string),
		ParentGroupID: d.Id(),
		FromPort:      rawMap["from_port"].(int),
		ToPort:        rawMap["to_port"].(int),
		IPProtocol:    rawMap["ip_protocol"].(string),
		IPRange:       secgroups.IPRange{CIDR: rawMap["cidr"].(string)},
	}
}

func rulesToMap(sgrs []secgroups.Rule) []map[string]interface{} {
	sgrMap := make([]map[string]interface{}, len(sgrs))
	for i, sgr := range sgrs {
		sgrMap[i] = map[string]interface{}{
			"id":          sgr.ID,
			"from_port":   sgr.FromPort,
			"to_port":     sgr.ToPort,
			"ip_protocol": sgr.IPProtocol,
			"cidr":        sgr.IPRange.CIDR,
		}
	}
	return sgrMap
}

func secgroupRuleV2Hash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int)))
	buf.WriteString(fmt.Sprintf("%s-", m["ip_protocol"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["cidr"].(string)))

	return hashcode.String(buf.String())
}
<|endoftext|>