<commit_before>package stripe

import (
	"net/url"
	"strconv"
)

// Coupon Durations
const (
	DurationForever   = "forever"
	DurationOnce      = "once"
	DurationRepeating = "repeating"
)

// see https://stripe.com/docs/api#coupon_object
type Coupon struct {
	// Coupon's Unique Identifier in the system.
	Id string `json:"id"`

	// Describes how long a customer who applies this coupon will get the
	// discount. Possible values are: forever, once, and repeating.
	Duration string `json:"duration"`

	// Percent that will be taken off the subtotal of any invoices for this
	// customer for the duration of the coupon. For example, a coupon with
	// percent_off of 50 will make a $100 invoice $50 instead.
	PercentOff int `json:"percent_off"`

	// If duration is repeating, the number of months the coupon applies. Null
	// if coupon duration is forever or once.
	DurationInMonths Int `json:"duration_in_months,omitempty"`

	// Maximum number of times this coupon can be redeemed by a customer before
	// it is no longer valid.
	MaxRedemptions Int `json:"max_redemptions,omitempty"`

	// Date after which the coupon can no longer be redeemed
	RedeemBy Int64 `json:"redeem_by,omitempty"`

	// Number of times this coupon has been applied to a customer.
	TimesRedeemed int  `json:"times_redeemed,omitempty"`
	Livemode      bool `json:"livemode"`
}

type CouponClient struct{}

// see https://stripe.com/docs/api?lang=java#create_coupon
type CreateCouponReq struct {
	// Unique string of your choice that will be used to identify this coupon
	// when applying it a customer.
	Id string

	// A positive integer between 1 and 100 that represents the discount the
	// coupon will apply.
	PercentOff int

	// Specifies how long the discount will be in effect. Can be forever, once,
	// or repeating.
	Duration string

	// If duration is repeating, a positive integer that specifies the number of
	// months the discount will be in effect.
	DurationInMonths int

	// A positive integer specifying the number of times the coupon can be
	// redeemed before it's no longer valid. For example, you might have a 50%
	// off coupon that the first 20 readers of your blog can use.
	MaxRedemptions int

	// UTC timestamp specifying the last time at which the coupon can be
	// redeemed. After the redeem_by date, the coupon can no longer be applied
	// to new customers.
	RedeemBy int64
}

// see https://stripe.com/docs/api?lang=java#create_coupon
func (self *CouponClient) Create(req *CreateCouponReq) (*Coupon, error) {
	coupon := Coupon{}
	values := url.Values{
		"duration":    {req.Duration},
		"percent_off": {strconv.Itoa(req.PercentOff)},
	}

	// coupon id is optional, add if specified
	if req.Id != "" {
		values.Add("id", req.Id)
	}

	// duration in months is optional, add if specified
	if req.DurationInMonths != 0 {
		values.Add("duration_in_months", strconv.Itoa(req.DurationInMonths))
	}

	// max_redemptions is optional, add if specified
	if req.MaxRedemptions != 0 {
		values.Add("max_redemptions", strconv.Itoa(req.MaxRedemptions))
	}

	// redeem_by is optional, add if specified
	if req.RedeemBy != 0 {
		values.Add("redeem_by", strconv.FormatInt(req.RedeemBy, 10))
	}
	err := query("POST", "/v1/coupons", values, &coupon)
	return &coupon, err
}

// Retrieves the coupon with the given ID.
//
// see https://stripe.com/docs/api?lang=java#retrieve_coupon
func (self *CouponClient) Retrieve(id string) (*Coupon, error) {
	coupon := Coupon{}
	path := "/v1/coupons/" + url.QueryEscape(id)
	err := query("GET", path, nil, &coupon)
	return &coupon, err
}

// Deletes the coupon with the given ID.
//
// see https://stripe.com/docs/api?lang=java#delete_coupon
func (self *CouponClient) Delete(id string) (*Coupon, error) {
	coupon := Coupon{}
	path := "/v1/coupons/" + url.QueryEscape(id)
	err := query("DELETE", path, nil, &coupon)
	return &coupon, err
}

// Returns a list of your coupons.
//
// see https://stripe.com/docs/api?lang=java#list_coupons
func (self *CouponClient) List() ([]*Coupon, error) {
	return self.ListN(10, 0)
}

// Returns a list of your coupons with the specified count and at the specified
// offset.
//
// see https://stripe.com/docs/api?lang=java#list_coupons
func (self *CouponClient) ListN(count int, offset int) ([]*Coupon, error) {
	// define a wrapper function for the Coupon List, so that we can
	// cleanly parse the JSON
	type listCouponResp struct{ Data []*Coupon }
	resp := listCouponResp{}

	// add the count and offset to the list of url values
	values := url.Values{
		"count":  {strconv.Itoa(count)},
		"offset": {strconv.Itoa(offset)},
	}

	err := query("GET", "/v1/coupons", values, &resp)
	if err != nil {
		return nil, err
	}
	return resp.Data, nil
}
<commit_msg>updated Create to check len 0 instead of empty string<commit_after>package stripe

import (
	"net/url"
	"strconv"
)

// Coupon Durations
const (
	DurationForever   = "forever"
	DurationOnce      = "once"
	DurationRepeating = "repeating"
)

// see https://stripe.com/docs/api#coupon_object
type Coupon struct {
	// Coupon's Unique Identifier in the system.
	Id string `json:"id"`

	// Describes how long a customer who applies this coupon will get the
	// discount. Possible values are: forever, once, and repeating.
	Duration string `json:"duration"`

	// Percent that will be taken off the subtotal of any invoices for this
	// customer for the duration of the coupon. For example, a coupon with
	// percent_off of 50 will make a $100 invoice $50 instead.
	PercentOff int `json:"percent_off"`

	// If duration is repeating, the number of months the coupon applies. Null
	// if coupon duration is forever or once.
	DurationInMonths Int `json:"duration_in_months,omitempty"`

	// Maximum number of times this coupon can be redeemed by a customer before
	// it is no longer valid.
	MaxRedemptions Int `json:"max_redemptions,omitempty"`

	// Date after which the coupon can no longer be redeemed
	RedeemBy Int64 `json:"redeem_by,omitempty"`

	// Number of times this coupon has been applied to a customer.
	TimesRedeemed int  `json:"times_redeemed,omitempty"`
	Livemode      bool `json:"livemode"`
}

type CouponClient struct{}

// see https://stripe.com/docs/api?lang=java#create_coupon
type CreateCouponReq struct {
	// Unique string of your choice that will be used to identify this coupon
	// when applying it a customer.
	Id string

	// A positive integer between 1 and 100 that represents the discount the
	// coupon will apply.
	PercentOff int

	// Specifies how long the discount will be in effect. Can be forever, once,
	// or repeating.
	Duration string

	// If duration is repeating, a positive integer that specifies the number of
	// months the discount will be in effect.
	DurationInMonths int

	// A positive integer specifying the number of times the coupon can be
	// redeemed before it's no longer valid. For example, you might have a 50%
	// off coupon that the first 20 readers of your blog can use.
	MaxRedemptions int

	// UTC timestamp specifying the last time at which the coupon can be
	// redeemed. After the redeem_by date, the coupon can no longer be applied
	// to new customers.
	RedeemBy int64
}

// see https://stripe.com/docs/api?lang=java#create_coupon
func (self *CouponClient) Create(req *CreateCouponReq) (*Coupon, error) {
	coupon := Coupon{}
	values := url.Values{
		"duration":    {req.Duration},
		"percent_off": {strconv.Itoa(req.PercentOff)},
	}

	// coupon id is optional, add if specified
	if len(req.Id) != 0 {
		values.Add("id", req.Id)
	}

	// duration in months is optional, add if specified
	if req.DurationInMonths != 0 {
		values.Add("duration_in_months", strconv.Itoa(req.DurationInMonths))
	}

	// max_redemptions is optional, add if specified
	if req.MaxRedemptions != 0 {
		values.Add("max_redemptions", strconv.Itoa(req.MaxRedemptions))
	}

	// redeem_by is optional, add if specified
	if req.RedeemBy != 0 {
		values.Add("redeem_by", strconv.FormatInt(req.RedeemBy, 10))
	}
	err := query("POST", "/v1/coupons", values, &coupon)
	return &coupon, err
}

// Retrieves the coupon with the given ID.
//
// see https://stripe.com/docs/api?lang=java#retrieve_coupon
func (self *CouponClient) Retrieve(id string) (*Coupon, error) {
	coupon := Coupon{}
	path := "/v1/coupons/" + url.QueryEscape(id)
	err := query("GET", path, nil, &coupon)
	return &coupon, err
}

// Deletes the coupon with the given ID.
//
// see https://stripe.com/docs/api?lang=java#delete_coupon
func (self *CouponClient) Delete(id string) (*Coupon, error) {
	coupon := Coupon{}
	path := "/v1/coupons/" + url.QueryEscape(id)
	err := query("DELETE", path, nil, &coupon)
	return &coupon, err
}

// Returns a list of your coupons.
//
// see https://stripe.com/docs/api?lang=java#list_coupons
func (self *CouponClient) List() ([]*Coupon, error) {
	return self.ListN(10, 0)
}

// Returns a list of your coupons with the specified count and at the specified
// offset.
//
// see https://stripe.com/docs/api?lang=java#list_coupons
func (self *CouponClient) ListN(count int, offset int) ([]*Coupon, error) {
	// define a wrapper function for the Coupon List, so that we can
	// cleanly parse the JSON
	type listCouponResp struct{ Data []*Coupon }
	resp := listCouponResp{}

	// add the count and offset to the list of url values
	values := url.Values{
		"count":  {strconv.Itoa(count)},
		"offset": {strconv.Itoa(offset)},
	}

	err := query("GET", "/v1/coupons", values, &resp)
	if err != nil {
		return nil, err
	}
	return resp.Data, nil
}
<|endoftext|>


<commit_before>/*
Package firego is a REST client for Firebase (https://firebase.com).
*/
package firego

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	_url "net/url"
	"strings"
	"sync"
	"time"
)

// TimeoutDuration is the length of time any request will have to establish
// a connection and receive headers from Firebase before returning
// an ErrTimeout error
var TimeoutDuration = 30 * time.Second

var defaultRedirectLimit = 30

// ErrTimeout is an error type is that is returned if a request
// exceeds the TimeoutDuration configured
type ErrTimeout struct {
	error
}

// query parameter constants
const (
	authParam    = "auth"
	formatParam  = "format"
	shallowParam = "shallow"
	formatVal    = "export"
)

// Firebase represents a location in the cloud
type Firebase struct {
	url    string
	params _url.Values
	client *http.Client

	watchMtx     sync.Mutex
	watching     bool
	stopWatching chan struct{}
}

func sanitizeURL(url string) string {
	if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
		url = "https://" + url
	}

	if strings.HasSuffix(url, "/") {
		url = url[:len(url)-1]
	}

	return url
}

// Preserve headers on redirect
// See: https://github.com/golang/go/issues/4800
func redirectPreserveHeaders(req *http.Request, via []*http.Request) error {
	if len(via) == 0 {
		// No redirects
		return nil
	}

	if len(via) > defaultRedirectLimit {
		return fmt.Errorf("%d consecutive requests(redirects)", len(via))
	}

	// mutate the subsequent redirect requests with the first Header
	for key, val := range via[0].Header {
		req.Header[key] = val
	}
	return nil
}

// New creates a new Firebase reference
func New(url string) *Firebase {

	var tr *http.Transport
	tr = &http.Transport{
		DisableKeepAlives: true, // https://code.google.com/p/go/issues/detail?id=3514
		Dial: func(network, address string) (net.Conn, error) {
			start := time.Now()
			c, err := net.DialTimeout(network, address, TimeoutDuration)
			tr.ResponseHeaderTimeout = TimeoutDuration - time.Since(start)
			return c, err
		},
	}

	var client *http.Client
	client = &http.Client{
		Transport:     tr,
		CheckRedirect: redirectPreserveHeaders,
	}

	return &Firebase{
		url:          sanitizeURL(url),
		params:       _url.Values{},
		client:       client,
		stopWatching: make(chan struct{}),
	}
}

// String returns the string representation of the
// Firebase reference
func (fb *Firebase) String() string {
	return fb.url
}

// Child creates a new Firebase reference for the requested
// child with the same configuration as the parent
func (fb *Firebase) Child(child string) *Firebase {
	c := &Firebase{
		url:          fb.url + "/" + child,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	return c
}

// Shallow limits the depth of the data returned when calling Value.
// If the data at the location is a JSON primitive (string, number or boolean),
// its value will be returned. If the data is a JSON object, the values
// for each key will be truncated to true.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-shallow
func (fb *Firebase) Shallow(v bool) {
	if v {
		fb.params.Set(shallowParam, "true")
	} else {
		fb.params.Del(shallowParam)
	}
}

// IncludePriority determines whether or not to ask Firebase
// for the values priority. By default, the priority is not returned
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-format
func (fb *Firebase) IncludePriority(v bool) {
	if v {
		fb.params.Set(formatParam, formatVal)
	} else {
		fb.params.Del(formatParam)
	}
}

func (fb *Firebase) makeRequest(method string, body []byte) (*http.Request, error) {
	path := fb.url + "/.json"

	if len(fb.params) > 0 {
		path += "?" + fb.params.Encode()
	}
	return http.NewRequest(method, path, bytes.NewReader(body))
}

func (fb *Firebase) doRequest(method string, body []byte) ([]byte, error) {
	req, err := fb.makeRequest(method, body)
	if err != nil {
		return nil, err
	}

	resp, err := fb.client.Do(req)
	switch err := err.(type) {
	default:
		return nil, err
	case nil:
		// carry on

	case *_url.Error:
		// `http.Client.Do` will return a `url.Error` that wraps a `net.Error`
		// when exceeding it's `Transport`'s `ResponseHeadersTimeout`
		e1, ok := err.Err.(net.Error)
		if ok && e1.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err

	case net.Error:
		// `http.Client.Do` will return a `net.Error` directly when Dial times
		// out, or when the Client's RoundTripper otherwise returns an err
		if err.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err
	}

	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode/200 != 1 {
		return nil, errors.New(string(respBody))
	}
	return respBody, nil
}
<commit_msg>Adds support for OrderBy StartAt and EndAt<commit_after>/*
Package firego is a REST client for Firebase (https://firebase.com).
*/
package firego

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	_url "net/url"
	"strings"
	"sync"
	"time"
)

// TimeoutDuration is the length of time any request will have to establish
// a connection and receive headers from Firebase before returning
// an ErrTimeout error
var TimeoutDuration = 30 * time.Second

var defaultRedirectLimit = 30

// ErrTimeout is an error type is that is returned if a request
// exceeds the TimeoutDuration configured
type ErrTimeout struct {
	error
}

// query parameter constants
const (
	authParam    = "auth"
	formatParam  = "format"
	shallowParam = "shallow"
	formatVal    = "export"
)

// Firebase represents a location in the cloud
type Firebase struct {
	url    string
	params _url.Values
	client *http.Client

	watchMtx     sync.Mutex
	watching     bool
	stopWatching chan struct{}
}

func sanitizeURL(url string) string {
	if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
		url = "https://" + url
	}

	if strings.HasSuffix(url, "/") {
		url = url[:len(url)-1]
	}

	return url
}

// Preserve headers on redirect
// See: https://github.com/golang/go/issues/4800
func redirectPreserveHeaders(req *http.Request, via []*http.Request) error {
	if len(via) == 0 {
		// No redirects
		return nil
	}

	if len(via) > defaultRedirectLimit {
		return fmt.Errorf("%d consecutive requests(redirects)", len(via))
	}

	// mutate the subsequent redirect requests with the first Header
	for key, val := range via[0].Header {
		req.Header[key] = val
	}
	return nil
}

// New creates a new Firebase reference
func New(url string) *Firebase {

	var tr *http.Transport
	tr = &http.Transport{
		DisableKeepAlives: true, // https://code.google.com/p/go/issues/detail?id=3514
		Dial: func(network, address string) (net.Conn, error) {
			start := time.Now()
			c, err := net.DialTimeout(network, address, TimeoutDuration)
			tr.ResponseHeaderTimeout = TimeoutDuration - time.Since(start)
			return c, err
		},
	}

	var client *http.Client
	client = &http.Client{
		Transport:     tr,
		CheckRedirect: redirectPreserveHeaders,
	}

	return &Firebase{
		url:          sanitizeURL(url),
		params:       _url.Values{},
		client:       client,
		stopWatching: make(chan struct{}),
	}
}

// String returns the string representation of the
// Firebase reference
func (fb *Firebase) String() string {
	return fb.url
}

// Child creates a new Firebase reference for the requested
// child with the same configuration as the parent
func (fb *Firebase) Child(child string) *Firebase {
	c := &Firebase{
		url:          fb.url + "/" + child,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	return c
}

// StartAt creates a new Firebase reference with the
// requested StartAt configuration
func (fb *Firebase) StartAt(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set("startAt", value)
	} else {
		c.params.Del("startAt")
	}
	return c
}

// EndAt creates a new Firebase reference with the
// requested EndAt configuration
func (fb *Firebase) EndAt(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set("endAt", value)
	} else {
		c.params.Del("endAt")
	}
	return c
}

// OrderBy creates a new Firebase reference with the
// requested OrderBy configuration
func (fb *Firebase) OrderBy(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set("orderBy", value)
	} else {
		c.params.Del("orderBy")
	}
	return c
}

// Shallow limits the depth of the data returned when calling Value.
// If the data at the location is a JSON primitive (string, number or boolean),
// its value will be returned. If the data is a JSON object, the values
// for each key will be truncated to true.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-shallow
func (fb *Firebase) Shallow(v bool) {
	if v {
		fb.params.Set(shallowParam, "true")
	} else {
		fb.params.Del(shallowParam)
	}
}

// IncludePriority determines whether or not to ask Firebase
// for the values priority. By default, the priority is not returned
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-format
func (fb *Firebase) IncludePriority(v bool) {
	if v {
		fb.params.Set(formatParam, formatVal)
	} else {
		fb.params.Del(formatParam)
	}
}

func (fb *Firebase) makeRequest(method string, body []byte) (*http.Request, error) {
	path := fb.url + "/.json"

	if len(fb.params) > 0 {
		path += "?" + fb.params.Encode()
	}
	fmt.Printf("Firebase Path: %v ", path)
	return http.NewRequest(method, path, bytes.NewReader(body))
}

func (fb *Firebase) doRequest(method string, body []byte) ([]byte, error) {
	req, err := fb.makeRequest(method, body)
	if err != nil {
		return nil, err
	}

	resp, err := fb.client.Do(req)
	switch err := err.(type) {
	default:
		return nil, err
	case nil:
		// carry on

	case *_url.Error:
		// `http.Client.Do` will return a `url.Error` that wraps a `net.Error`
		// when exceeding it's `Transport`'s `ResponseHeadersTimeout`
		e1, ok := err.Err.(net.Error)
		if ok && e1.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err

	case net.Error:
		// `http.Client.Do` will return a `net.Error` directly when Dial times
		// out, or when the Client's RoundTripper otherwise returns an err
		if err.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err
	}

	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode/200 != 1 {
		return nil, errors.New(string(respBody))
	}
	return respBody, nil
}
<|endoftext|>


<commit_before>package commands

import (
	"github.com/hawser/git-hawser/git"
	"github.com/hawser/git-hawser/hawser"
	"github.com/hawser/git-hawser/scanner"
	"github.com/rubyist/tracerx"
	"github.com/spf13/cobra"
	"io/ioutil"
	"os"
	"strings"
)

var (
	pushCmd = &cobra.Command{
		Use:   "push",
		Short: "Push files to the hawser endpoint",
		Run:   pushCommand,
	}
	dryRun       = false
	useStdin     = false
	deleteBranch = "(delete)"
)

// pushCommand is the command that's run via `git hawser push`. It has two modes
// of operation. The primary mode is run via the git pre-push hook. The pre-push
// hook passes two arguments on the command line:
//   1. Name of the remote to which the push is being done
//   2. URL to which the push is being done
//
// The hook receives commit information on stdin in the form:
//   <local ref> <local sha1> <remote ref> <remote sha1>
//
// In the typical case, pushCommand will get a list of git objects being pushed
// by using the following:
//    git rev-list --objects <local sha1> ^<remote sha1>
//
// If any of those git objects are associated with hawser objects, those hawser
// objects will be pushed to the hawser endpoint.
//
// In the case of pushing a new branch, the list of git objects will be all of
// the git objects in this branch.
//
// In the case of deleting a branch, no attempts to push hawser objects will be
// made.
//
// When pushing hawser objects, the client will first perform an OPTIONS command
// which will determine not only whether or not the client is authorized, but also
// whether or not that hawser endpoint already has the hawser object. If it
// does, the object will not be pushed.
//
// The other mode of operation is the dry run mode. In this mode, the repo
// and refspec are passed on the command line. pushCommand will calculate the
// git objects that would be pushed in a similar manner as above and will print
// out each file name.
func pushCommand(cmd *cobra.Command, args []string) {
	var left, right string

	if len(args) == 0 {
		Print("The git hawser pre-push hook is out of date. Please run `git hawser update`")
		os.Exit(1)
	}

	hawser.Config.CurrentRemote = args[0]

	if useStdin {
		refsData, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			Panic(err, "Error reading refs on stdin")
		}

		if len(refsData) == 0 {
			return
		}

		left, right = decodeRefs(string(refsData))
		if left == deleteBranch {
			return
		}
	} else {
		var repo, refspec string

		if len(args) < 1 {
			Print("Usage: git hawser push --dry-run <repo> [refspec]")
			return
		}

		repo = args[0]
		if len(args) == 2 {
			refspec = args[1]
		}

		localRef, err := git.CurrentRef()
		if err != nil {
			Panic(err, "Error getting local ref")
		}
		left = localRef

		remoteRef, err := git.LsRemote(repo, refspec)
		if err != nil {
			Panic(err, "Error getting remote ref")
		}

		if remoteRef != "" {
			right = "^" + strings.Split(remoteRef, "\t")[0]
		}
	}

	// Just use scanner here
	pointers, err := scanner.Scan(left, right)
	if err != nil {
		Panic(err, "Error scanning for hawser files")
	}

	for i, pointer := range pointers {
		if dryRun {
			Print("push %s", pointer.Name)
			continue
		}
		if wErr := pushAsset(pointer.Oid, pointer.Name, i+1, len(pointers)); wErr != nil {
			if Debugging || wErr.Panic {
				Panic(wErr.Err, wErr.Error())
			} else {
				Exit(wErr.Error())
			}
		}
	}
}

// pushAsset pushes the asset with the given oid to the hawser endpoint. It will
// first make an OPTIONS call. If OPTIONS returns a 200 status, it indicates that the
// hawser endpoint already has a hawser object for that oid. The object will
// not be pushed again.
func pushAsset(oid, filename string, index, totalFiles int) *hawser.WrappedError {
	tracerx.Printf("checking_asset: %s %s %d/%d", oid, filename, index, totalFiles)
	path, err := hawser.LocalMediaPath(oid)
	if err != nil {
		return hawser.Errorf(err, "Error uploading file %s (%s)", filename, oid)
	}

	cb, file, cbErr := hawser.CopyCallbackFile("push", filename, index, totalFiles)
	if cbErr != nil {
		Error(cbErr.Error())
	}

	if file != nil {
		defer file.Close()
	}

	return hawser.Upload(path, filename, cb)
}

// decodeRefs pulls the sha1s out of the line read from the pre-push
// hook's stdin.
func decodeRefs(input string) (string, string) {
	refs := strings.Split(strings.TrimSpace(input), " ")
	var left, right string

	if len(refs) > 1 {
		left = refs[1]
	}

	if len(refs) > 3 {
		right = "^" + refs[3]
	}

	return left, right
}

func init() {
	pushCmd.Flags().BoolVarP(&dryRun, "dry-run", "d", false, "Do everything except actually send the updates")
	pushCmd.Flags().BoolVarP(&useStdin, "stdin", "s", false, "Take refs on stdin (for pre-push hook)")
	RootCmd.AddCommand(pushCmd)
}
<commit_msg>ensure cleaned hawser objects exist before pushing<commit_after>package commands

import (
	"fmt"
	"github.com/hawser/git-hawser/git"
	"github.com/hawser/git-hawser/hawser"
	"github.com/hawser/git-hawser/pointer"
	"github.com/hawser/git-hawser/scanner"
	"github.com/rubyist/tracerx"
	"github.com/spf13/cobra"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var (
	pushCmd = &cobra.Command{
		Use:   "push",
		Short: "Push files to the hawser endpoint",
		Run:   pushCommand,
	}
	dryRun       = false
	useStdin     = false
	deleteBranch = "(delete)"
)

// pushCommand is the command that's run via `git hawser push`. It has two modes
// of operation. The primary mode is run via the git pre-push hook. The pre-push
// hook passes two arguments on the command line:
//   1. Name of the remote to which the push is being done
//   2. URL to which the push is being done
//
// The hook receives commit information on stdin in the form:
//   <local ref> <local sha1> <remote ref> <remote sha1>
//
// In the typical case, pushCommand will get a list of git objects being pushed
// by using the following:
//    git rev-list --objects <local sha1> ^<remote sha1>
//
// If any of those git objects are associated with hawser objects, those hawser
// objects will be pushed to the hawser endpoint.
//
// In the case of pushing a new branch, the list of git objects will be all of
// the git objects in this branch.
//
// In the case of deleting a branch, no attempts to push hawser objects will be
// made.
//
// When pushing hawser objects, the client will first perform an OPTIONS command
// which will determine not only whether or not the client is authorized, but also
// whether or not that hawser endpoint already has the hawser object. If it
// does, the object will not be pushed.
//
// The other mode of operation is the dry run mode. In this mode, the repo
// and refspec are passed on the command line. pushCommand will calculate the
// git objects that would be pushed in a similar manner as above and will print
// out each file name.
func pushCommand(cmd *cobra.Command, args []string) {
	var left, right string

	if len(args) == 0 {
		Print("The git hawser pre-push hook is out of date. Please run `git hawser update`")
		os.Exit(1)
	}

	hawser.Config.CurrentRemote = args[0]

	if useStdin {
		refsData, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			Panic(err, "Error reading refs on stdin")
		}

		if len(refsData) == 0 {
			return
		}

		left, right = decodeRefs(string(refsData))
		if left == deleteBranch {
			return
		}
	} else {
		var repo, refspec string

		if len(args) < 1 {
			Print("Usage: git hawser push --dry-run <repo> [refspec]")
			return
		}

		repo = args[0]
		if len(args) == 2 {
			refspec = args[1]
		}

		localRef, err := git.CurrentRef()
		if err != nil {
			Panic(err, "Error getting local ref")
		}
		left = localRef

		remoteRef, err := git.LsRemote(repo, refspec)
		if err != nil {
			Panic(err, "Error getting remote ref")
		}

		if remoteRef != "" {
			right = "^" + strings.Split(remoteRef, "\t")[0]
		}
	}

	// Just use scanner here
	pointers, err := scanner.Scan(left, right)
	if err != nil {
		Panic(err, "Error scanning for hawser files")
	}

	for i, pointer := range pointers {
		if dryRun {
			Print("push %s", pointer.Name)
			continue
		}
		if wErr := pushAsset(pointer.Oid, pointer.Name, i+1, len(pointers)); wErr != nil {
			if Debugging || wErr.Panic {
				Panic(wErr.Err, wErr.Error())
			} else {
				Exit(wErr.Error())
			}
		}
	}
}

// pushAsset pushes the asset with the given oid to the hawser endpoint. It will
// first make an OPTIONS call. If OPTIONS returns a 200 status, it indicates that the
// hawser endpoint already has a hawser object for that oid. The object will
// not be pushed again.
func pushAsset(oid, filename string, index, totalFiles int) *hawser.WrappedError {
	tracerx.Printf("checking_asset: %s %s %d/%d", oid, filename, index, totalFiles)
	path, err := hawser.LocalMediaPath(oid)
	if err != nil {
		return hawser.Errorf(err, "Error uploading file %s (%s)", filename, oid)
	}

	if err := ensureFile(filename, path); err != nil {
		return hawser.Errorf(err, "Error uploading file %s (%s)", filename, oid)
	}

	cb, file, cbErr := hawser.CopyCallbackFile("push", filename, index, totalFiles)
	if cbErr != nil {
		Error(cbErr.Error())
	}

	if file != nil {
		defer file.Close()
	}

	return hawser.Upload(path, filename, cb)
}

// ensureFile makes sure that the cleanPath exists before pushing it.  If it
// does not exist, it attempts to clean it by reading the file at smudgePath.
func ensureFile(smudgePath, cleanPath string) error {
	if _, err := os.Stat(cleanPath); err == nil {
		return nil
	}

	expectedOid := filepath.Base(cleanPath)
	localPath := filepath.Join(hawser.LocalWorkingDir, smudgePath)
	file, err := os.Open(localPath)
	if err != nil {
		return err
	}

	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		return err
	}

	cleaned, err := pointer.Clean(file, stat.Size(), nil)
	if err != nil {
		return err
	}

	cleaned.Close()

	if expectedOid != cleaned.Oid {
		return fmt.Errorf("Expected %s to have an OID of %s, got %s", smudgePath, expectedOid, cleaned.Oid)
	}

	return nil
}

// decodeRefs pulls the sha1s out of the line read from the pre-push
// hook's stdin.
func decodeRefs(input string) (string, string) {
	refs := strings.Split(strings.TrimSpace(input), " ")
	var left, right string

	if len(refs) > 1 {
		left = refs[1]
	}

	if len(refs) > 3 {
		right = "^" + refs[3]
	}

	return left, right
}

func init() {
	pushCmd.Flags().BoolVarP(&dryRun, "dry-run", "d", false, "Do everything except actually send the updates")
	pushCmd.Flags().BoolVarP(&useStdin, "stdin", "s", false, "Take refs on stdin (for pre-push hook)")
	RootCmd.AddCommand(pushCmd)
}
<|endoftext|>


<commit_before>package commands

import (
	"os"
	"sort"
	"strconv"
	"time"

	"github.com/concourse/fly/rc"
	"github.com/concourse/fly/ui"
	"github.com/dgrijalva/jwt-go"
	"github.com/fatih/color"
)

type TargetsCommand struct{}

func (command *TargetsCommand) Execute([]string) error {
	flyYAML, err := rc.LoadTargets()
	if err != nil {
		return err
	}

	table := ui.Table{
		Headers: ui.TableRow{
			{Contents: "name", Color: color.New(color.Bold)},
			{Contents: "url", Color: color.New(color.Bold)},
			{Contents: "expiry", Color: color.New(color.Bold)},
		},
	}

	for targetName, targetValues := range flyYAML.Targets {
		expirationTime := GetExpirationFromString(targetValues.Token)

		row := ui.TableRow{
			{Contents: string(targetName)},
			{Contents: targetValues.API},
			{Contents: expirationTime},
		}

		table.Data = append(table.Data, row)
	}

	sort.Sort(table.Data)

	return table.Render(os.Stdout)
}

func GetExpirationFromString(token *rc.TargetToken) string {
	if token == nil {
		return "n/a"
	}

	parsedToken, _ := jwt.Parse(token.Value, func(token *jwt.Token) (interface{}, error) {
		return "", nil
	})

	expClaim, ok := parsedToken.Claims["exp"]
	if !ok {
		return "n/a"
	}

	intSeconds, err := strconv.ParseInt(string(expClaim.(string)), 10, 64)
	if err != nil {
		return "n/a"
	}

	unixSeconds := time.Unix(intSeconds, 0)

	return unixSeconds.Format(time.RFC1123)
}
<commit_msg>support empty token struct and unquoted expiration<commit_after>package commands

import (
	"os"
	"sort"
	"strconv"
	"time"

	"github.com/concourse/fly/rc"
	"github.com/concourse/fly/ui"
	"github.com/dgrijalva/jwt-go"
	"github.com/fatih/color"
)

type TargetsCommand struct{}

func (command *TargetsCommand) Execute([]string) error {
	flyYAML, err := rc.LoadTargets()
	if err != nil {
		return err
	}

	table := ui.Table{
		Headers: ui.TableRow{
			{Contents: "name", Color: color.New(color.Bold)},
			{Contents: "url", Color: color.New(color.Bold)},
			{Contents: "expiry", Color: color.New(color.Bold)},
		},
	}

	for targetName, targetValues := range flyYAML.Targets {
		expirationTime := GetExpirationFromString(targetValues.Token)

		row := ui.TableRow{
			{Contents: string(targetName)},
			{Contents: targetValues.API},
			{Contents: expirationTime},
		}

		table.Data = append(table.Data, row)
	}

	sort.Sort(table.Data)

	return table.Render(os.Stdout)
}

func GetExpirationFromString(token *rc.TargetToken) string {
	if token == nil || token.Type == "" || token.Value == "" {
		return "n/a"
	}

	parsedToken, _ := jwt.Parse(token.Value, func(token *jwt.Token) (interface{}, error) {
		return "", nil
	})

	expClaim, ok := parsedToken.Claims["exp"]
	if !ok {
		return "n/a"
	}

	var intSeconds int64

	floatSeconds, ok := expClaim.(float64)
	if ok {
		intSeconds = int64(floatSeconds)
	} else {
		stringSeconds, ok := expClaim.(string)
		if !ok {
			return "n/a"
		}
		var err error
		intSeconds, err = strconv.ParseInt(stringSeconds, 10, 64)
		if err != nil {
			return "n/a"
		}
	}

	unixSeconds := time.Unix(intSeconds, 0)

	return unixSeconds.Format(time.RFC1123)
}
<|endoftext|>


<commit_before>package network

import (
	"../hashtree"
	"fmt"
)

// additional functions to complement network.pb.go

func (id *StaticId) CompactId() string {
	return fmt.Sprintf("%x-%d", id.GetHash(), id.GetLength())
}

func (id *StaticId) Bytes() hashtree.Bytes {
	return hashtree.Bytes(id.GetLength())
}

func (id *StaticId) Blocks() hashtree.Nodes {
	return hashtree.FileNodes(id.Bytes(), hashtree.FILE_BLOCK_SIZE)
}

func (id *StaticId) WidthForLevelOf(in *InnerHashes) hashtree.Nodes {
	return hashtree.LevelWidth(id.Blocks(), hashtree.Level(in.GetHeight()))
}

func NewInnerHashes(height hashtree.Level, from hashtree.Nodes, length hashtree.Nodes, bytes []byte) *InnerHashes {
	h := int32(height)
	f := int32(from)
	l := int32(length)
	return &InnerHashes{
		Height: &h,
		From:   &f,
		Length: &l,
		Hashes: bytes,
	}
}

func (in *InnerHashes) GetHeightL() hashtree.Level {
	return hashtree.Level(in.GetHeight())
}
func (in *InnerHashes) GetLengthN() hashtree.Nodes {
	return hashtree.Nodes(in.GetLength())
}

func (in *InnerHashes) GetFromN() hashtree.Nodes {
	return hashtree.Nodes(in.GetFrom())
}

func (in *InnerHashes) CheckWellFormedForId(id *StaticId) error {
	if in.GetFrom() < 0 {
		return fmt.Errorf("from %v is less than 0", in.GetFrom())
	}
	if in.GetLength()*hashtree.HASH_BYTES != int32(len(in.GetHashes())) {
		return fmt.Errorf("reported length %v blocks != length of data %v bytes", in.GetLength(), len(in.GetHashes()))
	}
	width := id.WidthForLevelOf(in)
	if in.GetFromN()+in.GetLengthN() > width {
		return fmt.Errorf("hash form %v for %v is longer than width of %v", in.GetFrom(), in.GetLength(), width)
	}

	//todo: more checks
	return nil
}

//Only use under SplitLocalSummable.
//Get the bytes of the local root sum.
func (in *InnerHashes) LocalSum() []byte {
	c := hashtree.NewNoPadTree()
	c.Write(in.GetHashes())
	return c.Sum(nil)
}

//Only use under SplitLocalSummable
//Get the position of the local root sum.
func (in *InnerHashes) LocalRoot(leafs hashtree.Nodes) (level hashtree.Level, node hashtree.Nodes) {
	h := in.GetHeightL()
	f := in.GetFromN()
	l := in.GetLengthN()
	n := hashtree.Levels(l) - 1
	level = h + n
	node = f >> uint32(n)
	for node != 0 && node%2 == 0 && node+1 == hashtree.LevelWidth(leafs, level) {
		//the node and it's parent have the same hash, the parent is the "better" root
		level += 1
		node /= 2
	}
	return
}

func logb(n hashtree.Nodes) hashtree.Nodes {
	i := hashtree.Nodes(0)
	for ; n >= 16; i += 5 {
		n /= 32
	}
	for ; n > 0; i++ {
		n /= 2
	}
	return i
}

func expb(n hashtree.Nodes) hashtree.Nodes {
	if n == 0 {
		return 0
	}
	n--
	i := hashtree.Nodes(1)
	for ; n >= 5; i *= 32 {
		n -= 5
	}
	for ; n > 0; i *= 2 {
		n--
	}
	return i
}

func (in *InnerHashes) Part(from hashtree.Nodes, to hashtree.Nodes) *InnerHashes {
	return NewInnerHashes(in.GetHeightL(), from, to-from,
		in.Hashes[(from-in.GetFromN())*hashtree.HASH_BYTES:(to-from)*hashtree.HASH_BYTES])
}

func (in *InnerHashes) Parts(l [][2]hashtree.Nodes) []*InnerHashes {
	r := make([]*InnerHashes, len(l))
	for _, v := range l {
		r = append(r, in.Part(v[0], v[1]))
	}
	return r
}

func mergeR(a [][2]hashtree.Nodes, b [][2]hashtree.Nodes) [][2]hashtree.Nodes {
	result := make([][2]hashtree.Nodes, len(a)+len(b))
	copy(result, a)
	copy(result[len(a):], b)
	return result
}

func shiftsls(sls [][2]hashtree.Nodes, delta hashtree.Nodes) [][2]hashtree.Nodes {
	for i := 0; i < len(sls); i++ {
		sls[i][0] += delta
		sls[i][1] += delta
	}
	return sls
}

func sls(from hashtree.Nodes, to hashtree.Nodes, width hashtree.Nodes) [][2]hashtree.Nodes {
	from = (from + 1) / 2 * 2
	if from > to || to >= width {
		panic(fmt.Sprintf("from:%v, to:%v, width%v", from, to, width))
	}

	if from == to {
		//there souldn't be any singles, unless it is the last one and even
		if from == width-1 && from%2 == 0 {
			return [][2]hashtree.Nodes{{from, to}}
		}
		return nil
	}
	if from == 0 {
		dev := expb(logb(to + 1))
		//log.Println(from,to,width,dev);
		if to == width-1 || to == dev-1 {
			return [][2]hashtree.Nodes{{from, to}}
		}
		return mergeR(sls(from, dev-1, dev), shiftsls(sls(0, to-dev, width-dev), dev))
	} else {
		dev := expb(logb(width - 1))
		//log.Println(from,to,width,dev);
		if from < dev {
			if to < dev {
				return sls(from, to, dev)
			} else {
				return mergeR(sls(from, dev-1, dev), shiftsls(sls(0, to-dev, width-dev), dev))
			}
		} else {
			return shiftsls(sls(from-dev, to-dev, width-dev), dev)
		}
	}
}

func (in *InnerHashes) SplitLocalSummable(id *StaticId) []*InnerHashes {
	if err := in.CheckWellFormedForId(id); err != nil {
		panic(err)
	}
	ranges := sls(hashtree.Nodes(in.GetFrom()), hashtree.Nodes(in.GetFrom()+in.GetLength()), id.WidthForLevelOf(in))
	return in.Parts(ranges)
}
<commit_msg>don't return pointers for InnerHashes<commit_after>package network

import (
	"../hashtree"
	"fmt"
)

// additional functions to complement network.pb.go

func (id *StaticId) CompactId() string {
	return fmt.Sprintf("%x-%d", id.GetHash(), id.GetLength())
}

func (id *StaticId) Bytes() hashtree.Bytes {
	return hashtree.Bytes(id.GetLength())
}

func (id *StaticId) Blocks() hashtree.Nodes {
	return hashtree.FileNodes(id.Bytes(), hashtree.FILE_BLOCK_SIZE)
}

func (id *StaticId) WidthForLevelOf(in *InnerHashes) hashtree.Nodes {
	return hashtree.LevelWidth(id.Blocks(), hashtree.Level(in.GetHeight()))
}

func NewInnerHashes(height hashtree.Level, from hashtree.Nodes, length hashtree.Nodes, bytes []byte) InnerHashes {
	h := int32(height)
	f := int32(from)
	l := int32(length)
	return InnerHashes{
		Height: &h,
		From:   &f,
		Length: &l,
		Hashes: bytes,
	}
}

func (in *InnerHashes) GetHeightL() hashtree.Level {
	return hashtree.Level(in.GetHeight())
}
func (in *InnerHashes) GetLengthN() hashtree.Nodes {
	return hashtree.Nodes(in.GetLength())
}

func (in *InnerHashes) GetFromN() hashtree.Nodes {
	return hashtree.Nodes(in.GetFrom())
}

func (in *InnerHashes) CheckWellFormedForId(id *StaticId) error {
	if in.GetFrom() < 0 {
		return fmt.Errorf("from %v is less than 0", in.GetFrom())
	}
	if in.GetLength()*hashtree.HASH_BYTES != int32(len(in.GetHashes())) {
		return fmt.Errorf("reported length %v blocks != length of data %v bytes", in.GetLength(), len(in.GetHashes()))
	}
	width := id.WidthForLevelOf(in)
	if in.GetFromN()+in.GetLengthN() > width {
		return fmt.Errorf("hash form %v for %v is longer than width of %v", in.GetFrom(), in.GetLength(), width)
	}

	//todo: more checks
	return nil
}

//Only use under SplitLocalSummable.
//Get the bytes of the local root sum.
func (in *InnerHashes) LocalSum() []byte {
	c := hashtree.NewNoPadTree()
	c.Write(in.GetHashes())
	return c.Sum(nil)
}

//Only use under SplitLocalSummable
//Get the position of the local root sum.
func (in *InnerHashes) LocalRoot(leafs hashtree.Nodes) (level hashtree.Level, node hashtree.Nodes) {
	h := in.GetHeightL()
	f := in.GetFromN()
	l := in.GetLengthN()
	n := hashtree.Levels(l) - 1
	level = h + n
	node = f >> uint32(n)
	for node != 0 && node%2 == 0 && node+1 == hashtree.LevelWidth(leafs, level) {
		//the node and it's parent have the same hash, the parent is the "better" root
		level += 1
		node /= 2
	}
	return
}

func logb(n hashtree.Nodes) hashtree.Nodes {
	i := hashtree.Nodes(0)
	for ; n >= 16; i += 5 {
		n /= 32
	}
	for ; n > 0; i++ {
		n /= 2
	}
	return i
}

func expb(n hashtree.Nodes) hashtree.Nodes {
	if n == 0 {
		return 0
	}
	n--
	i := hashtree.Nodes(1)
	for ; n >= 5; i *= 32 {
		n -= 5
	}
	for ; n > 0; i *= 2 {
		n--
	}
	return i
}

func (in *InnerHashes) Part(from hashtree.Nodes, to hashtree.Nodes) InnerHashes {
	return NewInnerHashes(in.GetHeightL(), from, to-from,
		in.Hashes[(from-in.GetFromN())*hashtree.HASH_BYTES:(to-from)*hashtree.HASH_BYTES])
}

func (in *InnerHashes) Parts(l [][2]hashtree.Nodes) []InnerHashes {
	r := make([]InnerHashes, len(l))
	for _, v := range l {
		r = append(r, in.Part(v[0], v[1]))
	}
	return r
}

func mergeR(a [][2]hashtree.Nodes, b [][2]hashtree.Nodes) [][2]hashtree.Nodes {
	result := make([][2]hashtree.Nodes, len(a)+len(b))
	copy(result, a)
	copy(result[len(a):], b)
	return result
}

func shiftsls(sls [][2]hashtree.Nodes, delta hashtree.Nodes) [][2]hashtree.Nodes {
	for i := 0; i < len(sls); i++ {
		sls[i][0] += delta
		sls[i][1] += delta
	}
	return sls
}

func sls(from hashtree.Nodes, to hashtree.Nodes, width hashtree.Nodes) [][2]hashtree.Nodes {
	from = (from + 1) / 2 * 2
	if from > to || to >= width {
		panic(fmt.Sprintf("from:%v, to:%v, width%v", from, to, width))
	}

	if from == to {
		//there souldn't be any singles, unless it is the last one and even
		if from == width-1 && from%2 == 0 {
			return [][2]hashtree.Nodes{{from, to}}
		}
		return nil
	}
	if from == 0 {
		dev := expb(logb(to + 1))
		//log.Println(from,to,width,dev);
		if to == width-1 || to == dev-1 {
			return [][2]hashtree.Nodes{{from, to}}
		}
		return mergeR(sls(from, dev-1, dev), shiftsls(sls(0, to-dev, width-dev), dev))
	} else {
		dev := expb(logb(width - 1))
		//log.Println(from,to,width,dev);
		if from < dev {
			if to < dev {
				return sls(from, to, dev)
			} else {
				return mergeR(sls(from, dev-1, dev), shiftsls(sls(0, to-dev, width-dev), dev))
			}
		} else {
			return shiftsls(sls(from-dev, to-dev, width-dev), dev)
		}
	}
}

func (in *InnerHashes) SplitLocalSummable(id *StaticId) []InnerHashes {
	if err := in.CheckWellFormedForId(id); err != nil {
		panic(err)
	}
	ranges := sls(hashtree.Nodes(in.GetFrom()), hashtree.Nodes(in.GetFrom()+in.GetLength()), id.WidthForLevelOf(in))
	return in.Parts(ranges)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"io"
	"log"
	"net"
	"net/http"
	"strconv"
	"time"
)

//go:generate go run scripts/mkpage.go filepost.html

func filepost(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		return
	}

	storage.Lock()
	defer storage.Unlock()

	r.ParseMultipartForm(32 << 20)

	onread := r.FormValue("onread") == "true"

	d, err := strconv.Atoi(r.FormValue("duration"))
	if err != nil {
		log.Printf("duration parse: %s", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	duration, err := time.ParseDuration(fmt.Sprintf("%dm", d))
	if err != nil {
		log.Printf("parse duration: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	from, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		log.Printf("split: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	files := make([]File, 0)
	for _, fh := range r.MultipartForm.File["filenames"] {
		f := File{
			Name: fh.Filename,
			Type: fh.Header["Content-Type"][0],
		}
		files = append(files, f)
	}

	if len(files) == 0 {
		log.Println("no files were specified")
		http.Redirect(w, r, "", http.StatusSeeOther)
		return
	}

	md := &MetaData{
		Type:    StorageFile,
		From:    from,
		Files:   files,
		Created: time.Now(),
		Expire:  time.Now().Add(duration),
		OnRead:  onread,
	}

	if err := storage.Mkdir(md); err != nil {
		log.Printf("mkdir: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	for i, fh := range r.MultipartForm.File["filenames"] {
		in, err := fh.Open()
		if err != nil {
			log.Printf("file upload: %v", err)
			w.Header().Set("Content-Type", "text/html")
			return
		}
		defer in.Close()

		out, err := storage.Create(md, fh.Filename)
		if err != nil {
			log.Printf("storage create: %v", err)
			w.Header().Set("Content-Type", "text/html")
			return
		}
		defer func() {
			if err := out.Close(); err != nil {
				log.Printf("close: %v", err)
			}
		}()

		nbytes, err := io.Copy(out, in)
		if err != nil {
			log.Printf("copy: %v", err)
			w.Header().Set("Content-Type", "text/html")
			return
		}

		uploads.Inc()
		uploadBytes.Add(float64(nbytes))

		log.Printf("uploaded %d bytes for %s as %s", nbytes, fh.Filename, md.Hash)

		md.Files[i].Size = nbytes
	}

	if err := storage.WriteMeta(md); err != nil {
		log.Printf("writemeta: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	t, err := template.New("reply").Parse(filepost_html)
	if err != nil {
		log.Printf("template parse: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	shareURL := fmt.Sprintf("http://%s/retrieve/%s", r.Host, md.Hash)

	w.Header().Set("Content-Type", "text/html")
	w.Header().Set("Cache-Control", "no-cache")
	if err := t.Execute(w, shareURL); err != nil {
		log.Printf("template exec: %v", err)
		return
	}
}
<commit_msg>report expiration time in upload log<commit_after>package main

import (
	"fmt"
	"html/template"
	"io"
	"log"
	"net"
	"net/http"
	"strconv"
	"time"
)

//go:generate go run scripts/mkpage.go filepost.html

func filepost(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		return
	}

	storage.Lock()
	defer storage.Unlock()

	r.ParseMultipartForm(32 << 20)

	onread := r.FormValue("onread") == "true"

	d, err := strconv.Atoi(r.FormValue("duration"))
	if err != nil {
		log.Printf("duration parse: %s", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	duration, err := time.ParseDuration(fmt.Sprintf("%dm", d))
	if err != nil {
		log.Printf("parse duration: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	from, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		log.Printf("split: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	files := make([]File, 0)
	for _, fh := range r.MultipartForm.File["filenames"] {
		f := File{
			Name: fh.Filename,
			Type: fh.Header["Content-Type"][0],
		}
		files = append(files, f)
	}

	if len(files) == 0 {
		log.Println("no files were specified")
		http.Redirect(w, r, "", http.StatusSeeOther)
		return
	}

	md := &MetaData{
		Type:    StorageFile,
		From:    from,
		Files:   files,
		Created: time.Now(),
		Expire:  time.Now().Add(duration),
		OnRead:  onread,
	}

	if err := storage.Mkdir(md); err != nil {
		log.Printf("mkdir: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	for i, fh := range r.MultipartForm.File["filenames"] {
		in, err := fh.Open()
		if err != nil {
			log.Printf("file upload: %v", err)
			w.Header().Set("Content-Type", "text/html")
			return
		}
		defer in.Close()

		out, err := storage.Create(md, fh.Filename)
		if err != nil {
			log.Printf("storage create: %v", err)
			w.Header().Set("Content-Type", "text/html")
			return
		}
		defer func() {
			if err := out.Close(); err != nil {
				log.Printf("close: %v", err)
			}
		}()

		nbytes, err := io.Copy(out, in)
		if err != nil {
			log.Printf("copy: %v", err)
			w.Header().Set("Content-Type", "text/html")
			return
		}

		uploads.Inc()
		uploadBytes.Add(float64(nbytes))

		log.Printf("uploaded %d bytes for %s as %s expires %v", nbytes, fh.Filename, md.Hash, md.Expire)

		md.Files[i].Size = nbytes
	}

	if err := storage.WriteMeta(md); err != nil {
		log.Printf("writemeta: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	t, err := template.New("reply").Parse(filepost_html)
	if err != nil {
		log.Printf("template parse: %v", err)
		w.Header().Set("Content-Type", "text/html")
		return
	}

	shareURL := fmt.Sprintf("http://%s/retrieve/%s", r.Host, md.Hash)

	w.Header().Set("Content-Type", "text/html")
	w.Header().Set("Cache-Control", "no-cache")
	if err := t.Execute(w, shareURL); err != nil {
		log.Printf("template exec: %v", err)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/joho/godotenv"
	"github.com/stretchr/testify/assert"
	"os"
	"testing"
)

func NewTestSlackNotifier() *SlackNotifier {
	godotenv.Load()

	apiToken := os.Getenv("SLACK_API_TOKEN")
	userName := os.Getenv("SLACK_USER_NAME")
	channel := os.Getenv("SLACK_CHANNEL")

	if len(userName) == 0 {
		userName = "zatsu_monitor"
	}

	if len(apiToken) == 0 || len(channel) == 0 {
		return nil
	}

	return NewSlackNotifier(apiToken, userName, "#"+channel)
}

func TestSlackNotifier_PostStatus_Successful(t *testing.T) {
	notifier := NewTestSlackNotifier()

	if notifier == nil {
		return
	}

	err := notifier.PostStatus("https://www.google.co.jp/", 0, 200)
	assert.NoError(t, err)
}

func TestSlackNotifier_PostStatus_Failure(t *testing.T) {
	notifier := NewTestSlackNotifier()

	if notifier == nil {
		return
	}

	err := notifier.PostStatus("https://www.google.co.jp/aaa", 0, 404)
	assert.NoError(t, err)
}
<commit_msg>Tweak test for screenshot<commit_after>package main

import (
	"github.com/joho/godotenv"
	"github.com/stretchr/testify/assert"
	"os"
	"testing"
)

func NewTestSlackNotifier() *SlackNotifier {
	godotenv.Load()

	apiToken := os.Getenv("SLACK_API_TOKEN")
	userName := os.Getenv("SLACK_USER_NAME")
	channel := os.Getenv("SLACK_CHANNEL")

	if len(userName) == 0 {
		userName = "zatsu_monitor"
	}

	if len(apiToken) == 0 || len(channel) == 0 {
		return nil
	}

	return NewSlackNotifier(apiToken, userName, "#"+channel)
}

func TestSlackNotifier_PostStatus_Successful(t *testing.T) {
	notifier := NewTestSlackNotifier()

	if notifier == nil {
		return
	}

	err := notifier.PostStatus("https://www.google.co.jp/", 500, 200)
	assert.NoError(t, err)
}

func TestSlackNotifier_PostStatus_Failure(t *testing.T) {
	notifier := NewTestSlackNotifier()

	if notifier == nil {
		return
	}

	err := notifier.PostStatus("https://www.google.co.jp/aaa", 0, 404)
	assert.NoError(t, err)
}
<|endoftext|>


<commit_before>// Copyright © 2017 The vt-go authors. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package vt

import (
	"bytes"
	"encoding/json"
	"io"
	"mime/multipart"
	"net/url"
	"os"
)

type progressReader struct {
	reader     io.Reader
	total      int64
	read       int64
	progressCh chan<- float32
}

func (pr *progressReader) Read(p []byte) (int, error) {
	n, err := pr.reader.Read(p)
	pr.read += int64(n)
	if pr.progressCh != nil {
		pr.progressCh <- float32(pr.read) / float32(pr.total) * 100
	}
	return n, err
}

// FileScanner represents a file scanner.
type FileScanner struct {
	cli *Client
}

// Scan sends a file to VirusTotal for scanning. The file content is read from
// the r io.Reader and sent to VirusTotal with the provided file name which can
// be left blank. The function also sends a float32 through the progress channel
// indicating the percentage of the file that has been already uploaded. An
// analysis object is returned as soon as the file is uploaded.
func (s *FileScanner) Scan(r io.Reader, filename string, progress chan<- float32) (*Object, error) {

	var uploadURL *url.URL
	var payloadSize int64

	b := bytes.Buffer{}

	// Create multipart writer for the file
	w := multipart.NewWriter(&b)
	f, err := w.CreateFormFile("file", filename)
	if err != nil {
		return nil, err
	}

	// Copy data from input stream to the multiparted file
	if payloadSize, err = io.Copy(f, r); err != nil {
		return nil, err
	}

	w.Close()

	if payloadSize > payloadMaxSize {
		// Payload is bigger than supported by AppEngine in a POST request,
		// let's ask for an upload URL.
		var u string
		if _, err := s.cli.GetData(URL("files/upload_url"), &u); err != nil {
			return nil, err
		}
		if uploadURL, err = url.Parse(u); err != nil {
			return nil, err
		}
	} else {
		uploadURL = URL("files")
	}

	pr := &progressReader{
		reader:     &b,
		total:      int64(b.Len()),
		progressCh: progress}

	headers := map[string]string{"Content-Type": w.FormDataContentType()}

	httpResp, err := s.cli.sendRequest("POST", uploadURL, pr, headers)
	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()

	apiResp, err := s.cli.parseResponse(httpResp)
	if err != nil {
		return nil, err
	}

	analysis := &Object{}
	if err := json.Unmarshal(apiResp.Data, analysis); err != nil {
		return nil, err
	}

	return analysis, nil
}

// ScanFile sends a file to VirusTotal for scanning. This function is similar to
// Scan but it receive an *os.File instead of a io.Reader and a file name.
func (s *FileScanner) ScanFile(f *os.File, progress chan<- float32) (*Object, error) {
	return s.Scan(f, f.Name(), progress)
}
<commit_msg>Improve description of FileScanner.Scan.<commit_after>// Copyright © 2017 The vt-go authors. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package vt

import (
	"bytes"
	"encoding/json"
	"io"
	"mime/multipart"
	"net/url"
	"os"
)

type progressReader struct {
	reader     io.Reader
	total      int64
	read       int64
	progressCh chan<- float32
}

func (pr *progressReader) Read(p []byte) (int, error) {
	n, err := pr.reader.Read(p)
	pr.read += int64(n)
	if pr.progressCh != nil {
		pr.progressCh <- float32(pr.read) / float32(pr.total) * 100
	}
	return n, err
}

// FileScanner represents a file scanner.
type FileScanner struct {
	cli *Client
}

// Scan sends a file to VirusTotal for scanning. The file content is read from
// the r io.Reader and sent to VirusTotal with the provided file name which can
// be left blank. The function also sends a float32 through the progress channel
// indicating the percentage of the file that has been already uploaded. The
// progress channel can be nil if the caller is not interested in receiving
// upload progress updates. An analysis object is returned as soon as the file
// is uploaded.
func (s *FileScanner) Scan(r io.Reader, filename string, progress chan<- float32) (*Object, error) {

	var uploadURL *url.URL
	var payloadSize int64

	b := bytes.Buffer{}

	// Create multipart writer for the file
	w := multipart.NewWriter(&b)
	f, err := w.CreateFormFile("file", filename)
	if err != nil {
		return nil, err
	}

	// Copy data from input stream to the multiparted file
	if payloadSize, err = io.Copy(f, r); err != nil {
		return nil, err
	}

	w.Close()

	if payloadSize > payloadMaxSize {
		// Payload is bigger than supported by AppEngine in a POST request,
		// let's ask for an upload URL.
		var u string
		if _, err := s.cli.GetData(URL("files/upload_url"), &u); err != nil {
			return nil, err
		}
		if uploadURL, err = url.Parse(u); err != nil {
			return nil, err
		}
	} else {
		uploadURL = URL("files")
	}

	pr := &progressReader{
		reader:     &b,
		total:      int64(b.Len()),
		progressCh: progress}

	headers := map[string]string{"Content-Type": w.FormDataContentType()}

	httpResp, err := s.cli.sendRequest("POST", uploadURL, pr, headers)
	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()

	apiResp, err := s.cli.parseResponse(httpResp)
	if err != nil {
		return nil, err
	}

	analysis := &Object{}
	if err := json.Unmarshal(apiResp.Data, analysis); err != nil {
		return nil, err
	}

	return analysis, nil
}

// ScanFile sends a file to VirusTotal for scanning. This function is similar to
// Scan but it receive an *os.File instead of a io.Reader and a file name.
func (s *FileScanner) ScanFile(f *os.File, progress chan<- float32) (*Object, error) {
	return s.Scan(f, f.Name(), progress)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"flag"
	"os/exec"
	"regexp"
	"time"
	"github.com/howeyc/fsnotify"
)

// Seconds to wait for the next job to begin
const WorkDelay = 5

// Pattern to match files which trigger a build
const FilePattern = `(.+\.go|.+\.c)$`

var flag_directory = flag.String("directory", "", "Directory to watch for changes")

var flag_pattern = flag.String("pattern", FilePattern, "Pattern of watched files")

// Run `go build` and print the output if something's gone wrong.
func build() {
	log.Println("Running build command!")

	cmd := exec.Command("go", "build")

	output, err := cmd.Output()

	if err == nil {
		log.Println("Build ok.")
	} else {
		log.Println("Error while building:\n",string(output))
	}
}

func matchesPattern(pattern *regexp.Regexp, file string) bool {
	return pattern.MatchString(file)
}

// Call `build()` periodically (every WorkDelay seconds) if
// there are any jobs to do. Jobs are detected and fed by the
// FS watcher.
func builder(jobs <-chan string) {
	ticker := time.Tick(time.Duration(WorkDelay * 1e9))

	for {
		<-jobs

		build()

		<-ticker
	}
}

func main() {
	flag.Parse()

	watcher, err := fsnotify.NewWatcher()
	defer watcher.Close()

	if err != nil {
		log.Fatal(err)
	}

	err = watcher.Watch(*flag_directory)

	if err != nil {
		log.Fatal(err)
	}

	pattern := regexp.MustCompile(*flag_pattern)
	jobs := make(chan string)

	go builder(jobs)

	for {
		select {
		case ev := <-watcher.Event:
			if ev.Name != "" && matchesPattern(pattern, ev.Name) {
				select {
					case jobs <- ev.Name:
					default:
				}
			}
		case err := <-watcher.Error:
			log.Fatal(err)
		}
	}
}
<commit_msg>Use directory as CWD<commit_after>package main

import (
	"log"
	"flag"
	"os/exec"
	"regexp"
	"time"
	"github.com/howeyc/fsnotify"
)

// Seconds to wait for the next job to begin
const WorkDelay = 5

// Pattern to match files which trigger a build
const FilePattern = `(.+\.go|.+\.c)$`

var flag_directory = flag.String("directory", "", "Directory to watch for changes")

var flag_pattern = flag.String("pattern", FilePattern, "Pattern of watched files")

// Run `go build` and print the output if something's gone wrong.
func build() {
	log.Println("Running build command!")

	cmd := exec.Command("go", "build")

	cmd.Dir = *flag_directory

	output, err := cmd.Output()

	if err == nil {
		log.Println("Build ok.")
	} else {
		log.Println("Error while building:\n",string(output))
	}
}

func matchesPattern(pattern *regexp.Regexp, file string) bool {
	return pattern.MatchString(file)
}

// Call `build()` periodically (every WorkDelay seconds) if
// there are any jobs to do. Jobs are detected and fed by the
// FS watcher.
func builder(jobs <-chan string) {
	ticker := time.Tick(time.Duration(WorkDelay * 1e9))

	for {
		<-jobs

		build()

		<-ticker
	}
}

func main() {
	flag.Parse()

	watcher, err := fsnotify.NewWatcher()
	defer watcher.Close()

	if err != nil {
		log.Fatal(err)
	}

	err = watcher.Watch(*flag_directory)

	if err != nil {
		log.Fatal(err)
	}

	pattern := regexp.MustCompile(*flag_pattern)
	jobs := make(chan string)

	go builder(jobs)

	for {
		select {
		case ev := <-watcher.Event:
			if ev.Name != "" && matchesPattern(pattern, ev.Name) {
				select {
					case jobs <- ev.Name:
					default:
				}
			}
		case err := <-watcher.Error:
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>/*
Package firego is a REST client for Firebase (https://firebase.com).
*/
package firego

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	_url "net/url"
	"strconv"
	"strings"
	"sync"
	"time"
)

// TimeoutDuration is the length of time any request will have to establish
// a connection and receive headers from Firebase before returning
// an ErrTimeout error.
var TimeoutDuration = 30 * time.Second

var defaultRedirectLimit = 30

// ErrTimeout is an error type is that is returned if a request
// exceeds the TimeoutDuration configured.
type ErrTimeout struct {
	error
}

// query parameter constants
const (
	authParam         = "auth"
	formatParam       = "format"
	shallowParam      = "shallow"
	orderByParam      = "orderBy"
	startAtParam      = "startAt"
	endAtParam        = "endAt"
	formatVal         = "export"
	limitToFirstParam = "limitToFirst"
	limitToLastParam  = "limitToLast"
)

// Firebase represents a location in the cloud.
type Firebase struct {
	url    string
	params _url.Values
	client *http.Client

	watchMtx     sync.Mutex
	watching     bool
	stopWatching chan struct{}
}

func sanitizeURL(url string) string {
	if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
		url = "https://" + url
	}

	if strings.HasSuffix(url, "/") {
		url = url[:len(url)-1]
	}

	return url
}

// Preserve headers on redirect.
//
// Reference https://github.com/golang/go/issues/4800
func redirectPreserveHeaders(req *http.Request, via []*http.Request) error {
	if len(via) == 0 {
		// No redirects
		return nil
	}

	if len(via) > defaultRedirectLimit {
		return fmt.Errorf("%d consecutive requests(redirects)", len(via))
	}

	// mutate the subsequent redirect requests with the first Header
	for key, val := range via[0].Header {
		req.Header[key] = val
	}
	return nil
}

// New creates a new Firebase reference,
// if client is nil, http.DefaultClient is used.
func New(url string, client *http.Client) *Firebase {

	if client == nil {
		var tr *http.Transport
		tr = &http.Transport{
			DisableKeepAlives: true, // https://code.google.com/p/go/issues/detail?id=3514
			Dial: func(network, address string) (net.Conn, error) {
				start := time.Now()
				c, err := net.DialTimeout(network, address, TimeoutDuration)
				tr.ResponseHeaderTimeout = TimeoutDuration - time.Since(start)
				return c, err
			},
		}

		client = &http.Client{
			Transport:     tr,
			CheckRedirect: redirectPreserveHeaders,
		}
	}

	return &Firebase{
		url:          sanitizeURL(url),
		params:       _url.Values{},
		client:       client,
		stopWatching: make(chan struct{}),
	}
}

// String returns the string representation of the
// Firebase reference.
func (fb *Firebase) String() string {
	return fb.url
}

// Child creates a new Firebase reference for the requested
// child with the same configuration as the parent.
func (fb *Firebase) Child(child string) *Firebase {
	c := &Firebase{
		url:          fb.url + "/" + child,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	return c
}

// StartAt creates a new Firebase reference with the
// requested StartAt configuration.
//
// Reference https://www.firebase.com/docs/rest/guide/retrieving-data.html#section-rest-filtering
func (fb *Firebase) StartAt(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set(startAtParam, value)
	} else {
		c.params.Del(startAtParam)
	}
	return c
}

// EndAt creates a new Firebase reference with the
// requested EndAt configuration.
//
// Reference https://www.firebase.com/docs/rest/guide/retrieving-data.html#section-rest-filtering
func (fb *Firebase) EndAt(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set(endAtParam, value)
	} else {
		c.params.Del(endAtParam)
	}
	return c
}

// OrderBy creates a new Firebase reference with the
// requested OrderBy configuration.
//
// Reference https://www.firebase.com/docs/rest/guide/retrieving-data.html#section-rest-filtering
func (fb *Firebase) OrderBy(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set(orderByParam, value)
	} else {
		c.params.Del(orderByParam)
	}
	return c
}

// LimitToFirst creates a new Firebase reference with the
// requested limitToFirst configuration.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-query
func (fb *Firebase) LimitToFirst(value int64) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value > 0 {
		c.params.Set(limitToFirstParam, strconv.FormatInt(value, 10))
	} else {
		c.params.Del(limitToFirstParam)
	}
	return c
}

// LimitToLast creates a new Firebase reference with the
// requested limitToLast configuration.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-query
func (fb *Firebase) LimitToLast(value int64) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value > 0 {
		c.params.Set(limitToLastParam, strconv.FormatInt(value, 10))
	} else {
		c.params.Del(limitToLastParam)
	}
	return c
}

// Shallow limits the depth of the data returned when calling Value.
// If the data at the location is a JSON primitive (string, number or boolean),
// its value will be returned. If the data is a JSON object, the values
// for each key will be truncated to true.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-shallow
func (fb *Firebase) Shallow(v bool) {
	if v {
		fb.params.Set(shallowParam, "true")
	} else {
		fb.params.Del(shallowParam)
	}
}

// IncludePriority determines whether or not to ask Firebase
// for the values priority. By default, the priority is not returned.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-format
func (fb *Firebase) IncludePriority(v bool) {
	if v {
		fb.params.Set(formatParam, formatVal)
	} else {
		fb.params.Del(formatParam)
	}
}

func (fb *Firebase) makeRequest(method string, body []byte) (*http.Request, error) {
	path := fb.url + "/.json"

	if len(fb.params) > 0 {
		path += "?" + fb.params.Encode()
	}
	return http.NewRequest(method, path, bytes.NewReader(body))
}

func (fb *Firebase) doRequest(method string, body []byte) ([]byte, error) {
	req, err := fb.makeRequest(method, body)
	if err != nil {
		return nil, err
	}

	resp, err := fb.client.Do(req)
	switch err := err.(type) {
	default:
		return nil, err
	case nil:
		// carry on

	case *_url.Error:
		// `http.Client.Do` will return a `url.Error` that wraps a `net.Error`
		// when exceeding it's `Transport`'s `ResponseHeadersTimeout`
		e1, ok := err.Err.(net.Error)
		if ok && e1.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err

	case net.Error:
		// `http.Client.Do` will return a `net.Error` directly when Dial times
		// out, or when the Client's RoundTripper otherwise returns an err
		if err.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err
	}

	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode/200 != 1 {
		return nil, errors.New(string(respBody))
	}
	return respBody, nil
}
<commit_msg>removing code duplication for copying a firebase instance<commit_after>/*
Package firego is a REST client for Firebase (https://firebase.com).
*/
package firego

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	_url "net/url"
	"strconv"
	"strings"
	"sync"
	"time"
)

// TimeoutDuration is the length of time any request will have to establish
// a connection and receive headers from Firebase before returning
// an ErrTimeout error.
var TimeoutDuration = 30 * time.Second

var defaultRedirectLimit = 30

// ErrTimeout is an error type is that is returned if a request
// exceeds the TimeoutDuration configured.
type ErrTimeout struct {
	error
}

// query parameter constants
const (
	authParam         = "auth"
	formatParam       = "format"
	shallowParam      = "shallow"
	orderByParam      = "orderBy"
	startAtParam      = "startAt"
	endAtParam        = "endAt"
	formatVal         = "export"
	limitToFirstParam = "limitToFirst"
	limitToLastParam  = "limitToLast"
)

// Firebase represents a location in the cloud.
type Firebase struct {
	url    string
	params _url.Values
	client *http.Client

	watchMtx     sync.Mutex
	watching     bool
	stopWatching chan struct{}
}

func sanitizeURL(url string) string {
	if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
		url = "https://" + url
	}

	if strings.HasSuffix(url, "/") {
		url = url[:len(url)-1]
	}

	return url
}

// Preserve headers on redirect.
//
// Reference https://github.com/golang/go/issues/4800
func redirectPreserveHeaders(req *http.Request, via []*http.Request) error {
	if len(via) == 0 {
		// No redirects
		return nil
	}

	if len(via) > defaultRedirectLimit {
		return fmt.Errorf("%d consecutive requests(redirects)", len(via))
	}

	// mutate the subsequent redirect requests with the first Header
	for key, val := range via[0].Header {
		req.Header[key] = val
	}
	return nil
}

// New creates a new Firebase reference,
// if client is nil, http.DefaultClient is used.
func New(url string, client *http.Client) *Firebase {

	if client == nil {
		var tr *http.Transport
		tr = &http.Transport{
			DisableKeepAlives: true, // https://code.google.com/p/go/issues/detail?id=3514
			Dial: func(network, address string) (net.Conn, error) {
				start := time.Now()
				c, err := net.DialTimeout(network, address, TimeoutDuration)
				tr.ResponseHeaderTimeout = TimeoutDuration - time.Since(start)
				return c, err
			},
		}

		client = &http.Client{
			Transport:     tr,
			CheckRedirect: redirectPreserveHeaders,
		}
	}

	return &Firebase{
		url:          sanitizeURL(url),
		params:       _url.Values{},
		client:       client,
		stopWatching: make(chan struct{}),
	}
}

// String returns the string representation of the
// Firebase reference.
func (fb *Firebase) String() string {
	return fb.url
}

// Child creates a new Firebase reference for the requested
// child with the same configuration as the parent.
func (fb *Firebase) Child(child string) *Firebase {
	c := fb.copy()
	c.url = c.url + "/" + child
	return c
}

// StartAt creates a new Firebase reference with the
// requested StartAt configuration.
//
// Reference https://www.firebase.com/docs/rest/guide/retrieving-data.html#section-rest-filtering
func (fb *Firebase) StartAt(value string) *Firebase {
	c := fb.copy()
	if value != "" {
		c.params.Set(startAtParam, value)
	} else {
		c.params.Del(startAtParam)
	}
	return c
}

// EndAt creates a new Firebase reference with the
// requested EndAt configuration.
//
// Reference https://www.firebase.com/docs/rest/guide/retrieving-data.html#section-rest-filtering
func (fb *Firebase) EndAt(value string) *Firebase {
	c := fb.copy()
	if value != "" {
		c.params.Set(endAtParam, value)
	} else {
		c.params.Del(endAtParam)
	}
	return c
}

// OrderBy creates a new Firebase reference with the
// requested OrderBy configuration.
//
// Reference https://www.firebase.com/docs/rest/guide/retrieving-data.html#section-rest-filtering
func (fb *Firebase) OrderBy(value string) *Firebase {
	c := fb.copy()
	if value != "" {
		c.params.Set(orderByParam, value)
	} else {
		c.params.Del(orderByParam)
	}
	return c
}

// LimitToFirst creates a new Firebase reference with the
// requested limitToFirst configuration.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-query
func (fb *Firebase) LimitToFirst(value int64) *Firebase {
	c := fb.copy()
	if value > 0 {
		c.params.Set(limitToFirstParam, strconv.FormatInt(value, 10))
	} else {
		c.params.Del(limitToFirstParam)
	}
	return c
}

// LimitToLast creates a new Firebase reference with the
// requested limitToLast configuration.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-query
func (fb *Firebase) LimitToLast(value int64) *Firebase {
	c := fb.copy()
	if value > 0 {
		c.params.Set(limitToLastParam, strconv.FormatInt(value, 10))
	} else {
		c.params.Del(limitToLastParam)
	}
	return c
}

// Shallow limits the depth of the data returned when calling Value.
// If the data at the location is a JSON primitive (string, number or boolean),
// its value will be returned. If the data is a JSON object, the values
// for each key will be truncated to true.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-shallow
func (fb *Firebase) Shallow(v bool) {
	if v {
		fb.params.Set(shallowParam, "true")
	} else {
		fb.params.Del(shallowParam)
	}
}

// IncludePriority determines whether or not to ask Firebase
// for the values priority. By default, the priority is not returned.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-format
func (fb *Firebase) IncludePriority(v bool) {
	if v {
		fb.params.Set(formatParam, formatVal)
	} else {
		fb.params.Del(formatParam)
	}
}

func (fb *Firebase) copy() *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	return c
}

func (fb *Firebase) makeRequest(method string, body []byte) (*http.Request, error) {
	path := fb.url + "/.json"

	if len(fb.params) > 0 {
		path += "?" + fb.params.Encode()
	}
	return http.NewRequest(method, path, bytes.NewReader(body))
}

func (fb *Firebase) doRequest(method string, body []byte) ([]byte, error) {
	req, err := fb.makeRequest(method, body)
	if err != nil {
		return nil, err
	}

	resp, err := fb.client.Do(req)
	switch err := err.(type) {
	default:
		return nil, err
	case nil:
		// carry on

	case *_url.Error:
		// `http.Client.Do` will return a `url.Error` that wraps a `net.Error`
		// when exceeding it's `Transport`'s `ResponseHeadersTimeout`
		e1, ok := err.Err.(net.Error)
		if ok && e1.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err

	case net.Error:
		// `http.Client.Do` will return a `net.Error` directly when Dial times
		// out, or when the Client's RoundTripper otherwise returns an err
		if err.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err
	}

	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode/200 != 1 {
		return nil, errors.New(string(respBody))
	}
	return respBody, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 The draw2d Authors. All rights reserved.
// created: 16/12/2017 by Drahoslav Bednářpackage draw2dsvg

package draw2dsvg

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"github.com/llgcode/draw2d"
	"image"
	"image/color"
	"image/png"
	"math"
	"strconv"
	"strings"
)

func toSvgRGBA(c color.Color) string {
	r, g, b, a := c.RGBA()
	r, g, b, a = r>>8, g>>8, b>>8, a>>8
	if a == 255 {
		return optiSprintf("#%02X%02X%02X", r, g, b)
	}
	return optiSprintf("rgba(%v,%v,%v,%f)", r, g, b, float64(a)/255)
}

func toSvgLength(l float64) string {
	if math.IsInf(l, 1) {
		return "100%"
	}
	return optiSprintf("%f", l)
}

func toSvgArray(nums []float64) string {
	arr := make([]string, len(nums))
	for i, num := range nums {
		arr[i] = optiSprintf("%f", num)
	}
	return strings.Join(arr, ",")
}

func toSvgFillRule(rule draw2d.FillRule) string {
	return map[draw2d.FillRule]string{
		draw2d.FillRuleEvenOdd: "evenodd",
		draw2d.FillRuleWinding: "nonzero",
	}[rule]
}

func toSvgPathDesc(p *draw2d.Path) string {
	parts := make([]string, len(p.Components))
	ps := p.Points
	for i, cmp := range p.Components {
		switch cmp {
		case draw2d.MoveToCmp:
			parts[i] = optiSprintf("M %f,%f", ps[0], ps[1])
			ps = ps[2:]
		case draw2d.LineToCmp:
			parts[i] = optiSprintf("L %f,%f", ps[0], ps[1])
			ps = ps[2:]
		case draw2d.QuadCurveToCmp:
			parts[i] = optiSprintf("Q %f,%f %f,%f", ps[0], ps[1], ps[2], ps[3])
			ps = ps[4:]
		case draw2d.CubicCurveToCmp:
			parts[i] = optiSprintf("C %f,%f %f,%f %f,%f", ps[0], ps[1], ps[2], ps[3], ps[4], ps[5])
			ps = ps[6:]
		case draw2d.ArcToCmp:
			cx, cy := ps[0], ps[1] // center
			rx, ry := ps[2], ps[3] // radii
			fi := ps[4] + ps[5]    // startAngle + angle

			// compute endpoint
			sinfi, cosfi := math.Sincos(fi)
			nom := math.Hypot(ry*cosfi, rx*sinfi)
			x := cx + (rx*ry*cosfi)/nom
			y := cy + (rx*ry*sinfi)/nom

			// compute large and sweep flags
			large := 0
			sweep := 0
			if math.Abs(ps[5]) > math.Pi {
				large = 1
			}
			if !math.Signbit(ps[5]) {
				sweep = 1
			}
			// dirty hack to ensure whole arc is drawn
			// if start point equals end point
			if sweep == 1 {
				x += 0.01 * sinfi
				y += 0.01 * -cosfi
			} else {
				x += 0.01 * sinfi
				y += 0.01 * cosfi
			}

			// rx ry x-axis-rotation large-arc-flag sweep-flag x y
			parts[i] = optiSprintf("A %f %f %v %v %v %F %F",
				rx, ry, 0, large, sweep, x, y,
			)
			ps = ps[6:]
		case draw2d.CloseCmp:
			parts[i] = "Z"
		}
	}
	return strings.Join(parts, " ")
}

func toSvgTransform(mat draw2d.Matrix) string {
	if mat.IsIdentity() {
		return ""
	}
	if mat.IsTranslation() {
		x, y := mat.GetTranslation()
		return optiSprintf("translate(%f,%f)", x, y)
	}
	return optiSprintf("matrix(%f,%f,%f,%f,%f,%f)",
		mat[0], mat[1], mat[2], mat[3], mat[4], mat[5],
	)
}

func imageToSvgHref(image image.Image) string {
	out := "data:image/png;base64,"
	pngBuf := &bytes.Buffer{}
	png.Encode(pngBuf, image)
	out += base64.RawStdEncoding.EncodeToString(pngBuf.Bytes())
	return out
}

// Do the same thing as fmt.Sprintf
// except it uses the optimal precition for floats: (0-3) for f and (0-6) for F
// eg.:
// optiSprintf("%f", 3.0)               => fmt.Sprintf("%.0f", 3.0)
// optiSprintf("%f", 3.33)              => fmt.Sprintf("%.2f", 3.33)
// optiSprintf("%f", 3.3001)            => fmt.Sprintf("%.1f", 3.3001)
// optiSprintf("%f", 3.333333333333333) => fmt.Sprintf("%.3f", 3.333333333333333)
// optiSprintf("%F", 3.333333333333333) => fmt.Sprintf("%.6f", 3.333333333333333)
func optiSprintf(format string, a ...interface{}) string {
	chunks := strings.Split(format, "%")
	newChunks := make([]string, len(chunks))
	for i, chunk := range chunks {
		if i != 0 {
			verb := chunk[0]
			if verb == 'f' || verb == 'F' {
				num := a[i-1].(float64)
				p := strconv.Itoa(getPrec(num, verb == 'F'))
				chunk = strings.Replace(chunk, string(verb), "."+p+"f", 1)
			}
		}
		newChunks[i] = chunk
	}
	format = strings.Join(newChunks, "%")
	return fmt.Sprintf(format, a...)
}

// TODO needs test, since it is not quiet right
func getPrec(num float64, better bool) int {
	max := 3
	eps := 0.0005
	if better {
		max = 6
		eps = 0.0000005
	}
	prec := 0
	for math.Mod(num, 1) > eps {
		num *= 10
		eps *= 10
		prec++
	}

	if max < prec {
		return max
	}
	return prec
}
<commit_msg>Fix SVG matrix conversion<commit_after>// Copyright 2015 The draw2d Authors. All rights reserved.
// created: 16/12/2017 by Drahoslav Bednářpackage draw2dsvg

package draw2dsvg

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"github.com/llgcode/draw2d"
	"image"
	"image/color"
	"image/png"
	"math"
	"strconv"
	"strings"
)

func toSvgRGBA(c color.Color) string {
	r, g, b, a := c.RGBA()
	r, g, b, a = r>>8, g>>8, b>>8, a>>8
	if a == 255 {
		return optiSprintf("#%02X%02X%02X", r, g, b)
	}
	return optiSprintf("rgba(%v,%v,%v,%f)", r, g, b, float64(a)/255)
}

func toSvgLength(l float64) string {
	if math.IsInf(l, 1) {
		return "100%"
	}
	return optiSprintf("%f", l)
}

func toSvgArray(nums []float64) string {
	arr := make([]string, len(nums))
	for i, num := range nums {
		arr[i] = optiSprintf("%f", num)
	}
	return strings.Join(arr, ",")
}

func toSvgFillRule(rule draw2d.FillRule) string {
	return map[draw2d.FillRule]string{
		draw2d.FillRuleEvenOdd: "evenodd",
		draw2d.FillRuleWinding: "nonzero",
	}[rule]
}

func toSvgPathDesc(p *draw2d.Path) string {
	parts := make([]string, len(p.Components))
	ps := p.Points
	for i, cmp := range p.Components {
		switch cmp {
		case draw2d.MoveToCmp:
			parts[i] = optiSprintf("M %f,%f", ps[0], ps[1])
			ps = ps[2:]
		case draw2d.LineToCmp:
			parts[i] = optiSprintf("L %f,%f", ps[0], ps[1])
			ps = ps[2:]
		case draw2d.QuadCurveToCmp:
			parts[i] = optiSprintf("Q %f,%f %f,%f", ps[0], ps[1], ps[2], ps[3])
			ps = ps[4:]
		case draw2d.CubicCurveToCmp:
			parts[i] = optiSprintf("C %f,%f %f,%f %f,%f", ps[0], ps[1], ps[2], ps[3], ps[4], ps[5])
			ps = ps[6:]
		case draw2d.ArcToCmp:
			cx, cy := ps[0], ps[1] // center
			rx, ry := ps[2], ps[3] // radii
			fi := ps[4] + ps[5]    // startAngle + angle

			// compute endpoint
			sinfi, cosfi := math.Sincos(fi)
			nom := math.Hypot(ry*cosfi, rx*sinfi)
			x := cx + (rx*ry*cosfi)/nom
			y := cy + (rx*ry*sinfi)/nom

			// compute large and sweep flags
			large := 0
			sweep := 0
			if math.Abs(ps[5]) > math.Pi {
				large = 1
			}
			if !math.Signbit(ps[5]) {
				sweep = 1
			}
			// dirty hack to ensure whole arc is drawn
			// if start point equals end point
			if sweep == 1 {
				x += 0.01 * sinfi
				y += 0.01 * -cosfi
			} else {
				x += 0.01 * sinfi
				y += 0.01 * cosfi
			}

			// rx ry x-axis-rotation large-arc-flag sweep-flag x y
			parts[i] = optiSprintf("A %f %f %v %v %v %F %F",
				rx, ry, 0, large, sweep, x, y,
			)
			ps = ps[6:]
		case draw2d.CloseCmp:
			parts[i] = "Z"
		}
	}
	return strings.Join(parts, " ")
}

func toSvgTransform(mat draw2d.Matrix) string {
	if mat.IsIdentity() {
		return ""
	}
	if mat.IsTranslation() {
		x, y := mat.GetTranslation()
		return optiSprintf("translate(%f,%f)", x, y)
	}
	return optiSprintf("matrix(%f,%f,%f,%f,%f,%f)",
		mat[0], mat[1], mat[2], mat[3], mat[4], mat[5],
	)
}

func imageToSvgHref(image image.Image) string {
	out := "data:image/png;base64,"
	pngBuf := &bytes.Buffer{}
	png.Encode(pngBuf, image)
	out += base64.RawStdEncoding.EncodeToString(pngBuf.Bytes())
	return out
}

// Do the same thing as fmt.Sprintf
// except it uses the optimal precition for floats: (0-3) for f and (0-6) for F
// eg.:
// optiSprintf("%f", 3.0)               => fmt.Sprintf("%.0f", 3.0)
// optiSprintf("%f", 3.33)              => fmt.Sprintf("%.2f", 3.33)
// optiSprintf("%f", 3.3001)            => fmt.Sprintf("%.1f", 3.3001)
// optiSprintf("%f", 3.333333333333333) => fmt.Sprintf("%.3f", 3.333333333333333)
// optiSprintf("%F", 3.333333333333333) => fmt.Sprintf("%.6f", 3.333333333333333)
func optiSprintf(format string, a ...interface{}) string {
	chunks := strings.Split(format, "%")
	newChunks := make([]string, len(chunks))
	for i, chunk := range chunks {
		if i != 0 {
			verb := chunk[0]
			if verb == 'f' || verb == 'F' {
				num := a[i-1].(float64)
				p := strconv.Itoa(getPrec(num, verb == 'F'))
				chunk = strings.Replace(chunk, string(verb), "."+p+"f", 1)
			}
		}
		newChunks[i] = chunk
	}
	format = strings.Join(newChunks, "%")
	return fmt.Sprintf(format, a...)
}

// TODO needs test, since it is not quiet right
func getPrec(num float64, better bool) int {
	num = math.Abs(num)
	max := 3
	eps := 0.0005
	if better {
		max = 6
		eps = 0.0000005
	}
	prec := 0
	for math.Mod(num, 1) > eps {
		num *= 10
		eps *= 10
		prec++
	}

	if max < prec {
		return max
	}
	return prec
}
<|endoftext|>