<commit_before>package main

import (
	"bufio"
	"bytes"
	"io"
	"strconv"
	"strings"
)

type token string

func tokenize(ior io.Reader, c chan<- token) {
	// Tokenizer states
	const (
		READY = iota
		READING
		STRLIT
	)

	// Single-rune tokens
	const TOKS = "()"
	const WS = " \t\n"
	const SPLIT = TOKS + WS

	r := bufio.NewReader(ior)

	state := READY
	var tmp bytes.Buffer

	ch, _, err := r.ReadRune()
	for err == nil {
		switch state {
		case READY:
			// c either begins or is a token
			if strings.ContainsRune(TOKS, ch) {
				c <- token(ch)
			} else if strings.ContainsRune(WS, ch) {
				// whitespace; ignore it
			} else if ch == '"' {
				tmp.WriteRune(ch)
				state = STRLIT
			} else {
				tmp.WriteRune(ch)
				state = READING
			}
		case READING:
			if strings.ContainsRune(SPLIT, ch) {
				// the current token is done
				c <- token(tmp.String())
				tmp.Reset()
				state = READY
				r.UnreadRune()
			} else {
				tmp.WriteRune(ch)
			}
		case STRLIT:
			tmp.WriteRune(ch)
			if ch == '"' {
				c <- token(tmp.String())
				tmp.Reset()
				state = READY
			}
		default:
			panic("Invalid state")
		}
		ch, _, err = r.ReadRune()
	}

	close(c)
	if err != nil && err != io.EOF {
		panic(err)
	}
}

type sexpr interface{}
type atom interface{}
type sym string

type cons struct {
	car sexpr
	cdr sexpr
}

var Nil = interface{}(nil)

// hard tokens
const (
	_LPAREN = "("
	_RPAREN = ")"
)

func parse(tc <-chan token, sc chan<- sexpr) {
	for tok := range tc {
		sc <- parseNext(tok, tc)
	}
	close(sc)
}

func parseNext(tok token, tc <-chan token) sexpr {
	switch tok {
	case _LPAREN:
		return parseCons(tc)
	case _RPAREN:
		panic("Unmatched ')'")
	}
	return parseAtom(tok)
}

func parseCons(tc <-chan token) sexpr {
	// note that we assume the LPAREN has already been read
	tok := <-tc
	if tok == _RPAREN {
		// nil atom
		return Nil
	}
	car := parseNext(tok, tc)
	cdr := parseCons(tc)
	return cons{car, cdr}
}

func parseAtom(tok token) (e sexpr) {
	e = sym(tok)

	// try as string literal
	if tok[0] == '"' {
		e = string(tok[1 : len(tok)-1])
	}

	// try as number
	n, err := strconv.ParseFloat(string(tok), 64)
	if err == nil {
		e = n
	}
	return
}
<commit_msg>Comments<commit_after>package main

import (
	"bufio"
	"bytes"
	"io"
	"strconv"
	"strings"
)

type token string

func tokenize(ior io.Reader, c chan<- token) {
	// Tokenizer states
	const (
		READY = iota
		READING
		STRLIT
		COMMENT
	)

	// Single-rune tokens
	const TOKS = "()"
	const WS = " \t\n"
	const SPLIT = TOKS + WS + ";"

	r := bufio.NewReader(ior)

	state := READY
	var tmp bytes.Buffer

	ch, _, err := r.ReadRune()
	for err == nil {
		switch state {
		case READY:
			// c either begins or is a token
			if strings.ContainsRune(TOKS, ch) {
				c <- token(ch)
			} else if strings.ContainsRune(WS, ch) {
				// whitespace; ignore it
			} else if ch == ';' {
				// read to EOL
				state = COMMENT
			} else if ch == '"' {
				tmp.WriteRune(ch)
				state = STRLIT
			} else {
				tmp.WriteRune(ch)
				state = READING
			}
		case READING:
			if strings.ContainsRune(SPLIT, ch) {
				// the current token is done
				c <- token(tmp.String())
				tmp.Reset()
				state = READY
				r.UnreadRune()
			} else {
				tmp.WriteRune(ch)
			}
		case STRLIT:
			tmp.WriteRune(ch)
			if ch == '"' {
				c <- token(tmp.String())
				tmp.Reset()
				state = READY
			}
		case COMMENT:
			if ch == '\n' {
				state = READY
			}
		default:
			panic("Invalid state")
		}
		ch, _, err = r.ReadRune()
	}

	close(c)
	if err != nil && err != io.EOF {
		panic(err)
	}
}

type sexpr interface{}
type atom interface{}
type sym string

type cons struct {
	car sexpr
	cdr sexpr
}

var Nil = interface{}(nil)

// hard tokens
const (
	_LPAREN = "("
	_RPAREN = ")"
)

func parse(tc <-chan token, sc chan<- sexpr) {
	for tok := range tc {
		sc <- parseNext(tok, tc)
	}
	close(sc)
}

func parseNext(tok token, tc <-chan token) sexpr {
	switch tok {
	case _LPAREN:
		return parseCons(tc)
	case _RPAREN:
		panic("Unmatched ')'")
	}
	return parseAtom(tok)
}

func parseCons(tc <-chan token) sexpr {
	// note that we assume the LPAREN has already been read
	tok := <-tc
	if tok == _RPAREN {
		// nil atom
		return Nil
	}
	car := parseNext(tok, tc)
	cdr := parseCons(tc)
	return cons{car, cdr}
}

func parseAtom(tok token) (e sexpr) {
	e = sym(tok)

	// try as string literal
	if tok[0] == '"' {
		e = string(tok[1 : len(tok)-1])
	}

	// try as number
	n, err := strconv.ParseFloat(string(tok), 64)
	if err == nil {
		e = n
	}
	return
}
<|endoftext|>


<commit_before>package carton

import (
	"bytes"
	log "github.com/Sirupsen/logrus"
	"github.com/megamsys/libgo/cmd"
	"github.com/megamsys/vertice/provision"
	"io"
	"time"
)

type DestroyOpts struct {
	B *provision.Box
}

// ChangeState runs a state increment of a machine or a container.
func Destroy(opts *DestroyOpts) error {
	var outBuffer bytes.Buffer
	start := time.Now()
	logWriter := LogWriter{Box: opts.B}
	logWriter.Async()
	defer logWriter.Close()
	writer := io.MultiWriter(&outBuffer, &logWriter)
	err := ProvisionerMap[opts.B.Provider].Destroy(opts.B, writer)
	elapsed := time.Since(start)
	// saveErr := saveDestroyedData(opts, outBuffer.String(), elapsed, err)
	// if saveErr != nil {
	// 	log.Errorf("WARNING: couldn't save destroyed data, destroy opts: %#v", opts)
	// }
	if err != nil {
		return err
	}
	return nil
}

func saveDestroyedData(opts *DestroyOpts, slog string, duration time.Duration, destroyError error) error {
	log.Debugf("%s in (%s)\n%s",
		cmd.Colorfy(opts.B.GetFullName(), "cyan", "", "bold"),
		cmd.Colorfy(duration.String(), "green", "", "bold"),
		cmd.Colorfy(slog, "yellow", "", ""))
	if destroyError == nil {
		markDeploysAsRemoved(opts)
	}
	return nil
}

func markDeploysAsRemoved(opts *DestroyOpts) {
	removedAssemblys := make([]string, 1)

	if _, err := NewAssembly(opts.B.CartonId,opts.B.AccountId,opts.B.OrgId); err == nil {
		removedAssemblys[0] = opts.B.CartonId
	}

	if opts.B.Level == provision.BoxSome {
		if comp, err := NewComponent(opts.B.Id,opts.B.AccountId,opts.B.OrgId); err == nil {
			comp.Delete(opts.B.AccountId,opts.B.OrgId)
		}
	}

	if asms, err := Get(opts.B.CartonsId, opts.B.AccountId); err == nil {
		asms.Delete(opts.B.CartonsId, opts.B.AccountId, removedAssemblys)
	}

}
<commit_msg>print duration after delete<commit_after>package carton

import (
	"bytes"
	log "github.com/Sirupsen/logrus"
	"github.com/megamsys/libgo/cmd"
	"github.com/megamsys/vertice/provision"
	"io"
	"time"
)

type DestroyOpts struct {
	B *provision.Box
}

// ChangeState runs a state increment of a machine or a container.
func Destroy(opts *DestroyOpts) error {
	var outBuffer bytes.Buffer
	start := time.Now()
	logWriter := LogWriter{Box: opts.B}
	logWriter.Async()
	defer logWriter.Close()
	writer := io.MultiWriter(&outBuffer, &logWriter)
	err := ProvisionerMap[opts.B.Provider].Destroy(opts.B, writer)
	elapsed := time.Since(start)
	log.Debugf("%s in (%s)\n%s",
		cmd.Colorfy(opts.B.GetFullName(), "cyan", "", "bold"),
		cmd.Colorfy(elapsed.String(), "green", "", "bold"),
		cmd.Colorfy(outBuffer.String(), "yellow", "", ""))
	// saveErr := saveDestroyedData(opts, outBuffer.String(), elapsed, err)
	// if saveErr != nil {
	// 	log.Errorf("WARNING: couldn't save destroyed data, destroy opts: %#v", opts)
	// }
	if err != nil {
		return err
	}
	return nil
}

func saveDestroyedData(opts *DestroyOpts, slog string, duration time.Duration, destroyError error) error {
	log.Debugf("%s in (%s)\n%s",
		cmd.Colorfy(opts.B.GetFullName(), "cyan", "", "bold"),
		cmd.Colorfy(duration.String(), "green", "", "bold"),
		cmd.Colorfy(slog, "yellow", "", ""))
	if destroyError == nil {
		markDeploysAsRemoved(opts)
	}
	return nil
}

func markDeploysAsRemoved(opts *DestroyOpts) {
	removedAssemblys := make([]string, 1)

	if _, err := NewAssembly(opts.B.CartonId,opts.B.AccountId,opts.B.OrgId); err == nil {
		removedAssemblys[0] = opts.B.CartonId
	}

	if opts.B.Level == provision.BoxSome {
		if comp, err := NewComponent(opts.B.Id,opts.B.AccountId,opts.B.OrgId); err == nil {
			comp.Delete(opts.B.AccountId,opts.B.OrgId)
		}
	}

	if asms, err := Get(opts.B.CartonsId, opts.B.AccountId); err == nil {
		asms.Delete(opts.B.CartonsId, opts.B.AccountId, removedAssemblys)
	}

}
<|endoftext|>


<commit_before>package walnut

import (
	"fmt"
	"strings"
)

const whitespace = " \t\n\v\f\r\u0085\u00A0"

// Outlines a "key = value" assignment.
type assignment struct {
	key, value string
	line       int
}

// Provides information about an indentation syntax error.
type indentError struct {
	error string
	line  int
}

// Returns a description of the error.
func (e indentError) Error() string {
	return e.error
}

// Generates a map of resolved keys and raw string values from a byte slice.
// Returns an error if the configuration source is not properly indented.
func parse(buf []byte) ([]assignment, *indentError) {
	lines := strings.Split(string(buf), "\n")
	raw := make([]assignment, 0)

	// collapse lines without any content
	for i, line := range lines {
		lines[i] = collapse(line)
	}

	parents := make([]string, 0)
	indents := make([]string, 0)

	for n, line := range lines {
		if line == "" {
			continue
		}

		k := key(line)
		i := indentation(line)
		d := depth(indents, i)

		// check for invalid indentation
		if d == -1 {
			e := fmt.Sprintf("invalid indentation on line %d", n)
			return nil, &indentError{e, n}
		}

		// trim now redundant levels
		if d < len(indents) {
			parents = parents[:d]
			indents = indents[:d]
		}

		// if the line contains an assignment, record the the value
		if strings.ContainsRune(line, '=') {
			raw = append(raw, assignment{
				key:   strings.Join(append(parents, k), "."),
				value: value(line),
				line:  n,
			})

			continue
		}

		// push the key and indentation onto their respective stacks
		parents = append(parents, k)
		indents = append(indents, i)
	}

	return raw, nil
}

// Trims trailing whitespace or, in the case of comment lines, returns
// an empty string.
func collapse(input string) string {
	s := strings.TrimRight(input, whitespace)

	for _, r := range s {
		if strings.ContainsRune(whitespace, r) {
			continue
		}

		// comment detected, blank this line
		if r == '#' {
			break
		}

		// if the first non-whitespace character @todo
		return input
	}

	return ""
}

// Returns the "key" component from a "key = value" string.
func key(input string) string {
	if eq := strings.IndexRune(input, '='); eq != -1 {
		input = input[:eq]
	}

	return strings.Trim(input, whitespace)
}

// Returns the "value" component from a "key = value" string.
func value(input string) string {
	if eq := strings.IndexRune(input, '='); eq != -1 {
		input = input[eq+1:]
	}

	return strings.Trim(input, whitespace)
}

// Returns the string's whitespace prefix.
func indentation(input string) string {
	end := strings.IndexFunc(input, func(r rune) bool {
		return strings.IndexRune(whitespace, r) == -1
	})

	if end == -1 {
		return ""
	}

	return input[:end]
}

// Given a list of previous indentation levels, finds the provided indentation
// level's depth value. A depth of 0 represents the lowest possible level of
// indentation.
// Returns -1 on errors caused by illegal indentation.
func depth(parents []string, current string) int {
	if current == "" {
		return 0
	}

	// the base indentation level must be an empty string
	if len(parents) == 0 {
		return -1
	}

	for i, prefix := range parents {
		switch {
		case current == prefix:
			return i
		case !strings.HasPrefix(current, prefix):
			return -1
		}
	}

	// if we get this far, the current line is further indented
	// than its parent
	return len(parents)
}
<commit_msg>Rename the 'assignment' struct to 'definition'<commit_after>package walnut

import (
	"fmt"
	"strings"
)

const whitespace = " \t\n\v\f\r\u0085\u00A0"

// Outlines a "key = value" assignment.
type definition struct {
	key, value string
	line       int
}

// Provides information about an indentation syntax error.
type indentError struct {
	error string
	line  int
}

// Returns a description of the error.
func (e indentError) Error() string {
	return e.error
}

// Generates a map of resolved keys and raw string values from a byte slice.
// Returns an error if the configuration source is not properly indented.
func parse(buf []byte) ([]definition, *indentError) {
	lines := strings.Split(string(buf), "\n")
	raw := make([]definition, 0)

	// collapse lines without any content
	for i, line := range lines {
		lines[i] = collapse(line)
	}

	parents := make([]string, 0)
	indents := make([]string, 0)

	for n, line := range lines {
		if line == "" {
			continue
		}

		k := key(line)
		i := indentation(line)
		d := depth(indents, i)

		// check for invalid indentation
		if d == -1 {
			e := fmt.Sprintf("invalid indentation on line %d", n)
			return nil, &indentError{e, n}
		}

		// trim now redundant levels
		if d < len(indents) {
			parents = parents[:d]
			indents = indents[:d]
		}

		// if the line contains an assignment, record the the value
		if strings.ContainsRune(line, '=') {
			raw = append(raw, definition{
				key:   strings.Join(append(parents, k), "."),
				value: value(line),
				line:  n,
			})

			continue
		}

		// push the key and indentation onto their respective stacks
		parents = append(parents, k)
		indents = append(indents, i)
	}

	return raw, nil
}

// Trims trailing whitespace or, in the case of comment lines, returns
// an empty string.
func collapse(input string) string {
	s := strings.TrimRight(input, whitespace)

	for _, r := range s {
		if strings.ContainsRune(whitespace, r) {
			continue
		}

		// comment detected, blank this line
		if r == '#' {
			break
		}

		// if the first non-whitespace character @todo
		return input
	}

	return ""
}

// Returns the "key" component from a "key = value" string.
func key(input string) string {
	if eq := strings.IndexRune(input, '='); eq != -1 {
		input = input[:eq]
	}

	return strings.Trim(input, whitespace)
}

// Returns the "value" component from a "key = value" string.
func value(input string) string {
	if eq := strings.IndexRune(input, '='); eq != -1 {
		input = input[eq+1:]
	}

	return strings.Trim(input, whitespace)
}

// Returns the string's whitespace prefix.
func indentation(input string) string {
	end := strings.IndexFunc(input, func(r rune) bool {
		return strings.IndexRune(whitespace, r) == -1
	})

	if end == -1 {
		return ""
	}

	return input[:end]
}

// Given a list of previous indentation levels, finds the provided indentation
// level's depth value. A depth of 0 represents the lowest possible level of
// indentation.
// Returns -1 on errors caused by illegal indentation.
func depth(parents []string, current string) int {
	if current == "" {
		return 0
	}

	// the base indentation level must be an empty string
	if len(parents) == 0 {
		return -1
	}

	for i, prefix := range parents {
		switch {
		case current == prefix:
			return i
		case !strings.HasPrefix(current, prefix):
			return -1
		}
	}

	// if we get this far, the current line is further indented
	// than its parent
	return len(parents)
}
<|endoftext|>


<commit_before>// Package parse provides a client for the Parse API.
package parse

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"

	"github.com/facebookgo/httperr"
)

const (
	userAgentHeader     = "User-Agent"
	userAgent           = "go-parse-2015-01-31"
	masterKeyHeader     = "X-Parse-Master-Key"
	restAPIKeyHeader    = "X-Parse-REST-API-Key"
	sessionTokenHeader  = "X-Parse-Session-Token"
	applicationIDHeader = "X-Parse-Application-Id"
)

var (
	errEmptyMasterKey    = errors.New("parse: cannot use empty MasterKey Credentials")
	errEmptyRestAPIKey   = errors.New("parse: cannot use empty RestAPIKey Credentials")
	errEmptySessionToken = errors.New("parse: cannot use empty SessionToken Credentials")

	// The default base URL for the API.
	defaultBaseURL = &url.URL{
		Scheme: "https",
		Host:   "api.parse.com",
		Path:   "/1/",
	}
)

// Credentials allows for adding authentication information to a request.
type Credentials interface {
	Modify(r *http.Request) error
}

// MasterKey adds the Master Key to the request.
type MasterKey string

// Modify adds the Master Key header.
func (m MasterKey) Modify(r *http.Request) error {
	if m == "" {
		return errEmptyMasterKey
	}
	r.Header.Set(masterKeyHeader, string(m))
	return nil
}

// RestAPIKey adds the Rest API Key to the request.
type RestAPIKey string

// Modify adds the Rest API Key header.
func (k RestAPIKey) Modify(r *http.Request) error {
	if k == "" {
		return errEmptyRestAPIKey
	}
	r.Header.Set(restAPIKeyHeader, string(k))
	return nil
}

// SessionToken adds the Rest API Key and the Session Token to the request.
type SessionToken struct {
	RestAPIKey   string
	SessionToken string
}

// Modify adds the Session Token header.
func (t SessionToken) Modify(r *http.Request) error {
	if t.RestAPIKey == "" {
		return errEmptyRestAPIKey
	}
	if t.SessionToken == "" {
		return errEmptySessionToken
	}
	r.Header.Set(restAPIKeyHeader, string(t.RestAPIKey))
	r.Header.Set(sessionTokenHeader, string(t.SessionToken))
	return nil
}

// An Error from the Parse API.
type Error struct {
	// These are provided by the Parse API and may not always be available.
	Message string `json:"error"`
	Code    int    `json:"code"`

	// This is the HTTP StatusCode.
	StatusCode int `json:"-"`

	request  *http.Request
	response *http.Response
}

func (e *Error) Error() string {
	var buf bytes.Buffer
	if e.Code != 0 {
		fmt.Fprintf(&buf, "code %d", e.Code)
	}
	if e.Code != 0 && e.Message != "" {
		fmt.Fprint(&buf, " and ")
	}
	if e.Message != "" {
		fmt.Fprintf(&buf, "message %s", e.Message)
	}
	return httperr.NewError(
		errors.New(buf.String()),
		httperr.RedactNoOp(),
		e.request,
		e.response,
	).Error()
}

// Client provides access to the Parse API.
type Client struct {
	// The underlying http.RoundTripper to perform the individual requests. When
	// nil http.DefaultTransport will be used.
	Transport http.RoundTripper

	// The base URL to parse relative URLs off. If you pass absolute URLs to
	// Client functions they are used as-is. When nil, the production Parse URL
	// will be used.
	BaseURL *url.URL

	// Application ID will be included if not empty.
	ApplicationID string

	// Credentials if set, will be included on every request.
	Credentials Credentials
}

func (c *Client) transport() http.RoundTripper {
	if c.Transport == nil {
		return http.DefaultTransport
	}
	return c.Transport
}

// Get performs a GET method call on the given url and unmarshal response into
// result.
func (c *Client) Get(u *url.URL, result interface{}) (*http.Response, error) {
	return c.Do(&http.Request{Method: "GET", URL: u}, nil, result)
}

// Post performs a POST method call on the given url with the given body and
// unmarshal response into result.
func (c *Client) Post(u *url.URL, body, result interface{}) (*http.Response, error) {
	return c.Do(&http.Request{Method: "POST", URL: u}, body, result)
}

// Put performs a PUT method call on the given url with the given body and
// unmarshal response into result.
func (c *Client) Put(u *url.URL, body, result interface{}) (*http.Response, error) {
	return c.Do(&http.Request{Method: "PUT", URL: u}, body, result)
}

// Delete performs a DELETE method call on the given url and unmarshal response
// into result.
func (c *Client) Delete(u *url.URL, result interface{}) (*http.Response, error) {
	return c.Do(&http.Request{Method: "DELETE", URL: u}, nil, result)
}

// Do performs a Parse API call. This method modifies the request and adds the
// Authentication headers. The body is JSON encoded and for responses in the
// 2xx or 3xx range the response will be JSON decoded into result, for others
// an error of type Error will be returned.
func (c *Client) Do(req *http.Request, body, result interface{}) (*http.Response, error) {
	req.Proto = "HTTP/1.1"
	req.ProtoMajor = 1
	req.ProtoMinor = 1

	if req.URL == nil {
		if c.BaseURL == nil {
			req.URL = defaultBaseURL
		} else {
			req.URL = c.BaseURL
		}
	} else {
		if !req.URL.IsAbs() {
			if c.BaseURL == nil {
				req.URL = defaultBaseURL.ResolveReference(req.URL)
			} else {
				req.URL = c.BaseURL.ResolveReference(req.URL)
			}
		}
	}

	if req.Host == "" {
		req.Host = req.URL.Host
	}

	if req.Header == nil {
		req.Header = make(http.Header)
	}

	req.Header.Add(userAgentHeader, userAgent)
	if c.ApplicationID != "" {
		req.Header.Add(applicationIDHeader, c.ApplicationID)
	}

	if c.Credentials != nil {
		if err := c.Credentials.Modify(req); err != nil {
			return nil, err
		}
	}

	// we need to buffer as Parse requires a Content-Length
	if body != nil {
		bd, err := json.Marshal(body)
		if err != nil {
			return nil, httperr.NewError(err, httperr.RedactNoOp(), req, nil)
		}
		req.Body = ioutil.NopCloser(bytes.NewReader(bd))
		req.ContentLength = int64(len(bd))
	}

	res, err := c.transport().RoundTrip(req)
	if err != nil {
		return res, httperr.NewError(err, httperr.RedactNoOp(), req, res)
	}
	defer res.Body.Close()

	if res.StatusCode > 399 || res.StatusCode < 200 {
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return res, httperr.NewError(err, httperr.RedactNoOp(), req, res)
		}

		apiErr := &Error{
			StatusCode: res.StatusCode,
			request:    req,
			response:   res,
		}
		if len(body) > 0 {
			err = json.Unmarshal(body, apiErr)
			if err != nil {
				return res, httperr.NewError(err, httperr.RedactNoOp(), req, res)
			}
		}
		return res, apiErr
	}

	if result != nil {
		if err := json.NewDecoder(res.Body).Decode(result); err != nil {
			return res, httperr.NewError(err, httperr.RedactNoOp(), req, res)
		}
	}
	return res, nil
}

// WithCredentials returns a new instance of the Client using the given
// Credentials. It discards the previous Credentials.
func (c *Client) WithCredentials(cr Credentials) *Client {
	var c2 Client
	c2 = *c
	c2.Credentials = cr
	return &c2
}
<commit_msg>split RoundTrip method to allow for more complex scenarios<commit_after>// Package parse provides a client for the Parse API.
package parse

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"

	"github.com/facebookgo/httperr"
)

const (
	userAgentHeader     = "User-Agent"
	userAgent           = "go-parse-2015-01-31"
	masterKeyHeader     = "X-Parse-Master-Key"
	restAPIKeyHeader    = "X-Parse-REST-API-Key"
	sessionTokenHeader  = "X-Parse-Session-Token"
	applicationIDHeader = "X-Parse-Application-Id"
)

var (
	errEmptyMasterKey    = errors.New("parse: cannot use empty MasterKey Credentials")
	errEmptyRestAPIKey   = errors.New("parse: cannot use empty RestAPIKey Credentials")
	errEmptySessionToken = errors.New("parse: cannot use empty SessionToken Credentials")

	// The default base URL for the API.
	defaultBaseURL = &url.URL{
		Scheme: "https",
		Host:   "api.parse.com",
		Path:   "/1/",
	}
)

// Credentials allows for adding authentication information to a request.
type Credentials interface {
	Modify(r *http.Request) error
}

// MasterKey adds the Master Key to the request.
type MasterKey string

// Modify adds the Master Key header.
func (m MasterKey) Modify(r *http.Request) error {
	if m == "" {
		return errEmptyMasterKey
	}
	r.Header.Set(masterKeyHeader, string(m))
	return nil
}

// RestAPIKey adds the Rest API Key to the request.
type RestAPIKey string

// Modify adds the Rest API Key header.
func (k RestAPIKey) Modify(r *http.Request) error {
	if k == "" {
		return errEmptyRestAPIKey
	}
	r.Header.Set(restAPIKeyHeader, string(k))
	return nil
}

// SessionToken adds the Rest API Key and the Session Token to the request.
type SessionToken struct {
	RestAPIKey   string
	SessionToken string
}

// Modify adds the Session Token header.
func (t SessionToken) Modify(r *http.Request) error {
	if t.RestAPIKey == "" {
		return errEmptyRestAPIKey
	}
	if t.SessionToken == "" {
		return errEmptySessionToken
	}
	r.Header.Set(restAPIKeyHeader, string(t.RestAPIKey))
	r.Header.Set(sessionTokenHeader, string(t.SessionToken))
	return nil
}

// An Error from the Parse API.
type Error struct {
	// These are provided by the Parse API and may not always be available.
	Message string `json:"error"`
	Code    int    `json:"code"`

	// This is the HTTP StatusCode.
	StatusCode int `json:"-"`

	request  *http.Request
	response *http.Response
}

func (e *Error) Error() string {
	var buf bytes.Buffer
	if e.Code != 0 {
		fmt.Fprintf(&buf, "code %d", e.Code)
	}
	if e.Code != 0 && e.Message != "" {
		fmt.Fprint(&buf, " and ")
	}
	if e.Message != "" {
		fmt.Fprintf(&buf, "message %s", e.Message)
	}
	return httperr.NewError(
		errors.New(buf.String()),
		httperr.RedactNoOp(),
		e.request,
		e.response,
	).Error()
}

// Client provides access to the Parse API.
type Client struct {
	// The underlying http.RoundTripper to perform the individual requests. When
	// nil http.DefaultTransport will be used.
	Transport http.RoundTripper

	// The base URL to parse relative URLs off. If you pass absolute URLs to
	// Client functions they are used as-is. When nil, the production Parse URL
	// will be used.
	BaseURL *url.URL

	// Application ID will be included if not empty.
	ApplicationID string

	// Credentials if set, will be included on every request.
	Credentials Credentials
}

func (c *Client) transport() http.RoundTripper {
	if c.Transport == nil {
		return http.DefaultTransport
	}
	return c.Transport
}

// Get performs a GET method call on the given url and unmarshal response into
// result.
func (c *Client) Get(u *url.URL, result interface{}) (*http.Response, error) {
	return c.Do(&http.Request{Method: "GET", URL: u}, nil, result)
}

// Post performs a POST method call on the given url with the given body and
// unmarshal response into result.
func (c *Client) Post(u *url.URL, body, result interface{}) (*http.Response, error) {
	return c.Do(&http.Request{Method: "POST", URL: u}, body, result)
}

// Put performs a PUT method call on the given url with the given body and
// unmarshal response into result.
func (c *Client) Put(u *url.URL, body, result interface{}) (*http.Response, error) {
	return c.Do(&http.Request{Method: "PUT", URL: u}, body, result)
}

// Delete performs a DELETE method call on the given url and unmarshal response
// into result.
func (c *Client) Delete(u *url.URL, result interface{}) (*http.Response, error) {
	return c.Do(&http.Request{Method: "DELETE", URL: u}, nil, result)
}

// RoundTrip performs a RoundTrip ignoring the request and response bodies. It
// is up to the caller to close them. This method modifies the request.
func (c *Client) RoundTrip(req *http.Request) (*http.Response, error) {
	req.Proto = "HTTP/1.1"
	req.ProtoMajor = 1
	req.ProtoMinor = 1

	if req.URL == nil {
		if c.BaseURL == nil {
			req.URL = defaultBaseURL
		} else {
			req.URL = c.BaseURL
		}
	} else {
		if !req.URL.IsAbs() {
			if c.BaseURL == nil {
				req.URL = defaultBaseURL.ResolveReference(req.URL)
			} else {
				req.URL = c.BaseURL.ResolveReference(req.URL)
			}
		}
	}

	if req.Host == "" {
		req.Host = req.URL.Host
	}

	if req.Header == nil {
		req.Header = make(http.Header)
	}

	req.Header.Add(userAgentHeader, userAgent)
	if c.ApplicationID != "" {
		req.Header.Add(applicationIDHeader, c.ApplicationID)
	}

	if c.Credentials != nil {
		if err := c.Credentials.Modify(req); err != nil {
			return nil, err
		}
	}

	res, err := c.transport().RoundTrip(req)
	if err != nil {
		return res, httperr.NewError(err, httperr.RedactNoOp(), req, res)
	}

	if res.StatusCode > 399 || res.StatusCode < 200 {
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return res, httperr.NewError(err, httperr.RedactNoOp(), req, res)
		}

		apiErr := &Error{
			StatusCode: res.StatusCode,
			request:    req,
			response:   res,
		}
		if len(body) > 0 {
			err = json.Unmarshal(body, apiErr)
			if err != nil {
				return res, httperr.NewError(err, httperr.RedactNoOp(), req, res)
			}
		}
		return res, apiErr
	}

	return res, nil
}

// Do performs a Parse API call. This method modifies the request and adds the
// Authentication headers. The body is JSON encoded and for responses in the
// 2xx or 3xx range the response will be JSON decoded into result, for others
// an error of type Error will be returned.
func (c *Client) Do(req *http.Request, body, result interface{}) (*http.Response, error) {
	// we need to buffer as Parse requires a Content-Length
	if body != nil {
		bd, err := json.Marshal(body)
		if err != nil {
			return nil, httperr.NewError(err, httperr.RedactNoOp(), req, nil)
		}
		req.Body = ioutil.NopCloser(bytes.NewReader(bd))
		req.ContentLength = int64(len(bd))
	}

	res, err := c.RoundTrip(req)
	if err != nil {
		return res, err
	}
	defer res.Body.Close()

	if result != nil {
		if err := json.NewDecoder(res.Body).Decode(result); err != nil {
			return res, httperr.NewError(err, httperr.RedactNoOp(), req, res)
		}
	}
	return res, nil
}

// WithCredentials returns a new instance of the Client using the given
// Credentials. It discards the previous Credentials.
func (c *Client) WithCredentials(cr Credentials) *Client {
	var c2 Client
	c2 = *c
	c2.Credentials = cr
	return &c2
}
<|endoftext|>


<commit_before>package catTracks

import (
	"encoding/json"
	"fmt"
	"sort"
	"time"

	"github.com/boltdb/bolt"
	"github.com/rotblauer/trackpoints/trackPoint"
	"log"
	"os"
	"os/user"
	"path/filepath"
)

var punktlichTileDBPathRelHome = filepath.Join("punktlich.rotblauer.com", "tester.db")

type LastKnown map[string]trackPoint.TrackPoint
type Metadata struct {
	KeyN               int
	KeyNUpdated        time.Time
	LastUpdatedAt      time.Time
	LastUpdatedBy      string
	LastUpdatedPointsN int
	TileDBLastUpdated  time.Time
}

func getmetadata() (out []byte, err error) {
	err = GetDB().View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(statsKey))
		out = b.Get([]byte("metadata"))
		return nil
	})
	return
}
func storemetadata(lastpoint trackPoint.TrackPoint, lenpointsupdated int) error {
	db := GetDB()
	e := db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(statsKey))

		// if not initialized, run the stats which takes a hot second
		var keyN int

		var tileDBLastUpdated time.Time
		var homedir string
		usr, err := user.Current()
		if err != nil {
			log.Println("get current user err", err)
			homedir = os.Getenv("HOME")
		} else {
			homedir = usr.HomeDir
		}
		dbpath := filepath.Join(homedir, punktlichTileDBPathRelHome)
		dbpath = filepath.Clean(dbpath)
		log.Println("dbpath", dbpath)
		dbfi, err := os.Stat(dbpath)
		if err == nil {
			tileDBLastUpdated = dbfi.ModTime()
		} else {
			log.Println("err tile db path stat:", err)
		}

		v := b.Get([]byte("metadata"))
		md := &Metadata{}
		var keyNUpdated time.Time

		if v == nil {
			log.Println("updating bucket stats key_n...")
			keyN = tx.Bucket([]byte(trackKey)).Stats().KeyN
			log.Println("initialized metadata", "keyN:", keyN)
			keyNUpdated = time.Now().UTC()
		} else {
			if e := json.Unmarshal(v, md); e != nil {
				return e
			}
		}
		if md != nil && (md.KeyNUpdated.IsZero() || time.Since(md.KeyNUpdated) > 24*time.Hour) {
			log.Println("updating bucket stats key_n...")
			log.Println("  because", md == nil, md.KeyNUpdated, md.KeyNUpdated.IsZero(), time.Since(md.KeyNUpdated) > 24*time.Hour)
			keyN = 180000000
			// keyN = tx.Bucket([]byte(trackKey)).Stats().KeyN
			log.Println("updated metadata keyN:", keyN)
			keyNUpdated = time.Now().UTC()
		} else {
			log.Println("dont update keyn", md == nil, md.KeyNUpdated, md.KeyNUpdated.IsZero(), time.Since(md.KeyNUpdated) > 24*time.Hour)
			keyN = md.KeyN + lenpointsupdated
		}

		d := &Metadata{
			KeyN:               keyN,
			LastUpdatedAt:      time.Now().UTC(),
			LastUpdatedBy:      lastpoint.Name,
			LastUpdatedPointsN: lenpointsupdated,
			TileDBLastUpdated:  tileDBLastUpdated,
		}
		if !keyNUpdated.IsZero() {
			d.KeyNUpdated = keyNUpdated
		} else {
			d.KeyNUpdated = md.KeyNUpdated
		}
		by, e := json.Marshal(d)
		if e != nil {
			return nil
		}
		if e := b.Put([]byte("metadata"), by); e != nil {
			return e
		}

		return nil
	})
	return e
}

func getLastKnownData() (out []byte, err error) {
	err = GetDB().View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(statsKey))
		out = b.Get([]byte("lastknown"))
		return nil
	})
	return
}

func storeLastKnown(tp trackPoint.TrackPoint) {
	//lastKnownMap[tp.Name] = tp
	lk := LastKnown{}
	if err := GetDB().Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(statsKey))

		v := b.Get([]byte("lastknown"))
		if e := json.Unmarshal(v, &lk); e != nil {
			log.Println("error unmarshalling nil lastknown", tp)
		}
		lk[tp.Name] = tp
		if by, e := json.Marshal(lk); e == nil {
			if e := b.Put([]byte("lastknown"), by); e != nil {
				return e
			}
		} else {
			log.Println("err marshalling lastknown", tp)
		}
		return nil
	}); err != nil {
		log.Println("error storing last known: %v", err)
	} else {
		log.Printf("stored last known: lk=%v\ntp=%v", lk, tp)
	}
}

func storePoints(trackPoints trackPoint.TrackPoints) error {
	var err error
	for _, point := range trackPoints {
		err = storePoint(point)
		if err != nil {
			return err
		}
	}
	if err == nil {
		l := len(trackPoints)
		err = storemetadata(trackPoints[l-1], l)
		storeLastKnown(trackPoints[l-1])
	}
	return err
}

func buildTrackpointKey(tp trackPoint.TrackPoint) []byte {
	if tp.Uuid == "" {
		if tp.ID != 0 {
			return i64tob(tp.ID)
		}
		return i64tob(tp.Time.UnixNano())
	}
	// have uuid
	k := []byte{}
	k = append(k, i64tob(tp.Time.UnixNano())...)
	k = append(k, []byte(tp.Uuid)...)
	return k
}

func storePoint(tp trackPoint.TrackPoint) error {

	var err error
	if tp.Time.IsZero() {
		tp.Time = time.Now()
	}

	GetDB().Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(trackKey))

		// id, _ := b.NextSequence()
		// trackPoint.ID = int(id)

		tp.ID = tp.Time.UnixNano() //dunno if can really get nanoy, or if will just *1000.

		key := buildTrackpointKey(tp)

		if exists := b.Get(key); exists != nil {
			// make sure it's ours
			var existingTrackpoint trackPoint.TrackPoint
			e := json.Unmarshal(exists, &existingTrackpoint)
			if e != nil {
				fmt.Println("Checking on an existing trackpoint and got an error with one of the existing trackpoints unmarshaling.")
			}
			if existingTrackpoint.Name == tp.Name && existingTrackpoint.Uuid == tp.Uuid {
				fmt.Println("Got redundant track; not storing: ", tp.Name, tp.Uuid, tp.Time)
				return nil
			}
		}
		// gets "" case nontestesing
		tp.Name = getTestesPrefix() + tp.Name

		trackPointJSON, err := json.Marshal(tp)
		if err != nil {
			return err
		}
		err = b.Put(key, trackPointJSON)
		if err != nil {
			fmt.Println("Didn't save post trackPoint in bolt.", err)
			return err
		}
		// p := quadtree.NewPoint(tp.Lat, tp.Lng, &tp)
		// if !GetQT().Insert(p) {
		// 	fmt.Println("Couldn't add to quadtree: ", p)
		// }
		fmt.Println("Saved trackpoint: ", tp)
		return nil
	})

	if err != nil {
		fmt.Println(err)
	}
	return err
}

func getAllStoredPoints() (tps trackPoint.TPs, e error) {
	start := time.Now()

	e = GetDB().View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(trackKey))

		// can swap out for- eacher if we figure indexing, or even want it
		b.ForEach(func(trackPointKey, trackPointVal []byte) error {

			var trackPointCurrent trackPoint.TrackPoint
			err := json.Unmarshal(trackPointVal, &trackPointCurrent)
			if err != nil {
				return err
			}

			tps = append(tps, &trackPointCurrent)
			return nil
		})
		return nil
	})
	fmt.Printf("Found %d points with iterator method - %s\n", len(tps), time.Since(start))

	return tps, e
}

//TODO make queryable ala which cat when
// , channel chan *trackPoint.TrackPoint
func getPointsQT(query *query) (tps trackPoint.TPs, err error) {

	if query == nil {
		query = NewQuery()
	}

	query.SetDefaults() // eps, lim  catches empty vals

	if query.IsBounded() {
		tps = getPointsFromQT(query)
	} else {
		tps, err = getAllStoredPoints()
		if err != nil {
			return nil, err
		}
	}

	if len(tps) > query.Limit {
		limitedTPs, err := limitTrackPoints(query, tps)
		if err != nil {
			fmt.Println(err)
			return tps, err
		}
		tps = limitedTPs
	}

	sort.Sort(tps)

	return tps, err
}
<commit_msg>problem: should not use fake number<commit_after>package catTracks

import (
	"encoding/json"
	"fmt"
	"sort"
	"time"

	"github.com/boltdb/bolt"
	"github.com/rotblauer/trackpoints/trackPoint"
	"log"
	"os"
	"os/user"
	"path/filepath"
)

var punktlichTileDBPathRelHome = filepath.Join("punktlich.rotblauer.com", "tester.db")

type LastKnown map[string]trackPoint.TrackPoint
type Metadata struct {
	KeyN               int
	KeyNUpdated        time.Time
	LastUpdatedAt      time.Time
	LastUpdatedBy      string
	LastUpdatedPointsN int
	TileDBLastUpdated  time.Time
}

func getmetadata() (out []byte, err error) {
	err = GetDB().View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(statsKey))
		out = b.Get([]byte("metadata"))
		return nil
	})
	return
}
func storemetadata(lastpoint trackPoint.TrackPoint, lenpointsupdated int) error {
	db := GetDB()
	e := db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(statsKey))

		// if not initialized, run the stats which takes a hot second
		var keyN int

		var tileDBLastUpdated time.Time
		var homedir string
		usr, err := user.Current()
		if err != nil {
			log.Println("get current user err", err)
			homedir = os.Getenv("HOME")
		} else {
			homedir = usr.HomeDir
		}
		dbpath := filepath.Join(homedir, punktlichTileDBPathRelHome)
		dbpath = filepath.Clean(dbpath)
		log.Println("dbpath", dbpath)
		dbfi, err := os.Stat(dbpath)
		if err == nil {
			tileDBLastUpdated = dbfi.ModTime()
		} else {
			log.Println("err tile db path stat:", err)
		}

		v := b.Get([]byte("metadata"))
		md := &Metadata{}
		var keyNUpdated time.Time

		if v == nil {
			log.Println("updating bucket stats key_n...")
			keyN = tx.Bucket([]byte(trackKey)).Stats().KeyN
			log.Println("initialized metadata", "keyN:", keyN)
			keyNUpdated = time.Now().UTC()
		} else {
			if e := json.Unmarshal(v, md); e != nil {
				return e
			}
		}
		if md != nil && (md.KeyNUpdated.IsZero() || time.Since(md.KeyNUpdated) > 24*time.Hour) {
			log.Println("updating bucket stats key_n...")
			log.Println("  because", md == nil, md.KeyNUpdated, md.KeyNUpdated.IsZero(), time.Since(md.KeyNUpdated) > 24*time.Hour)
			keyN = 0
			// keyN = tx.Bucket([]byte(trackKey)).Stats().KeyN
			log.Println("updated metadata keyN:", keyN)
			keyNUpdated = time.Now().UTC()
		} else {
			log.Println("dont update keyn", md == nil, md.KeyNUpdated, md.KeyNUpdated.IsZero(), time.Since(md.KeyNUpdated) > 24*time.Hour)
			keyN = md.KeyN + lenpointsupdated
		}

		d := &Metadata{
			KeyN:               keyN,
			LastUpdatedAt:      time.Now().UTC(),
			LastUpdatedBy:      lastpoint.Name,
			LastUpdatedPointsN: lenpointsupdated,
			TileDBLastUpdated:  tileDBLastUpdated,
		}
		if !keyNUpdated.IsZero() {
			d.KeyNUpdated = keyNUpdated
		} else {
			d.KeyNUpdated = md.KeyNUpdated
		}
		by, e := json.Marshal(d)
		if e != nil {
			return nil
		}
		if e := b.Put([]byte("metadata"), by); e != nil {
			return e
		}

		return nil
	})
	return e
}

func getLastKnownData() (out []byte, err error) {
	err = GetDB().View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(statsKey))
		out = b.Get([]byte("lastknown"))
		return nil
	})
	return
}

func storeLastKnown(tp trackPoint.TrackPoint) {
	//lastKnownMap[tp.Name] = tp
	lk := LastKnown{}
	if err := GetDB().Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(statsKey))

		v := b.Get([]byte("lastknown"))
		if e := json.Unmarshal(v, &lk); e != nil {
			log.Println("error unmarshalling nil lastknown", tp)
		}
		lk[tp.Name] = tp
		if by, e := json.Marshal(lk); e == nil {
			if e := b.Put([]byte("lastknown"), by); e != nil {
				return e
			}
		} else {
			log.Println("err marshalling lastknown", tp)
		}
		return nil
	}); err != nil {
		log.Println("error storing last known: %v", err)
	} else {
		log.Printf("stored last known: lk=%v\ntp=%v", lk, tp)
	}
}

func storePoints(trackPoints trackPoint.TrackPoints) error {
	var err error
	for _, point := range trackPoints {
		err = storePoint(point)
		if err != nil {
			return err
		}
	}
	if err == nil {
		l := len(trackPoints)
		err = storemetadata(trackPoints[l-1], l)
		storeLastKnown(trackPoints[l-1])
	}
	return err
}

func buildTrackpointKey(tp trackPoint.TrackPoint) []byte {
	if tp.Uuid == "" {
		if tp.ID != 0 {
			return i64tob(tp.ID)
		}
		return i64tob(tp.Time.UnixNano())
	}
	// have uuid
	k := []byte{}
	k = append(k, i64tob(tp.Time.UnixNano())...)
	k = append(k, []byte(tp.Uuid)...)
	return k
}

func storePoint(tp trackPoint.TrackPoint) error {

	var err error
	if tp.Time.IsZero() {
		tp.Time = time.Now()
	}

	GetDB().Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(trackKey))

		// id, _ := b.NextSequence()
		// trackPoint.ID = int(id)

		tp.ID = tp.Time.UnixNano() //dunno if can really get nanoy, or if will just *1000.

		key := buildTrackpointKey(tp)

		if exists := b.Get(key); exists != nil {
			// make sure it's ours
			var existingTrackpoint trackPoint.TrackPoint
			e := json.Unmarshal(exists, &existingTrackpoint)
			if e != nil {
				fmt.Println("Checking on an existing trackpoint and got an error with one of the existing trackpoints unmarshaling.")
			}
			if existingTrackpoint.Name == tp.Name && existingTrackpoint.Uuid == tp.Uuid {
				fmt.Println("Got redundant track; not storing: ", tp.Name, tp.Uuid, tp.Time)
				return nil
			}
		}
		// gets "" case nontestesing
		tp.Name = getTestesPrefix() + tp.Name

		trackPointJSON, err := json.Marshal(tp)
		if err != nil {
			return err
		}
		err = b.Put(key, trackPointJSON)
		if err != nil {
			fmt.Println("Didn't save post trackPoint in bolt.", err)
			return err
		}
		// p := quadtree.NewPoint(tp.Lat, tp.Lng, &tp)
		// if !GetQT().Insert(p) {
		// 	fmt.Println("Couldn't add to quadtree: ", p)
		// }
		fmt.Println("Saved trackpoint: ", tp)
		return nil
	})

	if err != nil {
		fmt.Println(err)
	}
	return err
}

func getAllStoredPoints() (tps trackPoint.TPs, e error) {
	start := time.Now()

	e = GetDB().View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(trackKey))

		// can swap out for- eacher if we figure indexing, or even want it
		b.ForEach(func(trackPointKey, trackPointVal []byte) error {

			var trackPointCurrent trackPoint.TrackPoint
			err := json.Unmarshal(trackPointVal, &trackPointCurrent)
			if err != nil {
				return err
			}

			tps = append(tps, &trackPointCurrent)
			return nil
		})
		return nil
	})
	fmt.Printf("Found %d points with iterator method - %s\n", len(tps), time.Since(start))

	return tps, e
}

//TODO make queryable ala which cat when
// , channel chan *trackPoint.TrackPoint
func getPointsQT(query *query) (tps trackPoint.TPs, err error) {

	if query == nil {
		query = NewQuery()
	}

	query.SetDefaults() // eps, lim  catches empty vals

	if query.IsBounded() {
		tps = getPointsFromQT(query)
	} else {
		tps, err = getAllStoredPoints()
		if err != nil {
			return nil, err
		}
	}

	if len(tps) > query.Limit {
		limitedTPs, err := limitTrackPoints(query, tps)
		if err != nil {
			fmt.Println(err)
			return tps, err
		}
		tps = limitedTPs
	}

	sort.Sort(tps)

	return tps, err
}
<|endoftext|>


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

// This file contains tests verifying the types associated with an AST after
// type checking.

package types

import (
	"go/ast"
	"go/parser"
	"testing"
)

const filename = "<src>"

func makePkg(t *testing.T, src string) (*ast.Package, error) {
	file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
	if err != nil {
		return nil, err
	}
	files := map[string]*ast.File{filename: file}
	pkg, err := ast.NewPackage(fset, files, GcImport, Universe)
	if err != nil {
		return nil, err
	}
	if err := Check(fset, pkg, nil, nil); err != nil {
		return nil, err
	}
	return pkg, nil
}

type testEntry struct {
	src, str string
}

// dup returns a testEntry where both src and str are the same.
func dup(s string) testEntry {
	return testEntry{s, s}
}

var testTypes = []testEntry{
	// basic types
	dup("int"),
	dup("float32"),
	dup("string"),

	// arrays
	dup("[10]int"),

	// slices
	dup("[]int"),
	dup("[][]int"),

	// structs
	dup("struct{}"),
	dup("struct{x int}"),
	{`struct {
		x, y int
		z float32 "foo"
	}`, `struct{x int; y int; z float32 "foo"}`},
	{`struct {
		string
		elems []T
	}`, `struct{string; elems []T}`},

	// pointers
	dup("*int"),
	dup("***struct{}"),
	dup("*struct{a int; b float32}"),

	// functions
	dup("func()"),
	dup("func(x int)"),
	{"func(x, y int)", "func(x int, y int)"},
	{"func(x, y int, z string)", "func(x int, y int, z string)"},
	dup("func(int)"),
	{"func(int, string, byte)", "func(int, string, byte)"},

	dup("func() int"),
	{"func() (string)", "func() string"},
	dup("func() (u int)"),
	{"func() (u, v int, w string)", "func() (u int, v int, w string)"},

	dup("func(int) string"),
	dup("func(x int) string"),
	dup("func(x int) (u string)"),
	{"func(x, y int) (u string)", "func(x int, y int) (u string)"},

	dup("func(...int) string"),
	dup("func(x ...int) string"),
	dup("func(x ...int) (u string)"),
	{"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"},

	// interfaces
	dup("interface{}"),
	dup("interface{m()}"),
	{`interface{
		m(int) float32
		String() string
	}`, `interface{String() string; m(int) float32}`}, // methods are sorted
	// TODO(gri) add test for interface w/ anonymous field

	// maps
	dup("map[string]int"),
	{"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},

	// channels
	dup("chan int"),
	dup("chan<- func()"),
	dup("<-chan []func() int"),
}

func TestTypes(t *testing.T) {
	for _, test := range testTypes {
		src := "package p; type T " + test.src
		pkg, err := makePkg(t, src)
		if err != nil {
			t.Errorf("%s: %s", src, err)
			continue
		}
		typ := underlying(pkg.Scope.Lookup("T").Type.(Type))
		str := typeString(typ)
		if str != test.str {
			t.Errorf("%s: got %s, want %s", test.src, str, test.str)
		}
	}
}

var testExprs = []testEntry{
	// basic type literals
	dup("x"),
	dup("true"),
	dup("42"),
	dup("3.1415"),
	dup("2.71828i"),
	dup(`'a'`),
	dup(`"foo"`),
	dup("`bar`"),

	// arbitrary expressions
	dup("&x"),
	dup("*x"),
	dup("(x)"),
	dup("x + y"),
	dup("x + y * 10"),
	dup("s.foo"),
	dup("s[0]"),
	dup("s[x:y]"),
	dup("s[:y]"),
	dup("s[x:]"),
	dup("s[:]"),
	dup("f(1, 2.3)"),
	dup("-f(10, 20)"),
	dup("f(x + y, +3.1415)"),
	{"func(a, b int) {}", "(func literal)"},
	{"func(a, b int) []int {}()[x]", "(func literal)()[x]"},
	{"[]int{1, 2, 3}", "(composite literal)"},
	{"[]int{1, 2, 3}[x:]", "(composite literal)[x:]"},
	{"x.([]string)", "x.(...)"},
}

func TestExprs(t *testing.T) {
	for _, test := range testExprs {
		src := "package p; var _ = " + test.src + "; var (x, y int; s []string; f func(int, float32))"
		pkg, err := makePkg(t, src)
		if err != nil {
			t.Errorf("%s: %s", src, err)
			continue
		}
		expr := pkg.Files[filename].Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec).Values[0]
		str := exprString(expr)
		if str != test.str {
			t.Errorf("%s: got %s, want %s", test.src, str, test.str)
		}
	}
}
<commit_msg>fix build: use temporary variable to avoid compiler error<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains tests verifying the types associated with an AST after
// type checking.

package types

import (
	"go/ast"
	"go/parser"
	"testing"
)

const filename = "<src>"

func makePkg(t *testing.T, src string) (*ast.Package, error) {
	file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
	if err != nil {
		return nil, err
	}
	files := map[string]*ast.File{filename: file}
	pkg, err := ast.NewPackage(fset, files, GcImport, Universe)
	if err != nil {
		return nil, err
	}
	if err := Check(fset, pkg, nil, nil); err != nil {
		return nil, err
	}
	return pkg, nil
}

type testEntry struct {
	src, str string
}

// dup returns a testEntry where both src and str are the same.
func dup(s string) testEntry {
	return testEntry{s, s}
}

var testTypes = []testEntry{
	// basic types
	dup("int"),
	dup("float32"),
	dup("string"),

	// arrays
	dup("[10]int"),

	// slices
	dup("[]int"),
	dup("[][]int"),

	// structs
	dup("struct{}"),
	dup("struct{x int}"),
	{`struct {
		x, y int
		z float32 "foo"
	}`, `struct{x int; y int; z float32 "foo"}`},
	{`struct {
		string
		elems []T
	}`, `struct{string; elems []T}`},

	// pointers
	dup("*int"),
	dup("***struct{}"),
	dup("*struct{a int; b float32}"),

	// functions
	dup("func()"),
	dup("func(x int)"),
	{"func(x, y int)", "func(x int, y int)"},
	{"func(x, y int, z string)", "func(x int, y int, z string)"},
	dup("func(int)"),
	{"func(int, string, byte)", "func(int, string, byte)"},

	dup("func() int"),
	{"func() (string)", "func() string"},
	dup("func() (u int)"),
	{"func() (u, v int, w string)", "func() (u int, v int, w string)"},

	dup("func(int) string"),
	dup("func(x int) string"),
	dup("func(x int) (u string)"),
	{"func(x, y int) (u string)", "func(x int, y int) (u string)"},

	dup("func(...int) string"),
	dup("func(x ...int) string"),
	dup("func(x ...int) (u string)"),
	{"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"},

	// interfaces
	dup("interface{}"),
	dup("interface{m()}"),
	{`interface{
		m(int) float32
		String() string
	}`, `interface{String() string; m(int) float32}`}, // methods are sorted
	// TODO(gri) add test for interface w/ anonymous field

	// maps
	dup("map[string]int"),
	{"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},

	// channels
	dup("chan int"),
	dup("chan<- func()"),
	dup("<-chan []func() int"),
}

func TestTypes(t *testing.T) {
	for _, test := range testTypes {
		src := "package p; type T " + test.src
		pkg, err := makePkg(t, src)
		if err != nil {
			t.Errorf("%s: %s", src, err)
			continue
		}
		typ := underlying(pkg.Scope.Lookup("T").Type.(Type))
		str := typeString(typ)
		if str != test.str {
			t.Errorf("%s: got %s, want %s", test.src, str, test.str)
		}
	}
}

var testExprs = []testEntry{
	// basic type literals
	dup("x"),
	dup("true"),
	dup("42"),
	dup("3.1415"),
	dup("2.71828i"),
	dup(`'a'`),
	dup(`"foo"`),
	dup("`bar`"),

	// arbitrary expressions
	dup("&x"),
	dup("*x"),
	dup("(x)"),
	dup("x + y"),
	dup("x + y * 10"),
	dup("s.foo"),
	dup("s[0]"),
	dup("s[x:y]"),
	dup("s[:y]"),
	dup("s[x:]"),
	dup("s[:]"),
	dup("f(1, 2.3)"),
	dup("-f(10, 20)"),
	dup("f(x + y, +3.1415)"),
	{"func(a, b int) {}", "(func literal)"},
	{"func(a, b int) []int {}()[x]", "(func literal)()[x]"},
	{"[]int{1, 2, 3}", "(composite literal)"},
	{"[]int{1, 2, 3}[x:]", "(composite literal)[x:]"},
	{"x.([]string)", "x.(...)"},
}

func TestExprs(t *testing.T) {
	for _, test := range testExprs {
		src := "package p; var _ = " + test.src + "; var (x, y int; s []string; f func(int, float32))"
		pkg, err := makePkg(t, src)
		if err != nil {
			t.Errorf("%s: %s", src, err)
			continue
		}
		// TODO(gri) writing the code below w/o the decl variable will
		//           cause a 386 compiler error (out of fixed registers)
		decl := pkg.Files[filename].Decls[0].(*ast.GenDecl)
		expr := decl.Specs[0].(*ast.ValueSpec).Values[0]
		str := exprString(expr)
		if str != test.str {
			t.Errorf("%s: got %s, want %s", test.src, str, test.str)
		}
	}
}
<|endoftext|>


<commit_before>/*  Original C version https://github.com/jgm/peg-markdown/
 *	Copyright 2008 John MacFarlane (jgm at berkeley dot edu).
 *
 *  Modifications and translation from C into Go
 *  based on markdown_output.c
 *	Copyright 2010 Michael Teichgräber (mt at wmipf dot de)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License or the MIT
 *  license.  See LICENSE for details.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 */

package markdown

// HTML output functions

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

type Writer interface {
	Write([]byte) (int, error)
	WriteString(string) (int, error)
	WriteRune(rune) (int, error)
	WriteByte(byte) error
}

type baseWriter struct {
	Writer
	padded int
}

type htmlOut struct {
	baseWriter
	obfuscate bool

	notenum  int
	endNotes []*element /* List of endnotes to print after main content. */
}

func ToHTML(w Writer) Formatter {
	f := new(htmlOut)
	f.baseWriter = baseWriter{w, 2}
	return f
}
func (f *htmlOut) FormatBlock(tree *element) {
	f.elist(tree)
}
func (f *htmlOut) Finish() {
	if len(f.endNotes) != 0 {
		f.sp()
		f.printEndnotes()
	}
	f.WriteByte('\n')
	f.padded = 2
}

// pad - add a number of newlines, the value of the
// argument minus the value of `padded'
// One newline means a line break, similar to troff's .br
// request, two newlines mean a line break plus an
// empty line, similar to troff's .sp request
func (w *baseWriter) pad(n int) {
	for ; n > w.padded; n-- {
		w.WriteByte('\n')
	}
	w.padded = 0
}

func (h *htmlOut) br() *htmlOut {
	h.pad(1)
	return h
}

func (h *htmlOut) sp() *htmlOut {
	h.pad(2)
	return h
}

func (h *htmlOut) skipPadding() *htmlOut {
	h.padded = 2
	return h
}

// print a string
func (w *htmlOut) s(s string) *htmlOut {
	w.WriteString(s)
	return w
}

/* print string, escaping for HTML
 * If obfuscate selected, convert characters to hex or decimal entities at random
 */
func (w *htmlOut) str(s string) *htmlOut {
	var ws string
	var i0 = 0

	o := w.obfuscate
	for i, r := range s {
		switch r {
		case '&':
			ws = "&"
		case '<':
			ws = "<"
		case '>':
			ws = ">"
		case '"':
			ws = """
		default:
			if o && r < 128 && r >= 0 {
				if rand.Intn(2) == 0 {
					ws = fmt.Sprintf("&#%d;", r)
				} else {
					ws = fmt.Sprintf("&#%x;", r)
				}
			} else {
				if i0 == -1 {
					i0 = i
				}
				continue
			}
		}
		if i0 != -1 {
			w.WriteString(s[i0:i])
			i0 = -1
		}
		w.WriteString(ws)
	}
	if i0 != -1 {
		w.WriteString(s[i0:])
	}
	return w
}

func (w *htmlOut) children(el *element) *htmlOut {
	return w.elist(el.children)
}
func (w *htmlOut) inline(tag string, el *element) *htmlOut {
	return w.s(tag).children(el).s("</").s(tag[1:])
}
func (w *htmlOut) listBlock(tag string, el *element) *htmlOut {
	return w.sp().s(tag).elist(el.children).br().s("</").s(tag[1:])
}
func (w *htmlOut) listItem(tag string, el *element) *htmlOut {
	return w.br().s(tag).skipPadding().elist(el.children).s("</").s(tag[1:])
}

/* print a list of elements
 */
func (w *htmlOut) elist(list *element) *htmlOut {
	for list != nil {
		w.elem(list)
		list = list.next
	}
	return w
}

// print an element
func (w *htmlOut) elem(elt *element) *htmlOut {
	var s string

	switch elt.key {
	case SPACE:
		s = elt.contents.str
	case LINEBREAK:
		s = "
\n"
	case STR:
		w.str(elt.contents.str)
	case ELLIPSIS:
		s = "…"
	case EMDASH:
		s = "—"
	case ENDASH:
		s = "–"
	case APOSTROPHE:
		s = "’"
	case SINGLEQUOTED:
		w.s("‘").children(elt).s("’")
	case DOUBLEQUOTED:
		w.s("“").children(elt).s("”")
	case CODE:
		w.s("").str(elt.contents.str).s("")
	case HTML:
		s = elt.contents.str
	case LINK:
		o := w.obfuscate
		if strings.Index(elt.contents.link.url, "mailto:") == 0 {
			w.obfuscate = true /* obfuscate mailto: links */
		}
		w.s(`<a href="`).str(elt.contents.link.url).s(`"`)
		if len(elt.contents.link.title) > 0 {
			w.s(` title="`).str(elt.contents.link.title).s(`"`)
		}
		w.s(">").elist(elt.contents.link.label).s("")
		w.obfuscate = o
	case IMAGE:
		w.s(`<img src="`).str(elt.contents.link.url).s(`" alt="`)
		w.elist(elt.contents.link.label).s(`"`)
		if len(elt.contents.link.title) > 0 {
			w.s(` title="`).str(elt.contents.link.title).s(`"`)
		}
		w.s(" />")
	case EMPH:
		w.inline("", elt)
	case STRONG:
		w.inline("", elt)
	case STRIKE:
		w.inline("", elt)
	case LIST:
		w.children(elt)
	case RAW:
		/* Shouldn't occur - these are handled by process_raw_blocks() */
		log.Fatalf("RAW")
	case H1, H2, H3, H4, H5, H6:
		h := "<h" + string('1'+elt.key-H1) + ">" /* assumes H1 ... H6 are in order */
		w.sp().inline(h, elt)
	case PLAIN:
		w.br().children(elt)
	case PARA:
		w.sp().inline("
", elt)
	case HRULE:
		w.sp().s("
")
	case HTMLBLOCK:
		w.sp().s(elt.contents.str)
	case VERBATIM:
		w.sp().s("
").str(elt.contents.str).s("
")
	case BULLETLIST:
		w.listBlock("
", elt)
	case ORDEREDLIST:
		w.listBlock("
", elt)
	case DEFINITIONLIST:
		w.listBlock("
", elt)
	case DEFTITLE:
		w.listItem("
", elt)
	case DEFDATA:
		w.listItem("
", elt)
	case LISTITEM:
		w.listItem("
", elt)
	case BLOCKQUOTE:
		w.sp().s("
\n").skipPadding().children(elt).br().s("
")
	case REFERENCE:
		/* Nonprinting */
	case NOTE:
		/* if contents.str == 0, then print note; else ignore, since this
		 * is a note block that has been incorporated into the notes list
		 */
		if elt.contents.str == "" {
			w.endNotes = append(w.endNotes, elt) /* add an endnote to global endnotes list */
			w.notenum++
			nn := w.notenum
			s = fmt.Sprintf(`<a class="noteref" id="fnref%d" href="#fn%d" title="Jump to note %d">[%d]</a>`,
				nn, nn, nn, nn)
		}
	default:
		log.Fatalf("htmlOut.elem encountered unknown element key = %d\n", elt.key)
	}
	if s != "" {
		w.s(s)
	}
	return w
}

func (w *htmlOut) printEndnotes() {
	counter := 0

	w.s("
\n
")
	for _, elt := range w.endNotes {
		counter++
		w.br().s(fmt.Sprintf("
\n", counter)).skipPadding()
		w.children(elt)
		w.s(fmt.Sprintf(" [back]", counter))
		w.br().s("
")
	}
	w.br().s("
")
}
<commit_msg>Update markdown parser to escape HTML outside of code blocks<commit_after>/*  Original C version https://github.com/jgm/peg-markdown/
 *	Copyright 2008 John MacFarlane (jgm at berkeley dot edu).
 *
 *  Modifications and translation from C into Go
 *  based on markdown_output.c
 *	Copyright 2010 Michael Teichgräber (mt at wmipf dot de)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License or the MIT
 *  license.  See LICENSE for details.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 */

package markdown

// HTML output functions

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

type Writer interface {
	Write([]byte) (int, error)
	WriteString(string) (int, error)
	WriteRune(rune) (int, error)
	WriteByte(byte) error
}

type baseWriter struct {
	Writer
	padded int
}

type htmlOut struct {
	baseWriter
	obfuscate bool

	notenum  int
	endNotes []*element /* List of endnotes to print after main content. */
}

func ToHTML(w Writer) Formatter {
	f := new(htmlOut)
	f.baseWriter = baseWriter{w, 2}
	return f
}
func (f *htmlOut) FormatBlock(tree *element) {
	f.elist(tree)
}
func (f *htmlOut) Finish() {
	if len(f.endNotes) != 0 {
		f.sp()
		f.printEndnotes()
	}
	f.WriteByte('\n')
	f.padded = 2
}

// pad - add a number of newlines, the value of the
// argument minus the value of `padded'
// One newline means a line break, similar to troff's .br
// request, two newlines mean a line break plus an
// empty line, similar to troff's .sp request
func (w *baseWriter) pad(n int) {
	for ; n > w.padded; n-- {
		w.WriteByte('\n')
	}
	w.padded = 0
}

func (h *htmlOut) br() *htmlOut {
	h.pad(1)
	return h
}

func (h *htmlOut) sp() *htmlOut {
	h.pad(2)
	return h
}

func (h *htmlOut) skipPadding() *htmlOut {
	h.padded = 2
	return h
}

// print a string
func (w *htmlOut) s(s string) *htmlOut {
	w.WriteString(s)
	return w
}

/* print string, escaping for HTML
 * If obfuscate selected, convert characters to hex or decimal entities at random
 */
func (w *htmlOut) str(s string) *htmlOut {
	var ws string
	var i0 = 0

	o := w.obfuscate
	for i, r := range s {
		switch r {
		case '&':
			ws = "&"
		case '<':
			ws = "<"
		case '>':
			ws = ">"
		case '"':
			ws = """
		default:
			if o && r < 128 && r >= 0 {
				if rand.Intn(2) == 0 {
					ws = fmt.Sprintf("&#%d;", r)
				} else {
					ws = fmt.Sprintf("&#%x;", r)
				}
			} else {
				if i0 == -1 {
					i0 = i
				}
				continue
			}
		}
		if i0 != -1 {
			w.WriteString(s[i0:i])
			i0 = -1
		}
		w.WriteString(ws)
	}
	if i0 != -1 {
		w.WriteString(s[i0:])
	}
	return w
}

func (w *htmlOut) children(el *element) *htmlOut {
	return w.elist(el.children)
}
func (w *htmlOut) inline(tag string, el *element) *htmlOut {
	return w.s(tag).children(el).s("</").s(tag[1:])
}
func (w *htmlOut) listBlock(tag string, el *element) *htmlOut {
	return w.sp().s(tag).elist(el.children).br().s("</").s(tag[1:])
}
func (w *htmlOut) listItem(tag string, el *element) *htmlOut {
	return w.br().s(tag).skipPadding().elist(el.children).s("</").s(tag[1:])
}

/* print a list of elements
 */
func (w *htmlOut) elist(list *element) *htmlOut {
	for list != nil {
		w.elem(list)
		list = list.next
	}
	return w
}

// print an element
func (w *htmlOut) elem(elt *element) *htmlOut {
	var s string

	switch elt.key {
	case SPACE:
		s = elt.contents.str
	case LINEBREAK:
		s = "
\n"
	case STR:
		w.str(elt.contents.str)
	case ELLIPSIS:
		s = "…"
	case EMDASH:
		s = "—"
	case ENDASH:
		s = "–"
	case APOSTROPHE:
		s = "’"
	case SINGLEQUOTED:
		w.s("‘").children(elt).s("’")
	case DOUBLEQUOTED:
		w.s("“").children(elt).s("”")
	case CODE:
		w.s("").str(elt.contents.str).s("")
	case HTML:
		s = html.EscapeString(elt.contents.str)
	case LINK:
		o := w.obfuscate
		if strings.Index(elt.contents.link.url, "mailto:") == 0 {
			w.obfuscate = true /* obfuscate mailto: links */
		}
		w.s(`<a href="`).str(elt.contents.link.url).s(`"`)
		if len(elt.contents.link.title) > 0 {
			w.s(` title="`).str(elt.contents.link.title).s(`"`)
		}
		w.s(">").elist(elt.contents.link.label).s("")
		w.obfuscate = o
	case IMAGE:
		w.s(`<img src="`).str(elt.contents.link.url).s(`" alt="`)
		w.elist(elt.contents.link.label).s(`"`)
		if len(elt.contents.link.title) > 0 {
			w.s(` title="`).str(elt.contents.link.title).s(`"`)
		}
		w.s(" />")
	case EMPH:
		w.inline("", elt)
	case STRONG:
		w.inline("", elt)
	case STRIKE:
		w.inline("", elt)
	case LIST:
		w.children(elt)
	case RAW:
		/* Shouldn't occur - these are handled by process_raw_blocks() */
		log.Fatalf("RAW")
	case H1, H2, H3, H4, H5, H6:
		h := "<h" + string('1'+elt.key-H1) + ">" /* assumes H1 ... H6 are in order */
		w.sp().inline(h, elt)
	case PLAIN:
		w.br().children(elt)
	case PARA:
		w.sp().inline("
", elt)
	case HRULE:
		w.sp().s("
")
	case HTMLBLOCK:
		w.sp().s(html.EscapeString(elt.contents.str))
	case VERBATIM:
		w.sp().s("
").str(elt.contents.str).s("
")
	case BULLETLIST:
		w.listBlock("
", elt)
	case ORDEREDLIST:
		w.listBlock("
", elt)
	case DEFINITIONLIST:
		w.listBlock("
", elt)
	case DEFTITLE:
		w.listItem("
", elt)
	case DEFDATA:
		w.listItem("
", elt)
	case LISTITEM:
		w.listItem("
", elt)
	case BLOCKQUOTE:
		w.sp().s("
\n").skipPadding().children(elt).br().s("
")
	case REFERENCE:
		/* Nonprinting */
	case NOTE:
		/* if contents.str == 0, then print note; else ignore, since this
		 * is a note block that has been incorporated into the notes list
		 */
		if elt.contents.str == "" {
			w.endNotes = append(w.endNotes, elt) /* add an endnote to global endnotes list */
			w.notenum++
			nn := w.notenum
			s = fmt.Sprintf(`<a class="noteref" id="fnref%d" href="#fn%d" title="Jump to note %d">[%d]</a>`,
				nn, nn, nn, nn)
		}
	default:
		log.Fatalf("htmlOut.elem encountered unknown element key = %d\n", elt.key)
	}
	if s != "" {
		w.s(s)
	}
	return w
}

func (w *htmlOut) printEndnotes() {
	counter := 0

	w.s("
\n
")
	for _, elt := range w.endNotes {
		counter++
		w.br().s(fmt.Sprintf("
\n", counter)).skipPadding()
		w.children(elt)
		w.s(fmt.Sprintf(" [back]", counter))
		w.br().s("
")
	}
	w.br().s("
")
}
<|endoftext|>


<commit_before>// A http.RoundTripper that retries common errors, with convenience constructors.
//
// NOTE: This meant for TEMPORARY, TRANSIENT ERRORS.
// Do not use for waiting on operations or polling of resource state,
// especially if the expected state (operation done, resource ready, etc)
// takes longer to reach than the default client Timeout.
// In those cases, retryTimeDuration(...)/resource.Retry with appropriate timeout
// and error predicates/handling should be used as a wrapper around the request
// instead.
//
// Example Usage:
// For handwritten/Go clients, the retry transport should be provided via
// the main client or a shallow copy of the HTTP resources, depending on the
// API-specific retry predicates.
// Example Usage in Terraform Config:
//	client := oauth2.NewClient(ctx, tokenSource)
//	// Create with default retry predicates
//	client.Transport := NewTransportWithDefaultRetries(client.Transport, defaultTimeout)
//
//	// If API uses just default retry predicates:
//	c.clientCompute, err = compute.NewService(ctx, option.WithHTTPClient(client))
//	...
//	// If API needs custom additional retry predicates:
//	sqlAdminHttpClient := ClientWithAdditionalRetries(client, retryTransport,
//			isTemporarySqlError1,
//			isTemporarySqlError2)
//	c.clientSqlAdmin, err = compute.NewService(ctx, option.WithHTTPClient(sqlAdminHttpClient))
// ...

package google

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"google.golang.org/api/googleapi"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"time"
)

const defaultRetryTransportTimeoutSec = 30

// NewTransportWithDefaultRetries constructs a default retryTransport that will retry common temporary errors
func NewTransportWithDefaultRetries(t http.RoundTripper) *retryTransport {
	return &retryTransport{
		retryPredicates: defaultErrorRetryPredicates,
		internal:        t,
	}
}

// Helper method to create a shallow copy of an HTTP client with a shallow-copied retryTransport
// s.t. the base HTTP transport is the same (i.e. client connection pools are shared, retryPredicates are different)
func ClientWithAdditionalRetries(baseClient *http.Client, baseRetryTransport *retryTransport, predicates ...RetryErrorPredicateFunc) *http.Client {
	copied := *baseClient
	if baseRetryTransport == nil {
		baseRetryTransport = NewTransportWithDefaultRetries(baseClient.Transport)
	}
	copied.Transport = baseRetryTransport.WithAddedPredicates(predicates...)
	return &copied
}

// Returns a shallow copy of the retry transport with additional retry
// predicates but same wrapped http.RoundTripper
func (t *retryTransport) WithAddedPredicates(predicates ...RetryErrorPredicateFunc) *retryTransport {
	copyT := *t
	copyT.retryPredicates = append(t.retryPredicates, predicates...)
	return &copyT
}

type retryTransport struct {
	retryPredicates []RetryErrorPredicateFunc
	internal        http.RoundTripper
}

// RoundTrip implements the RoundTripper interface method.
// It retries the given HTTP request based on the retry predicates
// registered under the retryTransport.
func (t *retryTransport) RoundTrip(req *http.Request) (resp *http.Response, respErr error) {
	// Set timeout to default value.
	ctx := req.Context()
	var ccancel context.CancelFunc
	if _, ok := ctx.Deadline(); !ok {
		ctx, ccancel = context.WithTimeout(ctx, defaultRetryTransportTimeoutSec*time.Second)
		defer func() {
			if ctx.Err() == nil {
				// Cleanup child context created for retry loop if ctx not done.
				ccancel()
			}
		}()
	}

	attempts := 0
	backoff := time.Millisecond * 500
	nextBackoff := time.Millisecond * 500

	log.Printf("[DEBUG] Retry Transport: starting RoundTrip retry loop")
Retry:
	for {
		log.Printf("[DEBUG] Retry Transport: request attempt %d", attempts)

		// Copy the request - we dont want to use the original request as
		// RoundTrip contract says request body can/will be consumed
		newRequest, copyErr := copyHttpRequest(req)
		if copyErr != nil {
			respErr = errwrap.Wrapf("unable to copy invalid http.Request for retry: {{err}}", copyErr)
			break Retry
		}

		// Do the wrapped Roundtrip. This is one request in the retry loop.
		resp, respErr = t.internal.RoundTrip(newRequest)
		attempts++

		retryErr := t.checkForRetryableError(resp, respErr)
		if retryErr == nil {
			log.Printf("[DEBUG] Retry Transport: Stopping retries, last request was successful")
			break Retry
		}
		if !retryErr.Retryable {
			log.Printf("[DEBUG] Retry Transport: Stopping retries, last request failed with non-retryable error: %s", retryErr.Err)
			break Retry
		}

		log.Printf("[DEBUG] Retry Transport: Waiting %s before trying request again", backoff)
		select {
		case <-ctx.Done():
			log.Printf("[DEBUG] Retry Transport: Stopping retries, context done: %v", ctx.Err())
			break Retry
		case <-time.After(backoff):
			log.Printf("[DEBUG] Retry Transport: Finished waiting %s before next retry", backoff)

			// Fibonnaci backoff - 0.5, 1, 1.5, 2.5, 4, 6.5, 10.5, ...
			lastBackoff := backoff
			backoff = backoff + nextBackoff
			nextBackoff = lastBackoff
			continue
		}
	}

	log.Printf("[DEBUG] Retry Transport: Returning after %d attempts", attempts)
	return resp, respErr
}

// copyHttpRequest provides an copy of the given HTTP request for one RoundTrip.
// If the request has a non-empty body (io.ReadCloser), the body is deep copied
// so it can be consumed.
func copyHttpRequest(req *http.Request) (*http.Request, error) {
	newRequest := *req

	if req.Body == nil || req.Body == http.NoBody {
		return &newRequest, nil
	}

	// Helpers like http.NewRequest add a GetBody for copying.
	// If not given, we should reject the request.
	if req.GetBody == nil {
		return nil, errors.New("invalid HTTP request for transport, expected request.GetBody for non-empty Body")
	}

	bd, err := req.GetBody()
	if err != nil {
		return nil, err
	}

	newRequest.Body = bd
	return &newRequest, nil
}

// checkForRetryableError uses the googleapi.CheckResponse util to check for
// errors in the response, and determines whether there is a retryable error.
// in response/response error.
func (t *retryTransport) checkForRetryableError(resp *http.Response, respErr error) *resource.RetryError {
	var errToCheck error

	if respErr != nil {
		errToCheck = respErr
	} else {
		respToCheck := *resp
		// The RoundTrip contract states that the HTTP response/response error
		// returned cannot be edited. We need to consume the Body to check for
		// errors, so we need to create a copy if the Response has a body.
		if resp.Body != nil && resp.Body != http.NoBody {
			// Use httputil.DumpResponse since the only important info is
			// error code and messages in the response body.
			dumpBytes, err := httputil.DumpResponse(resp, true)
			if err != nil {
				return resource.NonRetryableError(fmt.Errorf("unable to check response for error: %v", err))
			}
			respToCheck.Body = ioutil.NopCloser(bytes.NewReader(dumpBytes))
		}
		errToCheck = googleapi.CheckResponse(&respToCheck)
	}

	if isRetryableError(errToCheck, t.retryPredicates...) {
		return resource.RetryableError(errToCheck)
	}
	return resource.NonRetryableError(errToCheck)
}
<commit_msg>Consume original request body from retry transport (#3276) (#396)<commit_after>// A http.RoundTripper that retries common errors, with convenience constructors.
//
// NOTE: This meant for TEMPORARY, TRANSIENT ERRORS.
// Do not use for waiting on operations or polling of resource state,
// especially if the expected state (operation done, resource ready, etc)
// takes longer to reach than the default client Timeout.
// In those cases, retryTimeDuration(...)/resource.Retry with appropriate timeout
// and error predicates/handling should be used as a wrapper around the request
// instead.
//
// Example Usage:
// For handwritten/Go clients, the retry transport should be provided via
// the main client or a shallow copy of the HTTP resources, depending on the
// API-specific retry predicates.
// Example Usage in Terraform Config:
//	client := oauth2.NewClient(ctx, tokenSource)
//	// Create with default retry predicates
//	client.Transport := NewTransportWithDefaultRetries(client.Transport, defaultTimeout)
//
//	// If API uses just default retry predicates:
//	c.clientCompute, err = compute.NewService(ctx, option.WithHTTPClient(client))
//	...
//	// If API needs custom additional retry predicates:
//	sqlAdminHttpClient := ClientWithAdditionalRetries(client, retryTransport,
//			isTemporarySqlError1,
//			isTemporarySqlError2)
//	c.clientSqlAdmin, err = compute.NewService(ctx, option.WithHTTPClient(sqlAdminHttpClient))
// ...

package google

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"google.golang.org/api/googleapi"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"time"
)

const defaultRetryTransportTimeoutSec = 30

// NewTransportWithDefaultRetries constructs a default retryTransport that will retry common temporary errors
func NewTransportWithDefaultRetries(t http.RoundTripper) *retryTransport {
	return &retryTransport{
		retryPredicates: defaultErrorRetryPredicates,
		internal:        t,
	}
}

// Helper method to create a shallow copy of an HTTP client with a shallow-copied retryTransport
// s.t. the base HTTP transport is the same (i.e. client connection pools are shared, retryPredicates are different)
func ClientWithAdditionalRetries(baseClient *http.Client, baseRetryTransport *retryTransport, predicates ...RetryErrorPredicateFunc) *http.Client {
	copied := *baseClient
	if baseRetryTransport == nil {
		baseRetryTransport = NewTransportWithDefaultRetries(baseClient.Transport)
	}
	copied.Transport = baseRetryTransport.WithAddedPredicates(predicates...)
	return &copied
}

// Returns a shallow copy of the retry transport with additional retry
// predicates but same wrapped http.RoundTripper
func (t *retryTransport) WithAddedPredicates(predicates ...RetryErrorPredicateFunc) *retryTransport {
	copyT := *t
	copyT.retryPredicates = append(t.retryPredicates, predicates...)
	return &copyT
}

type retryTransport struct {
	retryPredicates []RetryErrorPredicateFunc
	internal        http.RoundTripper
}

// RoundTrip implements the RoundTripper interface method.
// It retries the given HTTP request based on the retry predicates
// registered under the retryTransport.
func (t *retryTransport) RoundTrip(req *http.Request) (resp *http.Response, respErr error) {
	// Set timeout to default value.
	ctx := req.Context()
	var ccancel context.CancelFunc
	if _, ok := ctx.Deadline(); !ok {
		ctx, ccancel = context.WithTimeout(ctx, defaultRetryTransportTimeoutSec*time.Second)
		defer func() {
			if ctx.Err() == nil {
				// Cleanup child context created for retry loop if ctx not done.
				ccancel()
			}
		}()
	}

	attempts := 0
	backoff := time.Millisecond * 500
	nextBackoff := time.Millisecond * 500

	log.Printf("[DEBUG] Retry Transport: starting RoundTrip retry loop")
Retry:
	for {
		log.Printf("[DEBUG] Retry Transport: request attempt %d", attempts)

		// Copy the request - we dont want to use the original request as
		// RoundTrip contract says request body can/will be consumed
		newRequest, copyErr := copyHttpRequest(req)
		if copyErr != nil {
			respErr = errwrap.Wrapf("unable to copy invalid http.Request for retry: {{err}}", copyErr)
			break Retry
		}

		// Do the wrapped Roundtrip. This is one request in the retry loop.
		resp, respErr = t.internal.RoundTrip(newRequest)
		attempts++

		retryErr := t.checkForRetryableError(resp, respErr)
		if retryErr == nil {
			log.Printf("[DEBUG] Retry Transport: Stopping retries, last request was successful")
			break Retry
		}
		if !retryErr.Retryable {
			log.Printf("[DEBUG] Retry Transport: Stopping retries, last request failed with non-retryable error: %s", retryErr.Err)
			break Retry
		}

		log.Printf("[DEBUG] Retry Transport: Waiting %s before trying request again", backoff)
		select {
		case <-ctx.Done():
			log.Printf("[DEBUG] Retry Transport: Stopping retries, context done: %v", ctx.Err())
			break Retry
		case <-time.After(backoff):
			log.Printf("[DEBUG] Retry Transport: Finished waiting %s before next retry", backoff)

			// Fibonnaci backoff - 0.5, 1, 1.5, 2.5, 4, 6.5, 10.5, ...
			lastBackoff := backoff
			backoff = backoff + nextBackoff
			nextBackoff = lastBackoff
			continue
		}
	}

	// VCR depends on the original request body being consumed, so consume it here
	_, err := httputil.DumpRequestOut(req, true)
	if err != nil {
		log.Printf("[DEBUG] Retry Transport: Reading request failed: %v", err)
	}

	log.Printf("[DEBUG] Retry Transport: Returning after %d attempts", attempts)
	return resp, respErr
}

// copyHttpRequest provides an copy of the given HTTP request for one RoundTrip.
// If the request has a non-empty body (io.ReadCloser), the body is deep copied
// so it can be consumed.
func copyHttpRequest(req *http.Request) (*http.Request, error) {
	newRequest := *req

	if req.Body == nil || req.Body == http.NoBody {
		return &newRequest, nil
	}

	// Helpers like http.NewRequest add a GetBody for copying.
	// If not given, we should reject the request.
	if req.GetBody == nil {
		return nil, errors.New("invalid HTTP request for transport, expected request.GetBody for non-empty Body")
	}

	bd, err := req.GetBody()
	if err != nil {
		return nil, err
	}

	newRequest.Body = bd
	return &newRequest, nil
}

// checkForRetryableError uses the googleapi.CheckResponse util to check for
// errors in the response, and determines whether there is a retryable error.
// in response/response error.
func (t *retryTransport) checkForRetryableError(resp *http.Response, respErr error) *resource.RetryError {
	var errToCheck error

	if respErr != nil {
		errToCheck = respErr
	} else {
		respToCheck := *resp
		// The RoundTrip contract states that the HTTP response/response error
		// returned cannot be edited. We need to consume the Body to check for
		// errors, so we need to create a copy if the Response has a body.
		if resp.Body != nil && resp.Body != http.NoBody {
			// Use httputil.DumpResponse since the only important info is
			// error code and messages in the response body.
			dumpBytes, err := httputil.DumpResponse(resp, true)
			if err != nil {
				return resource.NonRetryableError(fmt.Errorf("unable to check response for error: %v", err))
			}
			respToCheck.Body = ioutil.NopCloser(bytes.NewReader(dumpBytes))
		}
		errToCheck = googleapi.CheckResponse(&respToCheck)
	}

	if isRetryableError(errToCheck, t.retryPredicates...) {
		return resource.RetryableError(errToCheck)
	}
	return resource.NonRetryableError(errToCheck)
}
<|endoftext|>


<commit_before>// +build coprocess
// +build lua

package main

/*
#cgo pkg-config: luajit

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "coprocess/sds/sds.h"

#include "coprocess/api.h"

#include "coprocess/lua/binding.h"

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

static void LuaInit() {
  // TODO: Cache the middlewares.
}

static struct CoProcessMessage* LuaDispatchHook(struct CoProcessMessage* object) {

  struct CoProcessMessage* outputObject = malloc(sizeof *outputObject);

  lua_State *L = luaL_newstate();

  luaL_openlibs(L);
  luaL_dofile(L, "coprocess/lua/tyk/core.lua");

  lua_getglobal(L, "dispatch");
  lua_pushlstring(L, object->p_data, object->length);
  lua_pcall(L, 1, 1, 0);

  size_t lua_output_length = lua_tointeger(L, 0);
  const char* lua_output_data = lua_tolstring(L, 1, &lua_output_length);

  char* output = malloc(lua_output_length);
  memmove(output, lua_output_data, lua_output_length);

  lua_close(L);

  outputObject->p_data = (void*)output;
  outputObject->length = lua_output_length;

  return outputObject;
}
*/
import "C"

import(
  "unsafe"

  "github.com/TykTechnologies/tyk/coprocess"
  "github.com/Sirupsen/logrus"
)

// CoProcessName declares the driver name.
const CoProcessName string = "lua"

// LuaDispatcher implements a coprocess.Dispatcher
type LuaDispatcher struct {
	coprocess.Dispatcher
}

// Dispatch takes a CoProcessMessage and sends it to the CP.
func (d *LuaDispatcher) Dispatch(objectPtr unsafe.Pointer) unsafe.Pointer {
	var object *C.struct_CoProcessMessage
	object = (*C.struct_CoProcessMessage)(objectPtr)

	var newObjectPtr *C.struct_CoProcessMessage
	newObjectPtr = C.LuaDispatchHook(object)

	return unsafe.Pointer(newObjectPtr)
}

func LuaInit() {
  C.LuaInit()
}

// NewCoProcessDispatcher wraps all the actions needed for this CP.
func NewCoProcessDispatcher() (dispatcher coprocess.Dispatcher, err error) {

  LuaInit()

  dispatcher, err = &LuaDispatcher{}, nil

	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error(err)
	}

	return dispatcher, err
}
<commit_msg>Use JSON for Lua CP.<commit_after>// +build coprocess
// +build lua

package main

/*
#cgo pkg-config: luajit

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "coprocess/sds/sds.h"

#include "coprocess/api.h"

#include "coprocess/lua/binding.h"

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

static void LuaInit() {
  // TODO: Cache the middlewares.
}

static struct CoProcessMessage* LuaDispatchHook(struct CoProcessMessage* object) {

  struct CoProcessMessage* outputObject = malloc(sizeof *outputObject);

  lua_State *L = luaL_newstate();

  luaL_openlibs(L);
  luaL_dofile(L, "coprocess/lua/tyk/core.lua");

  lua_getglobal(L, "dispatch");
  lua_pushlstring(L, object->p_data, object->length);
  lua_pcall(L, 1, 1, 0);

  size_t lua_output_length = lua_tointeger(L, 0);
  const char* lua_output_data = lua_tolstring(L, 1, &lua_output_length);

  char* output = malloc(lua_output_length);
  memmove(output, lua_output_data, lua_output_length);

  lua_close(L);

  outputObject->p_data = (void*)output;
  outputObject->length = lua_output_length;

  return outputObject;
}
*/
import "C"

import(
  "unsafe"

  "github.com/TykTechnologies/tyk/coprocess"
  "github.com/Sirupsen/logrus"
)

// CoProcessName declares the driver name.
const CoProcessName string = "lua"

// MessageType sets the default message type.
var MessageType = coprocess.JsonMessage

// LuaDispatcher implements a coprocess.Dispatcher
type LuaDispatcher struct {
	coprocess.Dispatcher
}

// Dispatch takes a CoProcessMessage and sends it to the CP.
func (d *LuaDispatcher) Dispatch(objectPtr unsafe.Pointer) unsafe.Pointer {
	var object *C.struct_CoProcessMessage
	object = (*C.struct_CoProcessMessage)(objectPtr)

	var newObjectPtr *C.struct_CoProcessMessage
	newObjectPtr = C.LuaDispatchHook(object)

	return unsafe.Pointer(newObjectPtr)
}

func LuaInit() {
  C.LuaInit()
}

// NewCoProcessDispatcher wraps all the actions needed for this CP.
func NewCoProcessDispatcher() (dispatcher coprocess.Dispatcher, err error) {

  LuaInit()

  dispatcher, err = &LuaDispatcher{}, nil

	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error(err)
	}

	return dispatcher, err
}
<|endoftext|>


<commit_before>package slack

import (
	"fmt"

	"github.com/go-chat-bot/bot"
	"github.com/nlopes/slack"
)

var (
	rtm *slack.RTM
	api *slack.Client
)

func responseHandler(target string, message string, sender *bot.User) {
	rtm.SendMessage(rtm.NewOutgoingMessage(message, target))
}

// Extracts user information from slack API
func extractUser(userID string) *bot.User {
	slackUser, err := api.GetUserInfo(userID)
	if err != nil {
		fmt.Printf("Error retrieving slack user: %s\n", err)
		return &bot.User{Nick: userID}
	}
	return &bot.User{Nick: userID, RealName: slackUser.Profile.RealName}
}

// Run connects to slack RTM API using the provided token
func Run(token string) {
	api = slack.New(token)
	rtm = api.NewRTM()

	b := bot.New(&bot.Handlers{
		Response: responseHandler,
	})

	go rtm.ManageConnection()

Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch ev := msg.Data.(type) {
			case *slack.MessageEvent:
				b.MessageReceived(ev.Channel, ev.Text, extractUser(ev.User))

			case *slack.RTMError:
				fmt.Printf("Error: %s\n", ev.Error())

			case *slack.InvalidAuthEvent:
				fmt.Printf("Invalid credentials")
				break Loop
			}
		}
	}
}
<commit_msg>* Updated slack's extractUser to send return the nickname instead of the id<commit_after>package slack

import (
	"fmt"

	"github.com/go-chat-bot/bot"
	"github.com/nlopes/slack"
)

var (
	rtm *slack.RTM
	api *slack.Client
)

func responseHandler(target string, message string, sender *bot.User) {
	rtm.SendMessage(rtm.NewOutgoingMessage(message, target))
}

// Extracts user information from slack API
func extractUser(userID string) *bot.User {
	slackUser, err := api.GetUserInfo(userID)
	if err != nil {
		fmt.Printf("Error retrieving slack user: %s\n", err)
		return &bot.User{Nick: userID}
	}
	return &bot.User{Nick: slackUser.Name, RealName: slackUser.Profile.RealName}
}

// Run connects to slack RTM API using the provided token
func Run(token string) {
	api = slack.New(token)
	rtm = api.NewRTM()

	b := bot.New(&bot.Handlers{
		Response: responseHandler,
	})

	go rtm.ManageConnection()

Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch ev := msg.Data.(type) {
			case *slack.MessageEvent:
				b.MessageReceived(ev.Channel, ev.Text, extractUser(ev.User))

			case *slack.RTMError:
				fmt.Printf("Error: %s\n", ev.Error())

			case *slack.InvalidAuthEvent:
				fmt.Printf("Invalid credentials")
				break Loop
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/dragonfi/go-retro/snake/arena"
	"github.com/nsf/termbox-go"
	"math/rand"
	"time"
)

func putString(x, y int, s string) {
	for i, r := range s {
		termbox.SetCell(x+i, y, r, 0, 0)
	}
}

type Position struct {
	X, Y int
}

type ArenaWidget struct {
	arena  arena.Arena
	offset Position
	size   Position
	state  arena.State
}

func (w *ArenaWidget) Tick() {
	w.arena.Tick()
	w.state = w.arena.State()
}

func (w *ArenaWidget) SetSnakeHeading(direction arena.Direction) {
	w.arena.SetSnakeHeading(0, direction)
}

func (w ArenaWidget) setCell(x, y int, r rune, fg, bg termbox.Attribute) {
	termbox.SetCell(w.offset.X+x, w.offset.Y+y, r, fg, bg)
}

func (w ArenaWidget) putString(x, y int, str string) {
	putString(w.offset.X+x, w.offset.Y+y, str)
}

func (w ArenaWidget) drawBorder() {
	s := w.state
	for i := -1; i <= s.Size.X; i++ {
		for j := -1; j <= s.Size.Y; j++ {
			if i == -1 || i == s.Size.X || j == -1 || j == s.Size.Y {
				w.setCell(i, j, '#', 0, 0)
			}
		}
	}
}

func (w ArenaWidget) drawSnakes() {
	for _, snake := range w.state.Snakes {
		w.drawSnake(snake)
	}
}
func (w ArenaWidget) drawSnake(snake arena.Snake) {
	for _, p := range snake.Segments {
		w.setCell(p.X, p.Y, '#', 0, 0)
	}
}

func (w ArenaWidget) drawPointItem() {
	p := w.state.PointItem
	w.setCell(p.X, p.Y, '*', 0, 0)
}

func (w ArenaWidget) putGameOverText() {
	s := w.state
	w.putString(s.Size.X/2-9, s.Size.Y/2-3, "##################")
	w.putString(s.Size.X/2-9, s.Size.Y/2-2, "#    Game Over   #")
	w.putString(s.Size.X/2-9, s.Size.Y/2-1, "#                #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+0, "# Enter: Restart #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+1, "# ESC: Exit      #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+2, "##################")
}

func (w ArenaWidget) putScore() {
	s := w.state
	for i, snake := range s.Snakes {
		w.putString(1, 1+i, fmt.Sprintf("Score: %d", len(snake.Segments)))
	}
}

func (w ArenaWidget) Draw() {
	w.drawBorder()
	w.putScore()
	w.drawSnakes()
	w.drawPointItem()
	if w.state.GameIsOver {
		w.putGameOverText()
	}
}

func (w *ArenaWidget) ResetArena() {
	w.arena = arena.New(w.size.X, w.size.Y)
	w.arena.AddSnake(w.size.X/2, w.size.Y/2, 5, arena.EAST)
}

func NewArenaWidget(ox, oy, x, y int) ArenaWidget {
	w := ArenaWidget{offset: Position{ox, oy}, size: Position{x, y}}
	w.ResetArena()
	return w
}

func eventChannel() <-chan termbox.Event {
	events := make(chan termbox.Event)
	go func() {
		for {
			events <- termbox.PollEvent()
		}
	}()
	return events
}

func main() {
	rand.Seed(time.Now().UnixNano())
	termbox.Init()
	defer termbox.Close()
	x, y := termbox.Size()
	offsetx, offsety := 2, 2
	aw := NewArenaWidget(offsetx, offsety, x-2*offsetx, y-2*offsety)
	tick := time.Tick(100 * time.Millisecond)
	event := eventChannel()
	running := true

	handleKey := map[termbox.Key]func(){
		termbox.KeyEsc:        func() { running = false },
		termbox.KeyEnter:      func() { aw.ResetArena() },
		termbox.KeyArrowRight: func() { aw.SetSnakeHeading(arena.EAST) },
		termbox.KeyArrowUp:    func() { aw.SetSnakeHeading(arena.NORTH) },
		termbox.KeyArrowLeft:  func() { aw.SetSnakeHeading(arena.WEST) },
		termbox.KeyArrowDown:  func() { aw.SetSnakeHeading(arena.SOUTH) },
	}

	for running {
		termbox.Clear(0, 0)
		aw.Draw()
		termbox.Flush()
		select {
		case ev := <-event:
			if ev.Type == termbox.EventKey {
				f := handleKey[ev.Key]
				if f != nil {
					f()
				}
			}
		case <-tick:
			aw.Tick()
		}
	}
}
<commit_msg>Make snake.go into a two player game.<commit_after>package main

import (
	"fmt"
	"github.com/dragonfi/go-retro/snake/arena"
	"github.com/nsf/termbox-go"
	"math/rand"
	"time"
)

func putString(x, y int, s string) {
	for i, r := range s {
		termbox.SetCell(x+i, y, r, 0, 0)
	}
}

type Position struct {
	X, Y int
}

type ArenaWidget struct {
	arena  arena.Arena
	offset Position
	size   Position
	state  arena.State
}

func (w *ArenaWidget) Tick() {
	w.arena.Tick()
	w.state = w.arena.State()
}

func (w *ArenaWidget) SetSnakeHeading(snake int, direction arena.Direction) {
	w.arena.SetSnakeHeading(snake, direction)
}

func (w ArenaWidget) setCell(x, y int, r rune, fg, bg termbox.Attribute) {
	termbox.SetCell(w.offset.X+x, w.offset.Y+y, r, fg, bg)
}

func (w ArenaWidget) putString(x, y int, str string) {
	putString(w.offset.X+x, w.offset.Y+y, str)
}

func (w ArenaWidget) drawBorder() {
	s := w.state
	for i := -1; i <= s.Size.X; i++ {
		for j := -1; j <= s.Size.Y; j++ {
			if i == -1 || i == s.Size.X || j == -1 || j == s.Size.Y {
				w.setCell(i, j, '#', 0, 0)
			}
		}
	}
}

func (w ArenaWidget) drawSnakes() {
	for _, snake := range w.state.Snakes {
		w.drawSnake(snake)
	}
}
func (w ArenaWidget) drawSnake(snake arena.Snake) {
	for _, p := range snake.Segments {
		w.setCell(p.X, p.Y, '#', 0, 0)
	}
}

func (w ArenaWidget) drawPointItem() {
	p := w.state.PointItem
	w.setCell(p.X, p.Y, '*', 0, 0)
}

func (w ArenaWidget) putGameOverText() {
	s := w.state
	w.putString(s.Size.X/2-9, s.Size.Y/2-3, "##################")
	w.putString(s.Size.X/2-9, s.Size.Y/2-2, "#    Game Over   #")
	w.putString(s.Size.X/2-9, s.Size.Y/2-1, "#                #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+0, "# Enter: Restart #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+1, "# ESC: Exit      #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+2, "##################")
}

func (w ArenaWidget) putScore() {
	s := w.state
	for i, snake := range s.Snakes {
		w.putString(1, 1+i, fmt.Sprintf("Score: %d", len(snake.Segments)))
	}
}

func (w ArenaWidget) Draw() {
	w.drawBorder()
	w.putScore()
	w.drawSnakes()
	w.drawPointItem()
	if w.state.GameIsOver {
		w.putGameOverText()
	}
}

func (w *ArenaWidget) ResetArena() {
	w.arena = arena.New(w.size.X, w.size.Y)
	w.arena.AddSnake(w.size.X/2, w.size.Y/2, 5, arena.EAST)
	w.arena.AddSnake(w.size.X/3, w.size.Y/3, 5, arena.EAST)
}

func NewArenaWidget(ox, oy, x, y int) ArenaWidget {
	w := ArenaWidget{offset: Position{ox, oy}, size: Position{x, y}}
	w.ResetArena()
	return w
}

func eventChannel() <-chan termbox.Event {
	events := make(chan termbox.Event)
	go func() {
		for {
			events <- termbox.PollEvent()
		}
	}()
	return events
}

func main() {
	rand.Seed(time.Now().UnixNano())
	termbox.Init()
	defer termbox.Close()
	x, y := termbox.Size()
	offsetx, offsety := 2, 2
	aw := NewArenaWidget(offsetx, offsety, x-2*offsetx, y-2*offsety)
	tick := time.Tick(100 * time.Millisecond)
	event := eventChannel()
	running := true

	handleKey := map[termbox.Key]func(){
		termbox.KeyEsc:        func() { running = false },
		termbox.KeyEnter:      func() { aw.ResetArena() },
		termbox.KeyArrowRight: func() { aw.SetSnakeHeading(0, arena.EAST) },
		termbox.KeyArrowUp:    func() { aw.SetSnakeHeading(0, arena.NORTH) },
		termbox.KeyArrowLeft:  func() { aw.SetSnakeHeading(0, arena.WEST) },
		termbox.KeyArrowDown:  func() { aw.SetSnakeHeading(0, arena.SOUTH) },
	}

	handleCh := map[rune]func(){
		'D': func() { aw.SetSnakeHeading(1, arena.EAST) },
		'W': func() { aw.SetSnakeHeading(1, arena.NORTH) },
		'A': func() { aw.SetSnakeHeading(1, arena.WEST) },
		'S': func() { aw.SetSnakeHeading(1, arena.SOUTH) },
		'd': func() { aw.SetSnakeHeading(1, arena.EAST) },
		'w': func() { aw.SetSnakeHeading(1, arena.NORTH) },
		'a': func() { aw.SetSnakeHeading(1, arena.WEST) },
		's': func() { aw.SetSnakeHeading(1, arena.SOUTH) },
	}

	for running {
		termbox.Clear(0, 0)
		aw.Draw()
		termbox.Flush()
		select {
		case ev := <-event:
			if ev.Type == termbox.EventKey {
				f := handleCh[ev.Ch]
				if ev.Ch == 0 {
					f = handleKey[ev.Key]
				}
				if f != nil {
					f()
				}
			}
		case <-tick:
			aw.Tick()
		}
	}
}
<|endoftext|>