<commit_before>package argot

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"

	"github.com/xeipuuv/gojsonschema"
)

// HttpCall captures all the state relating to a single HTTP call. It
// may be used multiple times. An HttpCall can only be used by a
// single go-routine at a time.
type HttpCall struct {
	// The client used to perform the request.
	Client *http.Client
	// The request to be made.
	Request *http.Request
	// The response.
	Response *http.Response
	// The body which once received can be repeatedly reused.
	ResponseBody []byte
}

// NewHttpCall creates a new HttpCall. If client is nil, a new
// http.Client is used.
func NewHttpCall(client *http.Client) *HttpCall {
	if client == nil {
		client = new(http.Client)
	}
	return &HttpCall{
		Client: client,
	}
}

// AssertNoRequest returns nil iff hc.Request is nil.
func (hc *HttpCall) AssertNoRequest() error {
	if hc.Request == nil {
		return nil
	} else {
		return errors.New("Request already set")
	}
}

// AssertRequest returns nil iff hc.Request is non-nil.
func (hc *HttpCall) AssertRequest() error {
	if hc.Request == nil {
		return errors.New("No Request set")
	} else {
		return nil
	}
}

// AssertNoResponse returns nil iff hc.Response is nil.
func (hc *HttpCall) AssertNoResponse() error {
	if hc.Response == nil {
		return nil
	} else {
		return errors.New("Response already set")
	}
}

// EnsureResponse is idempotent. If there is already a response then
// it will return nil. Otherwise if there is no Request then it will
// return non-nil. Otherwise it will use hc.Client.Do to perform the
// request, set hc.Response, and return any error that occurs.
//
// Always use this in any step where you want to inspect the
// hc.Response.
func (hc *HttpCall) EnsureResponse() error {
	if hc.Response != nil {
		return nil
	} else if hc.Request == nil {
		return errors.New("Cannot ensure response: no request.")
	} else if response, err := hc.Client.Do(hc.Request); err != nil {
		return fmt.Errorf("Error when making call of %v: %v", hc.Request, err)
	} else {
		hc.Response = response
		return nil
	}
}

// ReceiveBody is idempotent. It will ensure there is a response using
// hc.EnsureResponse. If there is already a non-nil hc.ResponseBody
// then it will return nil. Otherwise it will receive the
// Response.Body, store it in hc.ResponseBody, and return any error
// that occurs.
//
// Always use this in any step where you want to inspect the
// hc.ResponseBody.
func (hc *HttpCall) ReceiveBody() error {
	if err := hc.EnsureResponse(); err != nil {
		return err
	} else if hc.ResponseBody != nil {
		return nil
	} else {
		defer hc.Response.Body.Close()
		bites := new(bytes.Buffer)
		if _, err = io.Copy(bites, hc.Response.Body); err != nil {
			return err
		} else {
			hc.ResponseBody = bites.Bytes()
			return nil
		}
	}
}

// Reset is idempotent. You should ensure this is called at the end of
// life for each HttpCall. It drains Response bodies if necessary, and
// cleans up resources.
func (hc *HttpCall) Reset() error {
	hc.Request = nil
	if hc.Response != nil && hc.ResponseBody == nil {
		io.Copy(ioutil.Discard, hc.Response.Body)
		hc.Response.Body.Close()
	}
	hc.Response = nil
	hc.ResponseBody = nil
	return nil
}

// NewRequest is a Step that when executed will create a new request
// using the given parameters. The step will automatically call
// hc.Reset to tidy up any previous use of hc, and thus prepare hc for
// the new request.
func (hc *HttpCall) NewRequest(method, urlStr string, body io.Reader) Step {
	return NewNamedStep(fmt.Sprintf("NewRequest(%s: %s)", method, urlStr), func() error {
		if err := hc.Reset(); err != nil {
			return err
		} else if req, err := http.NewRequest(method, urlStr, body); err != nil {
			return err
		} else {
			hc.Request = req
			return nil
		}
	})
}

// RequestHeader is a Step that when executed will set the given key
// and value as a header on the HTTP Request. This can only be done
// after hc.Request has been created (with NewRequest), and before
// hc.Response has been created.
func (hc *HttpCall) RequestHeader(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("RequestHeader(%s: %s)", key, value), func() error {
		if err := AnyError(hc.AssertRequest(), hc.AssertNoResponse()); err != nil {
			return err
		} else {
			hc.Request.Header.Set(key, value)
			return nil
		}
	})
}

// Call is a Step that when executed performs the HTTP Request
// Call. This is not normally necessary: all steps that require a
// Response will perform the HTTP Request when necessary. However, in
// some tests, you may not care about inspecting the HTTP Response but
// nevertheless wish the HTTP Request to be made.
func (hc *HttpCall) Call() Step {
	return NewNamedStep("Call", hc.EnsureResponse)
}

// ResponseStatusEquals is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless the hc.Response.StatusCode
// equals the status parameter.
func (hc *HttpCall) ResponseStatusEquals(status int) Step {
	return NewNamedStep(fmt.Sprintf("ResponseStatusEquals(%d)", status), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if hc.Response.StatusCode != status {
			return fmt.Errorf("Status: Expected %d; found %d.", status, hc.Response.StatusCode)
		} else {
			return nil
		}
	})
}

// ResponseHeaderExists is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless hc.Response.Header[key]
// exists. It says nothing about the value of the header.
func (hc *HttpCall) ResponseHeaderExists(key string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderExists(%s)", key), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if _, found := hc.Response.Header[key]; !found {
			return fmt.Errorf("Header '%s' not found.", key)
		} else {
			return nil
		}
	})
}

// ResponseHeaderNotExists is a Step that when executed ensures there
// is a non-nil hc.Response and errors unless hc.Response.Header[key]
// does not exist.
func (hc *HttpCall) ResponseHeaderNotExists(key string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderNotExists(%s)", key), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if _, found := hc.Response.Header[key]; found {
			return fmt.Errorf("Header '%s' found.", key)
		} else {
			return nil
		}
	})
}

// ResponseHeaderEquals is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless the
// hc.Response.Header.Get(key) equals the value parameter. Note this
// is an exact match.
func (hc *HttpCall) ResponseHeaderEquals(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderEquals(%s: %s)", key, value), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if header := hc.Response.Header.Get(key); header != value {
			return fmt.Errorf("Header '%s': Expected '%s'; found '%s'.", key, value, header)
		} else {
			return nil
		}
	})
}

// ResponseHeaderContains is a Step that when executed ensures there
// is a non-nil hc.Response and errors unless the
// hc.Response.Header.Get(key) contains the value parameter using
// strings.Contains.
func (hc *HttpCall) ResponseHeaderContains(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderContains(%s: %s)", key, value), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if header := hc.Response.Header.Get(key); !strings.Contains(header, value) {
			return fmt.Errorf("Header '%s': Expected '%s'; found '%s'.", key, value, header)
		} else {
			return nil
		}
	})
}

// ResponseBodyEquals is a Step that when executed ensures there is a
// non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// equals the value parameter. Note this is an exact match.
func (hc *HttpCall) ResponseBodyEquals(value string) Step {
	return NewNamedStep("ResponseBodyEquals", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if string(hc.ResponseBody) != value {
			return fmt.Errorf("Body: Expected '%s'; found '%s'.", value, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyContains is a Step that when executed ensures there is
// a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// contains the value parameter using strings.Contains.
func (hc *HttpCall) ResponseBodyContains(value string) Step {
	return NewNamedStep("ResponseBodyContains", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if !strings.Contains(string(hc.ResponseBody), value) {
			return fmt.Errorf("Body: Expected '%s'; found '%s'.", value, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyMatches is a Step that when executed ensures there is
// a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// matches the regular expression parameter.
func (hc *HttpCall) ResponseBodyMatches(pattern *regexp.Regexp) Step {
	return NewNamedStep(fmt.Sprintf("ResponseBodyMatches(%v)", pattern), func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if !pattern.MatchString(string(hc.ResponseBody)) {
			return fmt.Errorf("Body: Expected to match the pattern '%v'; found '%s'.", pattern, string(hc.ResponseBody))
		}
		return nil
	})
}

// ResponseBodyJSONSchema is a Step that when executed ensures there
// is a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// can be validated against the schema parameter using gojsonschema.
func (hc *HttpCall) ResponseBodyJSONSchema(schema string) Step {
	return NewNamedStep("ResponseBodyJSONSchema", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else {
			schemaLoader := gojsonschema.NewStringLoader(schema)
			bodyLoader := gojsonschema.NewStringLoader(string(hc.ResponseBody))
			if result, err := gojsonschema.Validate(schemaLoader, bodyLoader); err != nil {
				return err
			} else if !result.Valid() {
				msg := "Validation failure:\n"
				for _, err := range result.Errors() {
					msg += fmt.Sprintf("\t%v\n", err)
				}
				return errors.New(msg[:len(msg)-1])
			} else {
				return nil
			}
		}
	})
}
<commit_msg>Use an else block<commit_after>package argot

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"

	"github.com/xeipuuv/gojsonschema"
)

// HttpCall captures all the state relating to a single HTTP call. It
// may be used multiple times. An HttpCall can only be used by a
// single go-routine at a time.
type HttpCall struct {
	// The client used to perform the request.
	Client *http.Client
	// The request to be made.
	Request *http.Request
	// The response.
	Response *http.Response
	// The body which once received can be repeatedly reused.
	ResponseBody []byte
}

// NewHttpCall creates a new HttpCall. If client is nil, a new
// http.Client is used.
func NewHttpCall(client *http.Client) *HttpCall {
	if client == nil {
		client = new(http.Client)
	}
	return &HttpCall{
		Client: client,
	}
}

// AssertNoRequest returns nil iff hc.Request is nil.
func (hc *HttpCall) AssertNoRequest() error {
	if hc.Request == nil {
		return nil
	} else {
		return errors.New("Request already set")
	}
}

// AssertRequest returns nil iff hc.Request is non-nil.
func (hc *HttpCall) AssertRequest() error {
	if hc.Request == nil {
		return errors.New("No Request set")
	} else {
		return nil
	}
}

// AssertNoResponse returns nil iff hc.Response is nil.
func (hc *HttpCall) AssertNoResponse() error {
	if hc.Response == nil {
		return nil
	} else {
		return errors.New("Response already set")
	}
}

// EnsureResponse is idempotent. If there is already a response then
// it will return nil. Otherwise if there is no Request then it will
// return non-nil. Otherwise it will use hc.Client.Do to perform the
// request, set hc.Response, and return any error that occurs.
//
// Always use this in any step where you want to inspect the
// hc.Response.
func (hc *HttpCall) EnsureResponse() error {
	if hc.Response != nil {
		return nil
	} else if hc.Request == nil {
		return errors.New("Cannot ensure response: no request.")
	} else if response, err := hc.Client.Do(hc.Request); err != nil {
		return fmt.Errorf("Error when making call of %v: %v", hc.Request, err)
	} else {
		hc.Response = response
		return nil
	}
}

// ReceiveBody is idempotent. It will ensure there is a response using
// hc.EnsureResponse. If there is already a non-nil hc.ResponseBody
// then it will return nil. Otherwise it will receive the
// Response.Body, store it in hc.ResponseBody, and return any error
// that occurs.
//
// Always use this in any step where you want to inspect the
// hc.ResponseBody.
func (hc *HttpCall) ReceiveBody() error {
	if err := hc.EnsureResponse(); err != nil {
		return err
	} else if hc.ResponseBody != nil {
		return nil
	} else {
		defer hc.Response.Body.Close()
		bites := new(bytes.Buffer)
		if _, err = io.Copy(bites, hc.Response.Body); err != nil {
			return err
		} else {
			hc.ResponseBody = bites.Bytes()
			return nil
		}
	}
}

// Reset is idempotent. You should ensure this is called at the end of
// life for each HttpCall. It drains Response bodies if necessary, and
// cleans up resources.
func (hc *HttpCall) Reset() error {
	hc.Request = nil
	if hc.Response != nil && hc.ResponseBody == nil {
		io.Copy(ioutil.Discard, hc.Response.Body)
		hc.Response.Body.Close()
	}
	hc.Response = nil
	hc.ResponseBody = nil
	return nil
}

// NewRequest is a Step that when executed will create a new request
// using the given parameters. The step will automatically call
// hc.Reset to tidy up any previous use of hc, and thus prepare hc for
// the new request.
func (hc *HttpCall) NewRequest(method, urlStr string, body io.Reader) Step {
	return NewNamedStep(fmt.Sprintf("NewRequest(%s: %s)", method, urlStr), func() error {
		if err := hc.Reset(); err != nil {
			return err
		} else if req, err := http.NewRequest(method, urlStr, body); err != nil {
			return err
		} else {
			hc.Request = req
			return nil
		}
	})
}

// RequestHeader is a Step that when executed will set the given key
// and value as a header on the HTTP Request. This can only be done
// after hc.Request has been created (with NewRequest), and before
// hc.Response has been created.
func (hc *HttpCall) RequestHeader(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("RequestHeader(%s: %s)", key, value), func() error {
		if err := AnyError(hc.AssertRequest(), hc.AssertNoResponse()); err != nil {
			return err
		} else {
			hc.Request.Header.Set(key, value)
			return nil
		}
	})
}

// Call is a Step that when executed performs the HTTP Request
// Call. This is not normally necessary: all steps that require a
// Response will perform the HTTP Request when necessary. However, in
// some tests, you may not care about inspecting the HTTP Response but
// nevertheless wish the HTTP Request to be made.
func (hc *HttpCall) Call() Step {
	return NewNamedStep("Call", hc.EnsureResponse)
}

// ResponseStatusEquals is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless the hc.Response.StatusCode
// equals the status parameter.
func (hc *HttpCall) ResponseStatusEquals(status int) Step {
	return NewNamedStep(fmt.Sprintf("ResponseStatusEquals(%d)", status), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if hc.Response.StatusCode != status {
			return fmt.Errorf("Status: Expected %d; found %d.", status, hc.Response.StatusCode)
		} else {
			return nil
		}
	})
}

// ResponseHeaderExists is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless hc.Response.Header[key]
// exists. It says nothing about the value of the header.
func (hc *HttpCall) ResponseHeaderExists(key string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderExists(%s)", key), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if _, found := hc.Response.Header[key]; !found {
			return fmt.Errorf("Header '%s' not found.", key)
		} else {
			return nil
		}
	})
}

// ResponseHeaderNotExists is a Step that when executed ensures there
// is a non-nil hc.Response and errors unless hc.Response.Header[key]
// does not exist.
func (hc *HttpCall) ResponseHeaderNotExists(key string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderNotExists(%s)", key), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if _, found := hc.Response.Header[key]; found {
			return fmt.Errorf("Header '%s' found.", key)
		} else {
			return nil
		}
	})
}

// ResponseHeaderEquals is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless the
// hc.Response.Header.Get(key) equals the value parameter. Note this
// is an exact match.
func (hc *HttpCall) ResponseHeaderEquals(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderEquals(%s: %s)", key, value), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if header := hc.Response.Header.Get(key); header != value {
			return fmt.Errorf("Header '%s': Expected '%s'; found '%s'.", key, value, header)
		} else {
			return nil
		}
	})
}

// ResponseHeaderContains is a Step that when executed ensures there
// is a non-nil hc.Response and errors unless the
// hc.Response.Header.Get(key) contains the value parameter using
// strings.Contains.
func (hc *HttpCall) ResponseHeaderContains(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderContains(%s: %s)", key, value), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if header := hc.Response.Header.Get(key); !strings.Contains(header, value) {
			return fmt.Errorf("Header '%s': Expected '%s'; found '%s'.", key, value, header)
		} else {
			return nil
		}
	})
}

// ResponseBodyEquals is a Step that when executed ensures there is a
// non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// equals the value parameter. Note this is an exact match.
func (hc *HttpCall) ResponseBodyEquals(value string) Step {
	return NewNamedStep("ResponseBodyEquals", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if string(hc.ResponseBody) != value {
			return fmt.Errorf("Body: Expected '%s'; found '%s'.", value, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyContains is a Step that when executed ensures there is
// a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// contains the value parameter using strings.Contains.
func (hc *HttpCall) ResponseBodyContains(value string) Step {
	return NewNamedStep("ResponseBodyContains", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if !strings.Contains(string(hc.ResponseBody), value) {
			return fmt.Errorf("Body: Expected '%s'; found '%s'.", value, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyMatches is a Step that when executed ensures there is
// a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// matches the regular expression parameter.
func (hc *HttpCall) ResponseBodyMatches(pattern *regexp.Regexp) Step {
	return NewNamedStep(fmt.Sprintf("ResponseBodyMatches(%v)", pattern), func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if !pattern.MatchString(string(hc.ResponseBody)) {
			return fmt.Errorf("Body: Expected to match the pattern '%v'; found '%s'.", pattern, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyJSONSchema is a Step that when executed ensures there
// is a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// can be validated against the schema parameter using gojsonschema.
func (hc *HttpCall) ResponseBodyJSONSchema(schema string) Step {
	return NewNamedStep("ResponseBodyJSONSchema", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else {
			schemaLoader := gojsonschema.NewStringLoader(schema)
			bodyLoader := gojsonschema.NewStringLoader(string(hc.ResponseBody))
			if result, err := gojsonschema.Validate(schemaLoader, bodyLoader); err != nil {
				return err
			} else if !result.Valid() {
				msg := "Validation failure:\n"
				for _, err := range result.Errors() {
					msg += fmt.Sprintf("\t%v\n", err)
				}
				return errors.New(msg[:len(msg)-1])
			} else {
				return nil
			}
		}
	})
}
<|endoftext|>


<commit_before>package http

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/textproto"
	"net/url"
	"strings"
	"time"

	"github.com/gopherjs/gopherjs/js"

	"honnef.co/go/js/xhr"
)

type Client struct {
	Timeout time.Duration
}

var DefaultClient = Client{}

func (c *Client) Do(req *http.Request) (*http.Response, error) {
	var err error
	x := xhr.NewRequest(req.Method, req.URL.String())
	x.ResponseType = xhr.ArrayBuffer
	if c.Timeout > 0 {
		x.Timeout = int(c.Timeout / time.Millisecond)
	}
	for k, v := range req.Header {
		for _, vv := range v {
			x.SetRequestHeader(k, vv)
		}
	}
	var data []byte
	if req.Body != nil {
		defer req.Body.Close()
		data, err = ioutil.ReadAll(req.Body)
		if err != nil {
			return nil, err
		}
	}

	// FIXME req.Host

	err = x.Send(data)
	if err != nil {
		return nil, err
	}

	r := strings.NewReader(x.ResponseHeaders())
	headers, err := textproto.NewReader(bufio.NewReader(r)).ReadMIMEHeader()
	if err != nil && err != io.EOF {
		return nil, err
	}

	b := js.Global.Get("Uint8Array").New(x.Response).Interface().([]byte)
	res := &http.Response{
		Status:        fmt.Sprintf("%d %s", x.Status, x.StatusText),
		StatusCode:    x.Status,
		Header:        http.Header(headers),
		Body:          ioutil.NopCloser(bytes.NewReader(b)),
		ContentLength: int64(len(b)),
		// TODO other stuff
	}
	return res, nil
}

func (c *Client) Get(url string) (*http.Response, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	return c.Do(req)
}

func (c *Client) Head(url string) (*http.Response, error) {
	req, err := http.NewRequest("HEAD", url, nil)
	if err != nil {
		return nil, err
	}
	return c.Do(req)
}

func (c *Client) Post(url string, bodyType string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", bodyType)
	return c.Do(req)
}

func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) {
	return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}

func Get(url string) (*http.Response, error) {
	return DefaultClient.Get(url)
}

func Head(url string) (*http.Response, error) {
	return DefaultClient.Head(url)
}

func Post(url string, bodyType string, body io.Reader) (*http.Response, error) {
	return DefaultClient.Post(url, bodyType, body)
}
<commit_msg>add some documentation<commit_after>// Package http is a clone of net/http for GopherJS. It replicates
// most of the net/http.Client API, using XHR in the background, and
// making use of actual types from the net/http package, such as
// net/http.Request and net/http.Response.
//
// At this moment, the future of this package is not yet certain.
// Better solutions might present themselves, in which case this
// package will be removed and replaced with something better. Use at
// your own risk.
package http

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/textproto"
	"net/url"
	"strings"
	"time"

	"github.com/gopherjs/gopherjs/js"

	"honnef.co/go/js/xhr"
)

type Client struct {
	// The amount of time a request can take before it will be
	// terminated. Millisecond precision is supported.
	Timeout time.Duration
}

var DefaultClient = Client{}

func (c *Client) Do(req *http.Request) (*http.Response, error) {
	var err error
	x := xhr.NewRequest(req.Method, req.URL.String())
	x.ResponseType = xhr.ArrayBuffer
	if c.Timeout > 0 {
		x.Timeout = int(c.Timeout / time.Millisecond)
	}
	for k, v := range req.Header {
		for _, vv := range v {
			x.SetRequestHeader(k, vv)
		}
	}
	var data []byte
	if req.Body != nil {
		defer req.Body.Close()
		data, err = ioutil.ReadAll(req.Body)
		if err != nil {
			return nil, err
		}
	}

	// FIXME req.Host

	err = x.Send(data)
	if err != nil {
		return nil, err
	}

	r := strings.NewReader(x.ResponseHeaders())
	headers, err := textproto.NewReader(bufio.NewReader(r)).ReadMIMEHeader()
	if err != nil && err != io.EOF {
		return nil, err
	}

	b := js.Global.Get("Uint8Array").New(x.Response).Interface().([]byte)
	res := &http.Response{
		Status:        fmt.Sprintf("%d %s", x.Status, x.StatusText),
		StatusCode:    x.Status,
		Header:        http.Header(headers),
		Body:          ioutil.NopCloser(bytes.NewReader(b)),
		ContentLength: int64(len(b)),
		// TODO other stuff
	}
	return res, nil
}

func (c *Client) Get(url string) (*http.Response, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	return c.Do(req)
}

func (c *Client) Head(url string) (*http.Response, error) {
	req, err := http.NewRequest("HEAD", url, nil)
	if err != nil {
		return nil, err
	}
	return c.Do(req)
}

func (c *Client) Post(url string, bodyType string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", bodyType)
	return c.Do(req)
}

func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) {
	return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}

func Get(url string) (*http.Response, error) {
	return DefaultClient.Get(url)
}

func Head(url string) (*http.Response, error) {
	return DefaultClient.Head(url)
}

func Post(url string, bodyType string, body io.Reader) (*http.Response, error) {
	return DefaultClient.Post(url, bodyType, body)
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "strconv"
    "net/http"
    "huabot-sched/db"
    "github.com/go-martini/martini"
    "github.com/martini-contrib/render"
    "github.com/martini-contrib/binding"
)

const API = ""

func StartHttpServer(addr string) {
    mart := martini.Classic()
    mart.Use(render.Renderer(render.Options{
        Directory: "templates",
        Layout: "layout",
        Extensions: []string{".tmpl", ".html"},
        Charset: "UTF-8",
        IndentJSON: true,
        IndentXML: true,
        HTMLContentType: "application/xhtml+xml",
    }))

    api(mart)

    mart.RunOnAddr(addr)
}

type JobForm struct {
    Name    string `form:"name" binding:"required"`
    Timeout int    `form:"timeout"`
    SchedAt int    `form:"sched_at" binding:"required"`
}

func api(mart *martini.ClassicMartini) {

    mart.Post(API + "/jobs/", binding.Bind(JobForm{}), func(j JobForm, r render.Render) {
        job := db.Job{
            Name: j.Name,
            Timeout: j.Timeout,
            SchedAt: j.SchedAt,
            Status: "status",
        }
        err := job.Save()
        if err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
            return
        }
        r.JSON(http.StatusOK, map[string]db.Job{"job": job})
    })

    mart.Get(API + "/jobs/(?P<job_id>[0-9]+)", func(params martini.Params, r render.Render) {
        jobId, _ := strconv.Atoi(params["job_id"])
        job, err := db.GetJob(jobId)
        if err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
            return
        }
        r.JSON(http.StatusOK, map[string]db.Job{"job": job})
    })

    mart.Get(API + "/jobs/(?P<status>ready|doing)/", func(params martini.Params, req *http.Request, r render.Render) {
        status := params["status"]
        qs := req.URL.Query()
        var start, limit, stop int
        var err error
        if start, err = strconv.Atoi(qs.Get("start")); err != nil {
            start = 0
        }
        if limit, err = strconv.Atoi(qs.Get("limit")); err != nil {
            limit = 10
        }
        stop = start + limit
        var jobs []db.Job
        var count int
        jobs, err = db.RangeSchedJob(status, start, stop)
        count, _ = db.CountSchedJob(status)
        if err != nil {
            log.Printf("Error: RangeSchedJob error %s\n", err)
            r.JSON(http.StatusOK, map[string]interface{}{"jobs": "[]", "total": count, "current": start})
            return
        }
        r.JSON(http.StatusOK, map[string]interface{}{"jobs": jobs, "total": count, "current": start})
    })

    mart.Get(API + "/jobs/", func(req *http.Request, r render.Render) {
        qs := req.URL.Query()
        var start, limit, stop int
        var err error
        if start, err = strconv.Atoi(qs.Get("start")); err != nil {
            start = 0
        }
        if limit, err = strconv.Atoi(qs.Get("limit")); err != nil {
            limit = 10
        }
        stop = start + limit
        var jobs []db.Job
        var count int
        jobs, err = db.RangeJob(start, stop)
        count, _ = db.CountJob()
        if err != nil {
            log.Printf("Error: RangeSchedJob error %s\n", err)
            r.JSON(http.StatusOK, map[string]interface{}{"jobs": "[]", "total": count, "current": start})
            return
        }
        r.JSON(http.StatusOK, map[string]interface{}{"jobs": jobs, "total": count, "current": start})
    })

    mart.Delete(API + "/jobs/(?P<job_id>[0-9]+)", func(params martini.Params, r render.Render) {
        id, _ := strconv.Atoi(params["job_id"])
        err := db.DelJob(id)
        if err != nil {
            log.Printf("Error: DelJob error %s\n", err)
            r.JSON(http.StatusOK, map[string]interface{}{"err": err.Error()})
            return
        }
        r.JSON(http.StatusNotFound, map[string]interface{}{})
    })
}
<commit_msg>update the default job status<commit_after>package main

import (
    "log"
    "strconv"
    "net/http"
    "huabot-sched/db"
    "github.com/go-martini/martini"
    "github.com/martini-contrib/render"
    "github.com/martini-contrib/binding"
)

const API = ""

func StartHttpServer(addr string) {
    mart := martini.Classic()
    mart.Use(render.Renderer(render.Options{
        Directory: "templates",
        Layout: "layout",
        Extensions: []string{".tmpl", ".html"},
        Charset: "UTF-8",
        IndentJSON: true,
        IndentXML: true,
        HTMLContentType: "application/xhtml+xml",
    }))

    api(mart)

    mart.RunOnAddr(addr)
}

type JobForm struct {
    Name    string `form:"name" binding:"required"`
    Timeout int    `form:"timeout"`
    SchedAt int    `form:"sched_at" binding:"required"`
}

func api(mart *martini.ClassicMartini) {

    mart.Post(API + "/jobs/", binding.Bind(JobForm{}), func(j JobForm, r render.Render) {
        job := db.Job{
            Name: j.Name,
            Timeout: j.Timeout,
            SchedAt: j.SchedAt,
            Status: "ready",
        }
        err := job.Save()
        if err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
            return
        }
        r.JSON(http.StatusOK, map[string]db.Job{"job": job})
    })

    mart.Get(API + "/jobs/(?P<job_id>[0-9]+)", func(params martini.Params, r render.Render) {
        jobId, _ := strconv.Atoi(params["job_id"])
        job, err := db.GetJob(jobId)
        if err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
            return
        }
        r.JSON(http.StatusOK, map[string]db.Job{"job": job})
    })

    mart.Get(API + "/jobs/(?P<status>ready|doing)/", func(params martini.Params, req *http.Request, r render.Render) {
        status := params["status"]
        qs := req.URL.Query()
        var start, limit, stop int
        var err error
        if start, err = strconv.Atoi(qs.Get("start")); err != nil {
            start = 0
        }
        if limit, err = strconv.Atoi(qs.Get("limit")); err != nil {
            limit = 10
        }
        stop = start + limit
        var jobs []db.Job
        var count int
        jobs, err = db.RangeSchedJob(status, start, stop)
        count, _ = db.CountSchedJob(status)
        if err != nil {
            log.Printf("Error: RangeSchedJob error %s\n", err)
            r.JSON(http.StatusOK, map[string]interface{}{"jobs": "[]", "total": count, "current": start})
            return
        }
        r.JSON(http.StatusOK, map[string]interface{}{"jobs": jobs, "total": count, "current": start})
    })

    mart.Get(API + "/jobs/", func(req *http.Request, r render.Render) {
        qs := req.URL.Query()
        var start, limit, stop int
        var err error
        if start, err = strconv.Atoi(qs.Get("start")); err != nil {
            start = 0
        }
        if limit, err = strconv.Atoi(qs.Get("limit")); err != nil {
            limit = 10
        }
        stop = start + limit
        var jobs []db.Job
        var count int
        jobs, err = db.RangeJob(start, stop)
        count, _ = db.CountJob()
        if err != nil {
            log.Printf("Error: RangeSchedJob error %s\n", err)
            r.JSON(http.StatusOK, map[string]interface{}{"jobs": "[]", "total": count, "current": start})
            return
        }
        r.JSON(http.StatusOK, map[string]interface{}{"jobs": jobs, "total": count, "current": start})
    })

    mart.Delete(API + "/jobs/(?P<job_id>[0-9]+)", func(params martini.Params, r render.Render) {
        id, _ := strconv.Atoi(params["job_id"])
        err := db.DelJob(id)
        if err != nil {
            log.Printf("Error: DelJob error %s\n", err)
            r.JSON(http.StatusOK, map[string]interface{}{"err": err.Error()})
            return
        }
        r.JSON(http.StatusNotFound, map[string]interface{}{})
    })
}
<|endoftext|>


<commit_before>package hush // import "github.com/mndrix/hush"

import (
	"fmt"
	"os"
	p "path"

	"github.com/pkg/errors"
)

// Main implements the main() function of the hush command line tool.
func Main() {
	tree, err := LoadTree()
	if err != nil {
		die("%s\n", err.Error())
	}
	//warn("initial tree = %#v\n", tree)

	if len(os.Args) == 1 {
		err = tree.Print(os.Stdout)
		if err != nil {
			die("%s\n", err.Error())
		}
		os.Exit(0)
	}

	switch os.Args[1] {
	case "import": // hush import
		warnings, err := CmdImport(os.Stdout, os.Stdin, tree)
		if err != nil {
			die("%s\n", err.Error())
		}
		for _, warning := range warnings {
			warn(warning)
		}
	case "ls": // hush ls foo/bar
		if len(os.Args) < 3 {
			tree.Print(os.Stdout)
			return
		}
		CmdLs(os.Stdout, tree, os.Args[2])
	case "set": // hush set paypal.com/personal/user john@example.com
		p := NewPath(os.Args[2])
		v, err := captureValue(os.Args[3])
		if err != nil {
			die("%s\n", err.Error())
		}
		err = CmdSet(os.Stdout, tree, p, v)
		if err != nil {
			die("%s\n", err.Error())
		}
	default:
		die("Usage: hum ...\n")
	}
}

func die(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

func warn(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
}

func home() (string, error) {
	home := os.Getenv("HOME")
	if home == "" {
		return "", errors.New("Point $HOME at your home directory")
	}
	return home, nil
}

func hushPath() (string, error) {
	home, err := home()
	if err != nil {
		return "", err
	}
	return p.Join(home, ".hush"), nil
}

var editorVarNames = []string{
	"HUSH_EDITOR",
	"VISUAL",
	"EDITOR",
}

func editor() string {
	for _, varName := range editorVarNames {
		ed := os.Getenv(varName)
		if ed != "" {
			return ed
		}
	}

	ed := "vi"
	warn("environment configures no editor. defaulting to %s", ed)
	return ed
}
<commit_msg>Follow symlinks when locating .hush file<commit_after>package hush // import "github.com/mndrix/hush"

import (
	"fmt"
	"os"
	"path"
	"path/filepath"

	"github.com/pkg/errors"
)

// Main implements the main() function of the hush command line tool.
func Main() {
	tree, err := LoadTree()
	if err != nil {
		die("%s\n", err.Error())
	}
	//warn("initial tree = %#v\n", tree)

	if len(os.Args) == 1 {
		err = tree.Print(os.Stdout)
		if err != nil {
			die("%s\n", err.Error())
		}
		os.Exit(0)
	}

	switch os.Args[1] {
	case "import": // hush import
		warnings, err := CmdImport(os.Stdout, os.Stdin, tree)
		if err != nil {
			die("%s\n", err.Error())
		}
		for _, warning := range warnings {
			warn(warning)
		}
	case "ls": // hush ls foo/bar
		if len(os.Args) < 3 {
			tree.Print(os.Stdout)
			return
		}
		CmdLs(os.Stdout, tree, os.Args[2])
	case "set": // hush set paypal.com/personal/user john@example.com
		p := NewPath(os.Args[2])
		v, err := captureValue(os.Args[3])
		if err != nil {
			die("%s\n", err.Error())
		}
		err = CmdSet(os.Stdout, tree, p, v)
		if err != nil {
			die("%s\n", err.Error())
		}
	default:
		die("Usage: hum ...\n")
	}
}

func die(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

func warn(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
}

func home() (string, error) {
	home := os.Getenv("HOME")
	if home == "" {
		return "", errors.New("Point $HOME at your home directory")
	}
	return home, nil
}

func hushPath() (string, error) {
	home, err := home()
	if err != nil {
		return "", err
	}
	filename := path.Join(home, ".hush")
	return filepath.EvalSymlinks(filename)
}

var editorVarNames = []string{
	"HUSH_EDITOR",
	"VISUAL",
	"EDITOR",
}

func editor() string {
	for _, varName := range editorVarNames {
		ed := os.Getenv(varName)
		if ed != "" {
			return ed
		}
	}

	ed := "vi"
	warn("environment configures no editor. defaulting to %s", ed)
	return ed
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"strings"
	"time"

	"github.com/emersion/go-imap/client"
	message "github.com/emersion/go-message"
	"github.com/emersion/go-message/mail"
	"github.com/mmcdole/gofeed"
	"github.com/spf13/viper"
)

var mailTemplate = template.Must(template.New("mail").Parse(
	`

{{ .Title }} {{ .Author }}

{{ .Content }}

`))

type templatePayload struct {
	Link    string
	Title   string
	Author  string
	Content template.HTML
}

func FormatContent(item *gofeed.Item) (string, error) {
	var payload templatePayload

	payload.Link = item.Link
	payload.Title = item.Title

	if item.Author != nil {
		payload.Author = fmt.Sprintf("%s %s", item.Author.Name, item.Author.Email)
	}

	if len(item.Content) > 0 {
		payload.Content = template.HTML(item.Content)
	} else {
		payload.Content = template.HTML(item.Description)
	}

	var buffer bytes.Buffer

	err := mailTemplate.Execute(&buffer, payload)

	if err != nil {
		return "", err
	}

	return buffer.String(), nil
}

func NewMessage(item *gofeed.Item) (bytes.Buffer, error) {
	var b bytes.Buffer

	fromName := viper.GetString("imap.from.name")

	if item.Author != nil {
		fromName = fmt.Sprintf("%s %s", item.Author.Name, item.Author.Email)
	}

	from := []*mail.Address{{fromName, viper.GetString("imap.from.email")}}
	to := []*mail.Address{{viper.GetString("imap.to.name"), viper.GetString("imap.to.email")}}

	mediaParams := map[string]string{"charset": "utf-8"}

	h := mail.NewHeader()
	h.SetContentType("multipart/alternative", mediaParams)
	h.SetDate(*item.PublishedParsed)
	h.SetAddressList("From", from)
	h.SetAddressList("To", to)
	h.SetSubject(item.Title)

	// Create a new mail writer
	messageWriter, err := message.CreateWriter(&b, h.Header)
	defer messageWriter.Close()
	if err != nil {
		return b, err
	}

	htmlHeader := make(message.Header)
	htmlHeader.SetContentType("text/html", mediaParams)
	htmlWriter, err := messageWriter.CreatePart(htmlHeader)
	defer htmlWriter.Close()
	if err != nil {
		return b, err
	}

	content, err := FormatContent(item)
	if err != nil {
		return b, err
	}

	io.WriteString(htmlWriter, content)

	return b, nil
}

func AppendNewItemsViaIMAP(items ItemsWithFolders) error {
	if viper.GetBool("debug") {
		log.Printf("Found %d new items", len(items))
	}

	hostPort := fmt.Sprintf("%s:%d", viper.GetString("imap.host"), viper.GetInt("imap.port"))
	c, err := client.DialTLS(hostPort, nil)
	if err != nil {
		return err
	}

	defer c.Logout()

	if err := c.Login(viper.GetString("imap.username"), viper.GetString("imap.password")); err != nil {
		return err
	}

	if viper.GetBool("debug") {
		log.Println("Logged in to IMAP")
	}

	for _, entry := range items {
		if entry.Item.PublishedParsed == nil {
			t := time.Now()
			entry.Item.PublishedParsed = &t
		}

		folderName := entry.Folder
		if viper.GetBool("imap.folder_capitalize") {
			folderName = strings.Title(folderName)
		}
		folder := fmt.Sprintf("%s/%s", viper.GetString("imap.folder_prefix"), folderName)

		_ = c.Create(folder)

		msg, err := NewMessage(entry.Item)
		if err != nil {
			return err
		}

		if viper.GetBool("debug") {
			log.Printf("Appending item to %s", folder)
		}

		literal := bytes.NewReader(msg.Bytes())
		err = c.Append(folder, []string{}, *entry.Item.PublishedParsed, literal)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Minor cleanup<commit_after>package main

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"strings"
	"time"

	"github.com/emersion/go-imap/client"
	message "github.com/emersion/go-message"
	"github.com/emersion/go-message/mail"
	"github.com/mmcdole/gofeed"
	"github.com/spf13/viper"
)

var mailTemplate = template.Must(template.New("mail").Parse(
	`

{{ .Title }} {{ .Author }}

{{ .Content }}

`))

type templatePayload struct {
	Link    string
	Title   string
	Author  string
	Content template.HTML
}

func FormatContent(item *gofeed.Item) (string, error) {
	var payload templatePayload

	payload.Link = item.Link
	payload.Title = item.Title

	if item.Author != nil {
		payload.Author = fmt.Sprintf("%s %s", item.Author.Name, item.Author.Email)
	}

	if len(item.Content) > 0 {
		payload.Content = template.HTML(item.Content)
	} else {
		payload.Content = template.HTML(item.Description)
	}

	var buffer bytes.Buffer

	err := mailTemplate.Execute(&buffer, payload)

	if err != nil {
		return "", err
	}

	return buffer.String(), nil
}

func NewMessage(item *gofeed.Item) (bytes.Buffer, error) {
	var b bytes.Buffer

	fromName := viper.GetString("imap.from.name")

	if item.Author != nil {
		fromName = fmt.Sprintf("%s %s", item.Author.Name, item.Author.Email)
	}

	from := []*mail.Address{{fromName, viper.GetString("imap.from.email")}}
	to := []*mail.Address{{viper.GetString("imap.to.name"), viper.GetString("imap.to.email")}}

	mediaParams := map[string]string{"charset": "utf-8"}

	h := mail.NewHeader()
	h.SetContentType("multipart/alternative", mediaParams)
	h.SetDate(*item.PublishedParsed)
	h.SetAddressList("From", from)
	h.SetAddressList("To", to)
	h.SetSubject(item.Title)

	// Create a new mail writer
	messageWriter, err := message.CreateWriter(&b, h.Header)
	defer messageWriter.Close()
	if err != nil {
		return b, err
	}

	htmlHeader := mail.NewHeader()
	htmlHeader.SetContentType("text/html", mediaParams)
	htmlWriter, err := messageWriter.CreatePart(htmlHeader.Header)
	defer htmlWriter.Close()
	if err != nil {
		return b, err
	}

	content, err := FormatContent(item)
	if err != nil {
		return b, err
	}

	io.WriteString(htmlWriter, content)

	return b, nil
}

func AppendNewItemsViaIMAP(items ItemsWithFolders) error {
	if viper.GetBool("debug") {
		log.Printf("Found %d new items", len(items))
	}

	hostPort := fmt.Sprintf("%s:%d", viper.GetString("imap.host"), viper.GetInt("imap.port"))
	c, err := client.DialTLS(hostPort, nil)
	if err != nil {
		return err
	}

	defer c.Logout()

	if err := c.Login(viper.GetString("imap.username"), viper.GetString("imap.password")); err != nil {
		return err
	}

	if viper.GetBool("debug") {
		log.Println("Logged in to IMAP")
	}

	for _, entry := range items {
		if entry.Item.PublishedParsed == nil {
			t := time.Now()
			entry.Item.PublishedParsed = &t
		}

		folderName := entry.Folder
		if viper.GetBool("imap.folder_capitalize") {
			folderName = strings.Title(folderName)
		}
		folder := fmt.Sprintf("%s/%s", viper.GetString("imap.folder_prefix"), folderName)

		_ = c.Create(folder)

		msg, err := NewMessage(entry.Item)
		if err != nil {
			return err
		}

		if viper.GetBool("debug") {
			log.Printf("Appending item to %s", folder)
		}

		literal := bytes.NewReader(msg.Bytes())
		err = c.Append(folder, []string{}, *entry.Item.PublishedParsed, literal)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package goprocess

import (
	"sync"
)

// process implements Process
type process struct {
	children  sync.WaitGroup // wait group for child goroutines
	teardown  TeardownFunc   // called to run the teardown logic.
	closing   chan struct{}  // closed once close starts.
	closed    chan struct{}  // closed once close is done.
	closeOnce sync.Once      // ensure close is only called once.
	closeErr  error          // error to return to clients of Close()
}

// newProcess constructs and returns a Process.
// It will call tf TeardownFunc exactly once:
//  **after** all children have fully Closed,
//  **after** entering <-Closing(), and
//  **before** <-Closed().
func newProcess(tf TeardownFunc) *process {
	if tf == nil {
		tf = nilTeardownFunc
	}

	return &process{
		teardown: tf,
		closed:   make(chan struct{}),
		closing:  make(chan struct{}),
	}
}

func (p *process) WaitFor(q Process) {
	p.children.Add(1) // p waits on q to be done
	go func(p *process, q Process) {
		<-q.Closed()      // wait until q is closed
		p.children.Done() // p done waiting on q
	}(p, q)
}

func (p *process) AddChildNoWait(child Process) {
	go func(p, child Process) {
		<-p.Closing() // wait until p is closing
		child.Close() // close child
	}(p, child)
}

func (p *process) AddChild(child Process) {
	p.children.Add(1) // p waits on child to be done
	go func(p *process, child Process) {
		<-p.Closing()     // wait until p is closing
		child.Close()     // close child and wait
		p.children.Done() // p done waiting on child
	}(p, child)
}

func (p *process) Go(f ProcessFunc) Process {

	child := newProcess(nil)
	p.AddChild(child)
	child.children.Add(1) // child waits on func to be done
	go func() {
		f(child)
		child.children.Done()
	}()
	return child
}

// Close is the external close function.
// it's a wrapper around internalClose that waits on Closed()
func (p *process) Close() error {
	p.closeOnce.Do(p.doClose)
	<-p.Closed() // sync.Once should block, but this checks chan is closed too
	return p.closeErr
}

func (p *process) Closing() <-chan struct{} {
	return p.closing
}

func (p *process) Closed() <-chan struct{} {
	return p.closed
}

// the _actual_ close process.
func (p *process) doClose() {
	// this function should only be called once (hence the sync.Once).
	// and it will panic (on closeing channels) otherwise.

	close(p.closing)          // signal that we're shutting down (Closing)
	p.children.Wait()         // wait till all children are done (before teardown)
	p.closeErr = p.teardown() // actually run the close logic (ok safe to teardown)
	close(p.closed)           // signal that we're shut down (Closed)
}

// unclosable is a process that _cannot_ be closed. calling Close simply hangs.
type unclosable struct {
	*process
}

func (p *unclosable) Close() error {
	var hang chan struct{}
	<-hang // hang forever
	return nil
}
<commit_msg>Process.Go: make sure to close child when done<commit_after>package goprocess

import (
	"sync"
)

// process implements Process
type process struct {
	children  sync.WaitGroup // wait group for child goroutines
	teardown  TeardownFunc   // called to run the teardown logic.
	closing   chan struct{}  // closed once close starts.
	closed    chan struct{}  // closed once close is done.
	closeOnce sync.Once      // ensure close is only called once.
	closeErr  error          // error to return to clients of Close()
}

// newProcess constructs and returns a Process.
// It will call tf TeardownFunc exactly once:
//  **after** all children have fully Closed,
//  **after** entering <-Closing(), and
//  **before** <-Closed().
func newProcess(tf TeardownFunc) *process {
	if tf == nil {
		tf = nilTeardownFunc
	}

	return &process{
		teardown: tf,
		closed:   make(chan struct{}),
		closing:  make(chan struct{}),
	}
}

func (p *process) WaitFor(q Process) {
	p.children.Add(1) // p waits on q to be done
	go func(p *process, q Process) {
		<-q.Closed()      // wait until q is closed
		p.children.Done() // p done waiting on q
	}(p, q)
}

func (p *process) AddChildNoWait(child Process) {
	go func(p, child Process) {
		<-p.Closing() // wait until p is closing
		child.Close() // close child
	}(p, child)
}

func (p *process) AddChild(child Process) {
	select {
	case <-p.Closing():
		panic("attempt to add child to closing or closed process")
	default:
	}

	p.children.Add(1) // p waits on child to be done
	go func(p *process, child Process) {
		<-p.Closing()     // wait until p is closing
		child.Close()     // close child and wait
		p.children.Done() // p done waiting on child
	}(p, child)
}

func (p *process) Go(f ProcessFunc) Process {
	select {
	case <-p.Closing():
		panic("attempt to add child to closing or closed process")
	default:
	}

	// this is very similar to AddChild, but also runs the func
	// in the child. we replicate it here to save one goroutine.
	child := newProcess(nil)
	child.children.Add(1) // child waits on func to be done
	p.AddChild(child)
	go func() {
		f(child)
		child.children.Done() // wait on child's children to be done.
		child.Close()         // close to tear down.
	}()
	return child
}

// Close is the external close function.
// it's a wrapper around internalClose that waits on Closed()
func (p *process) Close() error {
	p.closeOnce.Do(p.doClose)
	<-p.Closed() // sync.Once should block, but this checks chan is closed too
	return p.closeErr
}

func (p *process) Closing() <-chan struct{} {
	return p.closing
}

func (p *process) Closed() <-chan struct{} {
	return p.closed
}

// the _actual_ close process.
func (p *process) doClose() {
	// this function should only be called once (hence the sync.Once).
	// and it will panic (on closeing channels) otherwise.

	close(p.closing)          // signal that we're shutting down (Closing)
	p.children.Wait()         // wait till all children are done (before teardown)
	p.closeErr = p.teardown() // actually run the close logic (ok safe to teardown)
	close(p.closed)           // signal that we're shut down (Closed)
}

// unclosable is a process that _cannot_ be closed. calling Close simply hangs.
type unclosable struct {
	*process
}

func (p *unclosable) Close() error {
	var hang chan struct{}
	<-hang // hang forever
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	"github.com/esiqveland/notify"
	"github.com/godbus/dbus"
)

func main() {
	iconName := "mail-unread"

	conn, err := dbus.SessionBus()
	if err != nil {
		panic(err)
	}

	notifier, err := notify.New(conn)
	if err != nil {
		log.Fatalln(err.Error())
	}
	defer notifier.Close()

	n := notify.Notification{
		AppName:       "Test GO App",
		ReplacesID:    uint32(0),
		AppIcon:       iconName,
		Summary:       "Test",
		Body:          "This is a test of the DBus bindings for go.",
		Actions:       []string{"cancel", "Cancel", "open", "Open"}, // tuples of (action_key, label)
		Hints:         map[string]dbus.Variant{},
		ExpireTimeout: int32(5000),
	}

	id, err := notifier.SendNotification(n)
	if err != nil {
		panic(err)
	}
	log.Printf("sent notification id: %v", id)

	actions := notifier.ActionInvoked()
	action := <-actions
	log.Printf("Action: %v Key: %v", action.Id, action.ActionKey)

	closer := <-notifier.NotificationClosed()
	log.Printf("NotificationClosed: %v Reason: %v", closer.Id, closer.Reason)

	caps, err := notifier.GetCapabilities()
	if err != nil {
		log.Printf("error fetching capabilities: %v", err)
	}
	for x := range caps {
		fmt.Printf("Registered capability: %v\n", caps[x])
	}

	info, err := notifier.GetServerInformation()
	if err != nil {
		log.Printf("error getting server information: %v", err)
	}
	fmt.Printf("Name:    %v\n", info.Name)
	fmt.Printf("Vendor:  %v\n", info.Vendor)
	fmt.Printf("Version: %v\n", info.Version)
	fmt.Printf("Spec:    %v\n", info.SpecVersion)

	// And there is a helper for just sending notifications directly if you have a connection:
	//notify.SendNotification(conn, n)

}
<commit_msg>[example] refactor<commit_after>package main

import (
	"fmt"
	"log"

	"github.com/esiqveland/notify"
	"github.com/godbus/dbus"
)

func main() {

	conn, err := dbus.SessionBus()
	if err != nil {
		panic(err)
	}

	// Basic usage
	// Create a Notification to send
	iconName := "mail-unread"
	n := notify.Notification{
		AppName:       "Test GO App",
		ReplacesID:    uint32(0),
		AppIcon:       iconName,
		Summary:       "Test",
		Body:          "This is a test of the DBus bindings for go.",
		Actions:       []string{"cancel", "Cancel", "open", "Open"}, // tuples of (action_key, label)
		Hints:         map[string]dbus.Variant{},
		ExpireTimeout: int32(5000),
	}

	// Ship it!
	createdID, err := notify.SendNotification(conn, n)
	if err != nil {
		log.Printf("error sending notification: %v", err.Error())
	}
	log.Printf("created notification with id: %v", createdID)

	// List server features!
	caps, err := notify.GetCapabilities(conn)
	if err != nil {
		log.Printf("error fetching capabilities: %v", err)
	}
	for x := range caps {
		fmt.Printf("Registered capability: %v\n", caps[x])
	}

	info, err := notify.GetServerInformation(conn)
	if err != nil {
		log.Printf("error getting server information: %v", err)
	}
	fmt.Printf("Name:    %v\n", info.Name)
	fmt.Printf("Vendor:  %v\n", info.Vendor)
	fmt.Printf("Version: %v\n", info.Version)
	fmt.Printf("Spec:    %v\n", info.SpecVersion)

	// Notifyer interface with event delivery
	notifier, err := notify.New(conn)
	if err != nil {
		log.Fatalln(err.Error())
	}
	defer notifier.Close()

	id, err := notifier.SendNotification(n)
	if err != nil {
		log.Printf("error sending notification: %v", err)
	}
	log.Printf("sent notification id: %v", id)

	// Listen for actions invoked!
	actions := notifier.ActionInvoked()
	go func() {
		action := <-actions
		log.Printf("ActionInvoked: %v Key: %v", action.Id, action.ActionKey)
	}()

	closer := <-notifier.NotificationClosed()
	log.Printf("NotificationClosed: %v Reason: %v", closer.Id, closer.Reason)

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	"github.com/tantalum73/Go-APNS"
)

func main() {
	m := goapns.NewMessage().Title("Title").Body("A Test notification :)").Sound("Default").Badge(42)
	m.Custom("key", "val")
	c, err := goapns.NewConnection("../../../../Push Test Push Cert.p12", "PasswortdesZertifikates")
	if err != nil {
		log.Fatal(err)
	} else {
		c.Development()
	}

	//fmt.Println(m)
	//iPad: a26f0000c05286ee6f31756b1b9d05b4a37ad512fabbe266dd21357b376f0e0e
	//iPhone: 428dc1d681e576f69f337cd0061b1cdd8da9b76daab39203fa649c26187722c0
	tokens := []string{"a26f0000c05286ee6f31756b1b9d05b4a37ad512fabbe266dd21357b376f0e0e",
		"428dc1d681e576f69f337cd0061b1cdd8da9b76daab39203fa649c26187722c0"}
	ch := make(chan goapns.Response, len(tokens))
	c.Push(m, tokens, ch)
	fmt.Println(m.JSONstring())

	for response := range ch {
		//fmt.Printf("\nReceived response: %v\n", response)
		if !response.Sent() {
			fmt.Printf("\nThere was an error sending to device %v : %v\n Timestamp: %v, == Zero %v\n\n", response.Token, response.Error, response.Timestamp(), response.Timestamp().IsZero())
		} else {
			fmt.Printf("\nPush successful for token: %v\n", response.Token)
		}

	}
}
<commit_msg>More comments on main.go<commit_after>package main

import (
	"fmt"
	"log"

	"github.com/tantalum73/Go-APNS"
)

func main() {
	//Creating the Connection by passing the path to a valid certificate and its passphrase
	conn, err := goapns.NewConnection("../../../../Push Test Push Cert.p12", "PasswortdesZertifikates")
	if err != nil {
		log.Fatal(err)
	} else {
		conn.Development()
	}

	//composing the Message
	message := goapns.NewMessage().Title("Title").Body("A Test notification :)").Sound("Default").Badge(42)
	message.Custom("key", "val")

	//iPad: a26f0000c05286ee6f31756b1b9d05b4a37ad512fabbe266dd21357b376f0e0e
	//iPhone: 428dc1d681e576f69f337cd0061b1cdd8da9b76daab39203fa649c26187722c0

	//Tokens from a database or, in my case, statically typed
	tokens := []string{"a26f0000c05286ee6f31756b1b9d05b4a37ad512fabbe266dd21357b376f0e0e",
		"428dc1d681e576f69f337cd0061b1cdd8da9b76daab39203fa649c26187722c0"}

	//create a channel that gets the Response object passed in,
	//it expects as many responses as there are token to push to
	channel := make(chan goapns.Response, len(tokens))

	//Print the JSON as it is sent to Apples servers
	fmt.Println(message.JSONstring())

	//Perform the push asynchronosly
	conn.Push(message, tokens, channel)

	//iterate through the responses
	for response := range channel {
		//fmt.Printf("\nReceived response: %v\n", response)
		if !response.Sent() {
			fmt.Printf("\nThere was an error sending to device %v : %v\n Timestamp: %v, == Zero %v\n\n", response.Token, response.Error, response.Timestamp(), response.Timestamp().IsZero())
		} else {
			fmt.Printf("\nPush successful for token: %v\n", response.Token)
		}

	}
}
<|endoftext|>


<commit_before>package main

import (
	redigo "github.com/garyburd/redigo/redis"
	"github.com/pierrre/imageserver"
	imageserver_cache_chain "github.com/pierrre/imageserver/cache/chain"
	imageserver_cache_memory "github.com/pierrre/imageserver/cache/memory"
	imageserver_cache_prefix "github.com/pierrre/imageserver/cache/prefix"
	imageserver_cache_redis "github.com/pierrre/imageserver/cache/redis"
	imageserver_http "github.com/pierrre/imageserver/http"
	imageserver_http_parser_graphicsmagick "github.com/pierrre/imageserver/http/parser/graphicsmagick"
	imageserver_http_parser_merge "github.com/pierrre/imageserver/http/parser/merge"
	imageserver_http_parser_source "github.com/pierrre/imageserver/http/parser/source"
	imageserver_processor_graphicsmagick "github.com/pierrre/imageserver/processor/graphicsmagick"
	imageserver_processor_limit "github.com/pierrre/imageserver/processor/limit"
	imageserver_provider_cache "github.com/pierrre/imageserver/provider/cache"
	imageserver_provider_http "github.com/pierrre/imageserver/provider/http"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

func main() {
	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	cache := imageserver_cache_chain.ChainCache{
		imageserver_cache_memory.New(10 * 1024 * 1024),
		&imageserver_cache_redis.RedisCache{
			Pool: &redigo.Pool{
				Dial: func() (redigo.Conn, error) {
					return redigo.Dial("tcp", "localhost:6379")
				},
				MaxIdle: 50,
			},
			Expire: time.Duration(7 * 24 * time.Hour),
		},
	}

	imageServer := &imageserver.Server{
		Cache: &imageserver_cache_prefix.PrefixCache{
			Prefix: "processed:",
			Cache:  cache,
		},
		Provider: &imageserver_provider_cache.CacheProvider{
			Cache: &imageserver_cache_prefix.PrefixCache{
				Prefix: "source:",
				Cache:  cache,
			},
			Provider: &imageserver_provider_http.HttpProvider{},
		},
		Processor: imageserver_processor_limit.New(16, &imageserver_processor_graphicsmagick.GraphicsMagickProcessor{
			Executable: "gm",
			Timeout:    time.Duration(5 * time.Second),
			AllowedFormats: []string{
				"jpeg",
				"png",
				"bmp",
				"gif",
			},
			DefaultQualities: map[string]string{
				"jpeg": "85",
			},
		}),
	}

	httpImageServer := &imageserver_http.Server{
		Parser: &imageserver_http_parser_merge.MergeParser{
			&imageserver_http_parser_source.SourceParser{},
			&imageserver_http_parser_graphicsmagick.GraphicsMagickParser{},
		},
		ImageServer: imageServer,
		Expire:      time.Duration(7 * 24 * time.Hour),
		RequestFunc: func(request *http.Request) error {
			url := request.URL
			query := url.Query()
			errorCodeString := query.Get("error")
			if len(errorCodeString) == 0 {
				return nil
			}
			errorCode, err := strconv.Atoi(errorCodeString)
			if err != nil {
				return imageserver.NewError(err.Error())
			}
			return imageserver_http.NewError(errorCode)
		},
		HeaderFunc: func(header http.Header, request *http.Request, err error) {
			header.Set("X-Hostname", hostname)
		},
		ErrorFunc: func(err error, request *http.Request) {
			log.Println(err)
		},
		ResponseFunc: func(request *http.Request, statusCode int, contentSize int64, err error) {
			var errString string
			if err != nil {
				errString = err.Error()
			}
			log.Println(request.Method, strconv.Quote(request.URL.String()), statusCode, contentSize, strconv.Quote(errString))
		},
	}

	http.Handle("/", httpImageServer)
	err = http.ListenAndServe(":8080", nil)
	if err != nil {
		panic(err)
	}
}
<commit_msg>Ignore example in build<commit_after>// +build ignore

package main

import (
	redigo "github.com/garyburd/redigo/redis"
	"github.com/pierrre/imageserver"
	imageserver_cache_chain "github.com/pierrre/imageserver/cache/chain"
	imageserver_cache_memory "github.com/pierrre/imageserver/cache/memory"
	imageserver_cache_prefix "github.com/pierrre/imageserver/cache/prefix"
	imageserver_cache_redis "github.com/pierrre/imageserver/cache/redis"
	imageserver_http "github.com/pierrre/imageserver/http"
	imageserver_http_parser_graphicsmagick "github.com/pierrre/imageserver/http/parser/graphicsmagick"
	imageserver_http_parser_merge "github.com/pierrre/imageserver/http/parser/merge"
	imageserver_http_parser_source "github.com/pierrre/imageserver/http/parser/source"
	imageserver_processor_graphicsmagick "github.com/pierrre/imageserver/processor/graphicsmagick"
	imageserver_processor_limit "github.com/pierrre/imageserver/processor/limit"
	imageserver_provider_cache "github.com/pierrre/imageserver/provider/cache"
	imageserver_provider_http "github.com/pierrre/imageserver/provider/http"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

func main() {
	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	cache := imageserver_cache_chain.ChainCache{
		imageserver_cache_memory.New(10 * 1024 * 1024),
		&imageserver_cache_redis.RedisCache{
			Pool: &redigo.Pool{
				Dial: func() (redigo.Conn, error) {
					return redigo.Dial("tcp", "localhost:6379")
				},
				MaxIdle: 50,
			},
			Expire: time.Duration(7 * 24 * time.Hour),
		},
	}

	imageServer := &imageserver.Server{
		Cache: &imageserver_cache_prefix.PrefixCache{
			Prefix: "processed:",
			Cache:  cache,
		},
		Provider: &imageserver_provider_cache.CacheProvider{
			Cache: &imageserver_cache_prefix.PrefixCache{
				Prefix: "source:",
				Cache:  cache,
			},
			Provider: &imageserver_provider_http.HttpProvider{},
		},
		Processor: imageserver_processor_limit.New(16, &imageserver_processor_graphicsmagick.GraphicsMagickProcessor{
			Executable: "gm",
			Timeout:    time.Duration(5 * time.Second),
			AllowedFormats: []string{
				"jpeg",
				"png",
				"bmp",
				"gif",
			},
			DefaultQualities: map[string]string{
				"jpeg": "85",
			},
		}),
	}

	httpImageServer := &imageserver_http.Server{
		Parser: &imageserver_http_parser_merge.MergeParser{
			&imageserver_http_parser_source.SourceParser{},
			&imageserver_http_parser_graphicsmagick.GraphicsMagickParser{},
		},
		ImageServer: imageServer,
		Expire:      time.Duration(7 * 24 * time.Hour),
		RequestFunc: func(request *http.Request) error {
			url := request.URL
			query := url.Query()
			errorCodeString := query.Get("error")
			if len(errorCodeString) == 0 {
				return nil
			}
			errorCode, err := strconv.Atoi(errorCodeString)
			if err != nil {
				return imageserver.NewError(err.Error())
			}
			return imageserver_http.NewError(errorCode)
		},
		HeaderFunc: func(header http.Header, request *http.Request, err error) {
			header.Set("X-Hostname", hostname)
		},
		ErrorFunc: func(err error, request *http.Request) {
			log.Println(err)
		},
		ResponseFunc: func(request *http.Request, statusCode int, contentSize int64, err error) {
			var errString string
			if err != nil {
				errString = err.Error()
			}
			log.Println(request.Method, strconv.Quote(request.URL.String()), statusCode, contentSize, strconv.Quote(errString))
		},
	}

	http.Handle("/", httpImageServer)
	err = http.ListenAndServe(":8080", nil)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha256"
	"time"

	"github.com/bwmarrin/go-alone"
)

func main() {

	// This secret is used as the hash key for the signer.
	var secret = []byte("It's a secret to everybody")

	// This data is what we will be signing below.
	var data = []byte("It's dangerous to go alone! Take this.")

	// Create a new Signer using our secret
	s := goalone.New(secret, nil)

	// Sign and return a token in the form of `data.signature`
	token := s.Sign(data)

	// You can reuse this struct as many times as you wish
	token2 := s.Sign(data)

	// You can easily Unsign a token, which will verify the signature is valid
	// then return signed data of the token.
	data, err := s.Unsign(token)
	if err != nil {
		// signature is not valid
	} else {
		// signature is valid, it is safe to use the data
		println(string(data))
	}

	// Of course, you can do this as many times as needed as well.
	data2, err2 := s.Unsign(token2)
	if err2 != nil {
		// signature is not valid
	} else {
		// signature is valid, it is safe to use the data
		println(string(data2))
	}

	// You can also write one-liners when you will not be reusing the hash.
	token3 := goalone.New(secret, nil).Sign(data)

	// Of course, you can Unsign with a one-liner too.
	data3, err3 := goalone.New(secret, nil).Unsign(token3)
	if err3 != nil {
		// signature is not valid
	} else {
		// signature is valid, it is safe to use the data
		println(string(data3))
	}

	// You can pass options to your new signer with the Options{} struct
	o := new(goalone.Options)

	// You can have the signer add timestamp to each token like this
	o.Timestamp = true

	// You can even set a custom timestamp epoch, if you want.
	// Just give it a unix timestamp in seconds and go-alone will
	// use it as an offset of all timestamps. This will allow you
	// to better future proof your tokens or to just make them
	// more obsecure.
	o.Epoch = 1293840000

	// You can use a different algorithm if you wish for better security
	// or a less secure one that is maybe faster? Up to you.
	o.Algorithm = sha256.New

	// Now lets pass these options to our new signer then sign our data
	s = goalone.New(secret, o)
	token = s.Sign(data)

	// Of course you can do this all as a one liner too, but it does start to get
	// a bit too long :)
	token = goalone.New(secret, &goalone.Options{Timestamp: true, Epoch: 1293840000, Algorithm: sha256.New}).Sign(data)

	// You can parse out a token into a struct that separates the payload and
	// timestamp for you.
	ts := s.Parse(token)

	// Now, we can print the payload with
	println(string(ts.Payload))

	// We can print the timestamp with
	println(ts.Timestamp.String())

	// We can even check how old our timestamp is.  You can do a lot of other
	// things with the Timestamp too, since it's a standard time.Time value.
	if time.Since(ts.Timestamp) > time.Hour {
		// That token's timestamp is over an hour old!
	}

}
<commit_msg>Fix comment.<commit_after>package main

import (
	"crypto/sha256"
	"time"

	"github.com/bwmarrin/go-alone"
)

func main() {

	// This secret is used as the hash key for the signer.
	var secret = []byte("It's a secret to everybody")

	// This data is what we will be signing below.
	var data = []byte("It's dangerous to go alone! Take this.")

	// Create a new Signer using our secret
	s := goalone.New(secret, nil)

	// Sign and return a token in the form of `data.signature`
	token := s.Sign(data)

	// You can reuse this struct as many times as you wish
	token2 := s.Sign(data)

	// You can easily Unsign a token, which will verify the signature is valid
	// then return signed data of the token.
	data, err := s.Unsign(token)
	if err != nil {
		// signature is not valid
	} else {
		// signature is valid, it is safe to use the data
		println(string(data))
	}

	// Of course, you can do this as many times as needed as well.
	data2, err2 := s.Unsign(token2)
	if err2 != nil {
		// signature is not valid
	} else {
		// signature is valid, it is safe to use the data
		println(string(data2))
	}

	// You can also write one-liners when you will not be reusing the hash.
	token3 := goalone.New(secret, nil).Sign(data)

	// Of course, you can Unsign with a one-liner too.
	data3, err3 := goalone.New(secret, nil).Unsign(token3)
	if err3 != nil {
		// signature is not valid
	} else {
		// signature is valid, it is safe to use the data
		println(string(data3))
	}

	// You can pass options to your new signer with the Options{} struct
	o := new(goalone.Options)

	// You can have the signer add timestamp to each token like this
	o.Timestamp = true

	// You can even set a custom timestamp epoch, if you want. Just give it a
	// unix timestamp in seconds and go-alone will use it as an offset for all
	// timestamps. This will allow you to better future proof your tokens or to
	// just make them more obsecure.
	o.Epoch = 1293840000

	// You can use a different algorithm if you wish for better security
	// or a less secure one that is maybe faster? Up to you.
	o.Algorithm = sha256.New

	// Now lets pass these options to our new signer then sign our data
	s = goalone.New(secret, o)
	token = s.Sign(data)

	// Of course you can do this all as a one liner too, but it does start to get
	// a bit too long :)
	token = goalone.New(secret, &goalone.Options{Timestamp: true, Epoch: 1293840000, Algorithm: sha256.New}).Sign(data)

	// You can parse out a token into a struct that separates the payload and
	// timestamp for you.
	ts := s.Parse(token)

	// Now, we can print the payload with
	println(string(ts.Payload))

	// We can print the timestamp with
	println(ts.Timestamp.String())

	// We can even check how old our timestamp is.  You can do a lot of other
	// things with the Timestamp too, since it's a standard time.Time value.
	if time.Since(ts.Timestamp) > time.Hour {
		// That token's timestamp is over an hour old!
	}

}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"strings"
	"sync"

	_ "net/http/pprof"

	"github.com/lucas-clemente/quic-go/http3"
	"github.com/lucas-clemente/quic-go/internal/testdata"
	"github.com/lucas-clemente/quic-go/internal/utils"
)

type binds []string

func (b binds) String() string {
	return strings.Join(b, ",")
}

func (b *binds) Set(v string) error {
	*b = strings.Split(v, ",")
	return nil
}

// Size is needed by the /demo/upload handler to determine the size of the uploaded file
type Size interface {
	Size() int64
}

func init() {
	http.HandleFunc("/demo/tile", func(w http.ResponseWriter, r *http.Request) {
		// Small 40x40 png
		w.Write([]byte{
			0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
			0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28,
			0x01, 0x03, 0x00, 0x00, 0x00, 0xb6, 0x30, 0x2a, 0x2e, 0x00, 0x00, 0x00,
			0x03, 0x50, 0x4c, 0x54, 0x45, 0x5a, 0xc3, 0x5a, 0xad, 0x38, 0xaa, 0xdb,
			0x00, 0x00, 0x00, 0x0b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x18,
			0x61, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xe2, 0xb8, 0x75, 0x22, 0x00,
			0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
		})
	})

	http.HandleFunc("/demo/tiles", func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, "")
		for i := 0; i < 200; i++ {
			fmt.Fprintf(w, `<img src="/demo/tile?cachebust=%d">`, i)
		}
		io.WriteString(w, "")
	})

	http.HandleFunc("/demo/echo", func(w http.ResponseWriter, r *http.Request) {
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Printf("error reading body while handling /echo: %s\n", err.Error())
		}
		w.Write(body)
	})

	// accept file uploads and return the MD5 of the uploaded file
	// maximum accepted file size is 1 GB
	http.HandleFunc("/demo/upload", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost {
			err := r.ParseMultipartForm(1 << 30) // 1 GB
			if err == nil {
				var file multipart.File
				file, _, err = r.FormFile("uploadfile")
				if err == nil {
					var size int64
					if sizeInterface, ok := file.(Size); ok {
						size = sizeInterface.Size()
						b := make([]byte, size)
						file.Read(b)
						md5 := md5.Sum(b)
						fmt.Fprintf(w, "%x", md5)
						return
					}
					err = errors.New("couldn't get uploaded file size")
				}
			}
			if err != nil {
				utils.DefaultLogger.Infof("Error receiving upload: %#v", err)
			}
		}
		io.WriteString(w, `<form action="/demo/upload" method="post" enctype="multipart/form-data">
				<input type="file" name="uploadfile">

				<input type="submit">
			</form>`)
	})
}

func main() {
	// defer profile.Start().Stop()
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()
	// runtime.SetBlockProfileRate(1)

	verbose := flag.Bool("v", false, "verbose")
	bs := binds{}
	flag.Var(&bs, "bind", "bind to")
	www := flag.String("www", "/var/www", "www data")
	tcp := flag.Bool("tcp", false, "also listen on TCP")
	flag.Parse()

	logger := utils.DefaultLogger

	if *verbose {
		logger.SetLogLevel(utils.LogLevelDebug)
	} else {
		logger.SetLogLevel(utils.LogLevelInfo)
	}
	logger.SetLogTimeFormat("")

	http.Handle("/", http.FileServer(http.Dir(*www)))

	if len(bs) == 0 {
		bs = binds{"localhost:6121"}
	}

	var wg sync.WaitGroup
	wg.Add(len(bs))
	for _, b := range bs {
		bCap := b
		go func() {
			var err error
			if *tcp {
				certFile, keyFile := testdata.GetCertificatePaths()
				err = http3.ListenAndServe(bCap, certFile, keyFile, nil)
			} else {
				server := http3.Server{
					Server: &http.Server{Addr: bCap},
				}
				err = server.ListenAndServeTLS(testdata.GetCertificatePaths())
			}
			if err != nil {
				fmt.Println(err)
			}
			wg.Done()
		}()
	}
	wg.Wait()
}
<commit_msg>add an HTTP endpoint to output arbitrary length data to example server<commit_after>package main

import (
	"crypto/md5"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"strconv"
	"strings"
	"sync"

	_ "net/http/pprof"

	"github.com/lucas-clemente/quic-go/http3"
	"github.com/lucas-clemente/quic-go/integrationtests/tools/testserver"
	"github.com/lucas-clemente/quic-go/internal/testdata"
	"github.com/lucas-clemente/quic-go/internal/utils"
)

type binds []string

func (b binds) String() string {
	return strings.Join(b, ",")
}

func (b *binds) Set(v string) error {
	*b = strings.Split(v, ",")
	return nil
}

// Size is needed by the /demo/upload handler to determine the size of the uploaded file
type Size interface {
	Size() int64
}

func init() {
	http.HandleFunc("/demo/tile", func(w http.ResponseWriter, r *http.Request) {
		// Small 40x40 png
		w.Write([]byte{
			0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
			0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28,
			0x01, 0x03, 0x00, 0x00, 0x00, 0xb6, 0x30, 0x2a, 0x2e, 0x00, 0x00, 0x00,
			0x03, 0x50, 0x4c, 0x54, 0x45, 0x5a, 0xc3, 0x5a, 0xad, 0x38, 0xaa, 0xdb,
			0x00, 0x00, 0x00, 0x0b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x18,
			0x61, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xe2, 0xb8, 0x75, 0x22, 0x00,
			0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
		})
	})

	http.HandleFunc("/demo/tiles", func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, "")
		for i := 0; i < 200; i++ {
			fmt.Fprintf(w, `<img src="/demo/tile?cachebust=%d">`, i)
		}
		io.WriteString(w, "")
	})

	http.HandleFunc("/demo/echo", func(w http.ResponseWriter, r *http.Request) {
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Printf("error reading body while handling /echo: %s\n", err.Error())
		}
		w.Write(body)
	})

	// accept file uploads and return the MD5 of the uploaded file
	// maximum accepted file size is 1 GB
	http.HandleFunc("/demo/upload", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost {
			err := r.ParseMultipartForm(1 << 30) // 1 GB
			if err == nil {
				var file multipart.File
				file, _, err = r.FormFile("uploadfile")
				if err == nil {
					var size int64
					if sizeInterface, ok := file.(Size); ok {
						size = sizeInterface.Size()
						b := make([]byte, size)
						file.Read(b)
						md5 := md5.Sum(b)
						fmt.Fprintf(w, "%x", md5)
						return
					}
					err = errors.New("couldn't get uploaded file size")
				}
			}
			if err != nil {
				utils.DefaultLogger.Infof("Error receiving upload: %#v", err)
			}
		}
		io.WriteString(w, `<form action="/demo/upload" method="post" enctype="multipart/form-data">
				<input type="file" name="uploadfile">

				<input type="submit">
			</form>`)
	})
}

func main() {
	// defer profile.Start().Stop()
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()
	// runtime.SetBlockProfileRate(1)

	verbose := flag.Bool("v", false, "verbose")
	bs := binds{}
	flag.Var(&bs, "bind", "bind to")
	www := flag.String("www", "/var/www", "www data")
	tcp := flag.Bool("tcp", false, "also listen on TCP")
	flag.Parse()

	logger := utils.DefaultLogger

	if *verbose {
		logger.SetLogLevel(utils.LogLevelDebug)
	} else {
		logger.SetLogLevel(utils.LogLevelInfo)
	}
	logger.SetLogTimeFormat("")

	http.Handle("/", http.FileServer(http.Dir(*www)))
	http.HandleFunc("/dynamic/", func(w http.ResponseWriter, r *http.Request) {
		const maxSize = 1 << 30 // 1 GB
		num, err := strconv.ParseInt(strings.ReplaceAll(r.RequestURI, "/dynamic/", ""), 10, 64)
		if err != nil || num <= 0 || num > maxSize {
			w.WriteHeader(400)
			return
		}
		w.Write(testserver.GeneratePRData(int(num)))
	})

	if len(bs) == 0 {
		bs = binds{"localhost:6121"}
	}

	var wg sync.WaitGroup
	wg.Add(len(bs))
	for _, b := range bs {
		bCap := b
		go func() {
			var err error
			if *tcp {
				certFile, keyFile := testdata.GetCertificatePaths()
				err = http3.ListenAndServe(bCap, certFile, keyFile, nil)
			} else {
				server := http3.Server{
					Server: &http.Server{Addr: bCap},
				}
				err = server.ListenAndServeTLS(testdata.GetCertificatePaths())
			}
			if err != nil {
				fmt.Println(err)
			}
			wg.Done()
		}()
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>package bites_test

import (
	"fmt"

	"github.com/PieterD/bites"
)

func ExampleStringOps() {
	// Chain operations to construct your buffer.
	b := bites.New().PutByte('H').PutRune('e', nil).PutString("llo ").PutSlice([]byte("world!"))
	fmt.Println(b.String())
	// Output: Hello world!
}

func ExampleExpect() {
	// Chain operations to construct your buffer.
	var hash [32]byte
	b := bites.New().PutString("some string").PutUint32(513).PutVar(912345)
	b = b.PutByte('Q').PutSlice(hash[:]).PutString("another one")

	// Chain operations to read your buffer, using expect and get.
	var qbyte byte
	var hashcopy [32]byte
	var str string
	r := b.Skip(11).ExpectUint32(513).ExpectVarInt(912345, nil).GetByte(&qbyte)
	r = r.GetSliceCopy(hashcopy[:]).GetString(&str, 7).ExpectString(" one")
	fmt.Printf("%c %s\n", qbyte, str)
	// Output: Q another
}
<commit_msg>Fixed examples<commit_after>package bites_test

import (
	"fmt"

	"github.com/PieterD/bites"
)

func ExampleBites() {
	// Chain operations to construct your buffer.
	var hash [32]byte
	b := bites.New().PutString("some string").PutUint32(513).PutVar(912345)
	b = b.PutByte('Q').PutSlice(hash[:]).PutString("another one")

	// Chain operations to read your buffer, using expect and get.
	var qbyte byte
	var hashcopy [32]byte
	var str string
	r := b.Skip(11).ExpectUint32(513).ExpectVarInt(912345, nil).GetByte(&qbyte)
	r = r.GetSliceCopy(hashcopy[:]).GetString(&str, 7).ExpectString(" one")

	fmt.Printf("%c %s\n", qbyte, str)
	// Output: Q another
}

func ExampleWriter() {
	b := bites.New().PutString("Hello")
	w := bites.NewWriter(b)
	fmt.Fprintf(w, ", world!")
	fmt.Println(w.Bites().String())
	// Output: Hello, world!
}
<|endoftext|>


<commit_before>// Copyright 2015 Alex Browne and Soroush Pour.
// Allrights reserved. Use of this source code is
// governed by the MIT license, which can be found
// in the LICENSE file.

package router_test

import (
	"fmt"
	"github.com/go-humble/router"
)

func ExampleRoutes() {
	// Create a new Router object
	r := router.New()
	// Use HandleFunc to add routes.
	r.HandleFunc("/greet/{name}", func(params map[string]string) {
		// The handler for this route simply grabs the name parameter
		// from the map of params and says hello.
		fmt.Printf("Hello, %s\n", params["name"])
	})
	// You must call Start in order to start listening for changes
	// in the url and trigger the appropriate handler function.
	r.Start()
}
<commit_msg>Update example to be compatible with godoc<commit_after>// Copyright 2015 Alex Browne and Soroush Pour.
// Allrights reserved. Use of this source code is
// governed by the MIT license, which can be found
// in the LICENSE file.

package router_test

import (
	"fmt"
	"github.com/go-humble/router"
)

func ExampleRouter_HandleFunc() {
	// Create a new Router object
	r := router.New()
	// Use HandleFunc to add routes.
	r.HandleFunc("/greet/{name}", func(params map[string]string) {
		// The handler for this route simply grabs the name parameter
		// from the map of params and says hello.
		fmt.Printf("Hello, %s\n", params["name"])
	})
	// You must call Start in order to start listening for changes
	// in the url and trigger the appropriate handler function.
	r.Start()
}
<|endoftext|>


<commit_before>package jsonseq_test

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/jmank88/jsonseq"
)

func ExampleWriteRecord() {
	_ = jsonseq.WriteRecord(os.Stdout, []byte(`{"id":1}`))
	_ = jsonseq.WriteRecord(os.Stdout, []byte(`{"id":2}`))
	_ = jsonseq.WriteRecord(os.Stdout, []byte(`{"id":3}`))

	// Output:
	// {"id":1}
	// {"id":2}
	// {"id":3}
	//
}

func ExampleRecordWriter() {
	encoder := json.NewEncoder(&jsonseq.RecordWriter{os.Stdout})
	_ = encoder.Encode("Test")
	_ = encoder.Encode(123.456)
	_ = encoder.Encode(struct{ Id int }{Id: 1})

	// Output:
	// "Test"
	// 123.456
	// {"Id":1}
	//
}

func ExampleDecoder_Decode() {
	d := jsonseq.NewDecoder(strings.NewReader(`{"id":1} 12341234 true discarded junk`))
	for {
		var i interface{}
		if err := d.Decode(&i); err != nil {
			if err == io.EOF {
				break
			}
			fmt.Println(err)
		} else {
			fmt.Println(i)
		}
	}

	// Output:
	// map[id:1]
	// invalid record: "1234"
	// 1234
	// true
}
<commit_msg>update examples<commit_after>package jsonseq_test

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/jmank88/jsonseq"
)

func ExampleWriteRecord() {
	_ = jsonseq.WriteRecord(os.Stdout, []byte(`{"id":1}`))
	_ = jsonseq.WriteRecord(os.Stdout, []byte(`{"id":2}`))
	_ = jsonseq.WriteRecord(os.Stdout, []byte(`{"id":3}`))

	// Output:
	// {"id":1}
	// {"id":2}
	// {"id":3}
	//
}

func ExampleNewEncoder() {
	encoder := jsonseq.NewEncoder(os.Stdout)
	_ = encoder.Encode("Test")
	_ = encoder.Encode(123.456)
	_ = encoder.Encode(struct{ Id int }{Id: 1})

	// Output:
	// "Test"
	// 123.456
	// {"Id":1}
	//
}

func ExampleDecoder_Decode() {
	d := jsonseq.NewDecoder(strings.NewReader(`{"id":1} 12341234 true discarded junk`))
	for {
		var i interface{}
		if err := d.Decode(&i); err != nil {
			if err == io.EOF {
				break
			}
			fmt.Println(err)
		} else {
			fmt.Println(i)
		}
	}

	// Output:
	// map[id:1]
	// invalid record: "1234"
	// 1234
	// true
}
<|endoftext|>


<commit_before>package chardet

import (
	"fmt"
)

var (
	zh_gb18030_text = []byte{
		71, 111, 202, 199, 71, 111, 111, 103, 108, 101, 233, 95, 176, 108, 181, 196, 210, 187, 214, 214, 190, 142, 215, 103, 208, 205, 163, 172, 129, 75, 176, 108,
		208, 205, 163, 172, 178, 162, 190, 223, 211, 208, 192, 172, 187, 248, 187, 216, 202, 213, 185, 166, 196, 220, 181, 196, 177, 224, 179, 204, 211, 239, 209, 212,
		161, 163, 10,
	}
)

func ExampleTextDetector() {
	detector := NewTextDetector()
	result, err := detector.DetectBest(zh_gb18030_text)
	if err == nil {
		fmt.Printf(
			"Detected charset is %s, language is %s",
			result.Charset,
			result.Language)
	}
	// Output:
	// Detected charset is GB-18030, language is zh
}
<commit_msg>Move example test to it's own package<commit_after>package chardet_test

import (
	"fmt"
	"github.com/saintfish/chardet"
)

var (
	zh_gb18030_text = []byte{
		71, 111, 202, 199, 71, 111, 111, 103, 108, 101, 233, 95, 176, 108, 181, 196, 210, 187, 214, 214, 190, 142, 215, 103, 208, 205, 163, 172, 129, 75, 176, 108,
		208, 205, 163, 172, 178, 162, 190, 223, 211, 208, 192, 172, 187, 248, 187, 216, 202, 213, 185, 166, 196, 220, 181, 196, 177, 224, 179, 204, 211, 239, 209, 212,
		161, 163, 10,
	}
)

func ExampleTextDetector() {
	detector := chardet.NewTextDetector()
	result, err := detector.DetectBest(zh_gb18030_text)
	if err == nil {
		fmt.Printf(
			"Detected charset is %s, language is %s",
			result.Charset,
			result.Language)
	}
	// Output:
	// Detected charset is GB-18030, language is zh
}
<|endoftext|>


<commit_before>package cdp_test

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"github.com/mafredri/cdp"
	"github.com/mafredri/cdp/devtool"
	"github.com/mafredri/cdp/protocol/dom"
	"github.com/mafredri/cdp/protocol/page"
	"github.com/mafredri/cdp/rpcc"
)

func Example() {
	err := run(5 * time.Second)
	if err != nil {
		log.Fatal(err)
	}
}

func run(timeout time.Duration) error {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	// Use the DevTools HTTP/JSON API to manage targets (e.g. pages, webworkers).
	devt := devtool.New("http://127.0.0.1:9222")
	pt, err := devt.Get(ctx, devtool.Page)
	if err != nil {
		pt, err = devt.Create(ctx)
		if err != nil {
			return err
		}
	}

	// Initiate a new RPC connection to the Chrome Debugging Protocol target.
	conn, err := rpcc.DialContext(ctx, pt.WebSocketDebuggerURL)
	if err != nil {
		return err
	}
	defer conn.Close() // Leaving connections open will leak memory.

	c := cdp.NewClient(conn)

	// Open a DOMContentEventFired client to buffer this event.
	domContent, err := c.Page.DOMContentEventFired(ctx)
	if err != nil {
		return err
	}
	defer domContent.Close()

	// Enable events on the Page domain, it's often preferrable to create
	// event clients before enabling events so that we don't miss any.
	if err = c.Page.Enable(ctx); err != nil {
		return err
	}

	// Create the Navigate arguments with the optional Referrer field set.
	navArgs := page.NewNavigateArgs("https://www.google.com").
		SetReferrer("https://duckduckgo.com")
	nav, err := c.Page.Navigate(ctx, navArgs)
	if err != nil {
		return err
	}

	// Wait until we have a DOMContentEventFired event.
	if _, err = domContent.Recv(); err != nil {
		return err
	}

	fmt.Printf("Page loaded with frame ID: %s\n", nav.FrameID)

	// Fetch the document root node. We can pass nil here
	// since this method only takes optional arguments.
	doc, err := c.DOM.GetDocument(ctx, nil)
	if err != nil {
		return err
	}

	// Get the outer HTML for the page.
	result, err := c.DOM.GetOuterHTML(ctx, &dom.GetOuterHTMLArgs{
		NodeID: doc.Root.NodeID,
	})
	if err != nil {
		return err
	}

	fmt.Printf("HTML: %s\n", result.OuterHTML)

	// Capture a screenshot of the current page.
	screenshotName := "screenshot.jpg"
	screenshotArgs := page.NewCaptureScreenshotArgs().
		SetFormat("jpeg").
		SetQuality(80)
	screenshot, err := c.Page.CaptureScreenshot(ctx, screenshotArgs)
	if err != nil {
		return err
	}
	if err = ioutil.WriteFile(screenshotName, screenshot.Data, 0644); err != nil {
		return err
	}

	fmt.Printf("Saved screenshot: %s\n", screenshotName)

	return nil
}
<commit_msg>Fix browser test for updated protocol<commit_after>package cdp_test

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"github.com/mafredri/cdp"
	"github.com/mafredri/cdp/devtool"
	"github.com/mafredri/cdp/protocol/dom"
	"github.com/mafredri/cdp/protocol/page"
	"github.com/mafredri/cdp/rpcc"
)

func Example() {
	err := run(5 * time.Second)
	if err != nil {
		log.Fatal(err)
	}
}

func run(timeout time.Duration) error {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	// Use the DevTools HTTP/JSON API to manage targets (e.g. pages, webworkers).
	devt := devtool.New("http://127.0.0.1:9222")
	pt, err := devt.Get(ctx, devtool.Page)
	if err != nil {
		pt, err = devt.Create(ctx)
		if err != nil {
			return err
		}
	}

	// Initiate a new RPC connection to the Chrome Debugging Protocol target.
	conn, err := rpcc.DialContext(ctx, pt.WebSocketDebuggerURL)
	if err != nil {
		return err
	}
	defer conn.Close() // Leaving connections open will leak memory.

	c := cdp.NewClient(conn)

	// Open a DOMContentEventFired client to buffer this event.
	domContent, err := c.Page.DOMContentEventFired(ctx)
	if err != nil {
		return err
	}
	defer domContent.Close()

	// Enable events on the Page domain, it's often preferrable to create
	// event clients before enabling events so that we don't miss any.
	if err = c.Page.Enable(ctx); err != nil {
		return err
	}

	// Create the Navigate arguments with the optional Referrer field set.
	navArgs := page.NewNavigateArgs("https://www.google.com").
		SetReferrer("https://duckduckgo.com")
	nav, err := c.Page.Navigate(ctx, navArgs)
	if err != nil {
		return err
	}

	// Wait until we have a DOMContentEventFired event.
	if _, err = domContent.Recv(); err != nil {
		return err
	}

	fmt.Printf("Page loaded with frame ID: %s\n", nav.FrameID)

	// Fetch the document root node. We can pass nil here
	// since this method only takes optional arguments.
	doc, err := c.DOM.GetDocument(ctx, nil)
	if err != nil {
		return err
	}

	// Get the outer HTML for the page.
	result, err := c.DOM.GetOuterHTML(ctx, &dom.GetOuterHTMLArgs{
		NodeID: &doc.Root.NodeID,
	})
	if err != nil {
		return err
	}

	fmt.Printf("HTML: %s\n", result.OuterHTML)

	// Capture a screenshot of the current page.
	screenshotName := "screenshot.jpg"
	screenshotArgs := page.NewCaptureScreenshotArgs().
		SetFormat("jpeg").
		SetQuality(80)
	screenshot, err := c.Page.CaptureScreenshot(ctx, screenshotArgs)
	if err != nil {
		return err
	}
	if err = ioutil.WriteFile(screenshotName, screenshot.Data, 0644); err != nil {
		return err
	}

	fmt.Printf("Saved screenshot: %s\n", screenshotName)

	return nil
}
<|endoftext|>


<commit_before>package jsoniter_test

import (
	"encoding/json"
	"fmt"
	"github.com/json-iterator/go"
	"os"
)

func ExampleMarshal() {
	type ColorGroup struct {
		ID     int
		Name   string
		Colors []string
	}
	group := ColorGroup{
		ID:     1,
		Name:   "Reds",
		Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
	}
	b, err := jsoniter.Marshal(group)
	if err != nil {
		fmt.Println("error:", err)
	}
	os.Stdout.Write(b)
	// Output:
	// {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
}

func ExampleUnmarshal() {
	var jsonBlob = []byte(`[
		{"Name": "Platypus", "Order": "Monotremata"},
		{"Name": "Quoll",    "Order": "Dasyuromorphia"}
	]`)
	type Animal struct {
		Name  string
		Order string
	}
	var animals []Animal
	err := jsoniter.Unmarshal(jsonBlob, &animals)
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%+v", animals)
	// Output:
	// [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
}
<commit_msg>fix import not use<commit_after>package jsoniter_test

import (
	"fmt"
	"os"

	"github.com/json-iterator/go"
)

func ExampleMarshal() {
	type ColorGroup struct {
		ID     int
		Name   string
		Colors []string
	}
	group := ColorGroup{
		ID:     1,
		Name:   "Reds",
		Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
	}
	b, err := jsoniter.Marshal(group)
	if err != nil {
		fmt.Println("error:", err)
	}
	os.Stdout.Write(b)
	// Output:
	// {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
}

func ExampleUnmarshal() {
	var jsonBlob = []byte(`[
		{"Name": "Platypus", "Order": "Monotremata"},
		{"Name": "Quoll",    "Order": "Dasyuromorphia"}
	]`)
	type Animal struct {
		Name  string
		Order string
	}
	var animals []Animal
	err := jsoniter.Unmarshal(jsonBlob, &animals)
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%+v", animals)
	// Output:
	// [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
}
<|endoftext|>