<commit_before>package yiigo

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"sync"
	"time"

	ini "gopkg.in/ini.v1"

	"github.com/garyburd/redigo/redis"
	"github.com/youtube/vitess/go/pools"
	"golang.org/x/net/context"
)

// RedisPoolResource redis pool resource
type RedisPoolResource struct {
	name string
	pool *pools.ResourcePool
	mux  sync.Mutex
}

// RedisResourceConn redis connection resource
type RedisResourceConn struct {
	redis.Conn
}

var (
	// RedisPool default connection pool
	RedisPool *RedisPoolResource

	redisMap map[string]*RedisPoolResource
	redisMux sync.RWMutex
)

// Close close connection resorce
func (r RedisResourceConn) Close() {
	r.Conn.Close()
}

func initRedis() {
	sections := childSections("redis")

	if len(sections) > 0 {
		initMultiRedis(sections)
		return
	}

	initSingleRedis()
}

func initSingleRedis() {
	RedisPool = &RedisPoolResource{name: "redis"}
	RedisPool.dial()
}

func initMultiRedis(sections []*ini.Section) {
	redisMap = make(map[string]*RedisPoolResource, len(sections))

	for _, v := range sections {
		pool := &RedisPoolResource{name: v.Name()}
		pool.dial()

		redisMap[v.Name()] = pool
	}

	if redis, ok := redisMap["redis.default"]; ok {
		RedisPool = redis
	}
}

// RedisConnPool get an redis pool
func RedisConnPool(conn ...string) (*RedisPoolResource, error) {
	redisMux.RLock()
	defer redisMux.RUnlock()

	c := "default"

	if len(conn) > 0 {
		c = conn[0]
	}

	schema := fmt.Sprintf("redis.%s", c)

	pool, ok := redisMap[schema]

	if !ok {
		return nil, fmt.Errorf("redis %s is not connected", schema)
	}

	return pool, nil
}

func (r *RedisPoolResource) dial() {
	r.mux.Lock()
	defer r.mux.Unlock()

	if r.pool != nil {
		return
	}

	poolMinActive := EnvInt(r.name, "poolMinActive", 10)
	poolMaxActive := EnvInt(r.name, "poolMaxActive", 20)
	poolIdleTimeout := EnvDuration(r.name, "poolIdleTimeout", time.Duration(60000)*time.Millisecond)

	r.pool = pools.NewResourcePool(func() (pools.Resource, error) {
		dsn := fmt.Sprintf("%s:%d", EnvString(r.name, "host", "localhost"), EnvInt("redis", "port", 6379))

		dialOptions := []redis.DialOption{
			redis.DialPassword(EnvString(r.name, "password", "")),
			redis.DialDatabase(EnvInt(r.name, "database", 0)),
			redis.DialConnectTimeout(EnvDuration(r.name, "connectTimeout", time.Duration(10000)*time.Millisecond)),
			redis.DialReadTimeout(EnvDuration(r.name, "readTimeout", time.Duration(10000)*time.Millisecond)),
			redis.DialWriteTimeout(EnvDuration(r.name, "writeTimeout", time.Duration(10000)*time.Millisecond)),
		}

		conn, err := redis.Dial("tcp", dsn, dialOptions...)

		if err != nil {
			return nil, err
		}

		return RedisResourceConn{conn}, nil
	}, poolMinActive, poolMaxActive, poolIdleTimeout*time.Millisecond)
}

// Get get a connection resource from the pool
func (r *RedisPoolResource) Get() (RedisResourceConn, error) {
	if r.pool.IsClosed() {
		r.dial()
	}

	ctx := context.TODO()
	resource, err := r.pool.Get(ctx)

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

	return resource.(RedisResourceConn), nil
}

// Put return a connection resource to the pool
func (r *RedisPoolResource) Put(rc RedisResourceConn) {
	r.pool.Put(rc)
}

// ScanJSON scans src to the struct pointed to by dest
func ScanJSON(reply interface{}, dest interface{}) error {
	bytes, err := redis.Bytes(reply, nil)

	if err != nil {
		return err
	}

	err = json.Unmarshal(bytes, dest)

	if err != nil {
		return err
	}

	return nil
}

// ScanJSONSlice scans src to the slice pointed to by dest
func ScanJSONSlice(reply interface{}, dest interface{}) error {
	bytes, err := redis.ByteSlices(reply, nil)

	if err != nil {
		return err
	}

	if len(bytes) == 0 {
		return nil
	}

	v := reflect.Indirect(reflect.ValueOf(dest))

	if v.Kind() != reflect.Slice {
		return errors.New("the dest must be a slice")
	}

	t := v.Type()
	v.Set(reflect.MakeSlice(t, 0, 0))

	for _, b := range bytes {
		elem := reflect.New(t.Elem()).Elem()
		err := json.Unmarshal(b, elem.Addr().Interface())

		if err != nil {
			return err
		}

		v.Set(reflect.Append(v, elem))
	}

	return nil
}
<commit_msg>fix redis pool get<commit_after>package yiigo

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"sync"
	"time"

	ini "gopkg.in/ini.v1"

	"github.com/garyburd/redigo/redis"
	"github.com/youtube/vitess/go/pools"
	"golang.org/x/net/context"
)

// RedisPoolResource redis pool resource
type RedisPoolResource struct {
	name string
	pool *pools.ResourcePool
	mux  sync.Mutex
}

// RedisResourceConn redis connection resource
type RedisResourceConn struct {
	redis.Conn
}

var (
	// RedisPool default connection pool
	RedisPool *RedisPoolResource

	redisMap map[string]*RedisPoolResource
	redisMux sync.RWMutex
)

// Close close connection resorce
func (r RedisResourceConn) Close() {
	r.Conn.Close()
}

func initRedis() {
	sections := childSections("redis")

	if len(sections) > 0 {
		initMultiRedis(sections)
		return
	}

	initSingleRedis()
}

func initSingleRedis() {
	RedisPool = &RedisPoolResource{name: "redis"}
	RedisPool.dial()
}

func initMultiRedis(sections []*ini.Section) {
	redisMap = make(map[string]*RedisPoolResource, len(sections))

	for _, v := range sections {
		pool := &RedisPoolResource{name: v.Name()}
		pool.dial()

		redisMap[v.Name()] = pool
	}

	if redis, ok := redisMap["redis.default"]; ok {
		RedisPool = redis
	}
}

// RedisConnPool get an redis pool
func RedisConnPool(conn ...string) (*RedisPoolResource, error) {
	redisMux.RLock()
	defer redisMux.RUnlock()

	c := "default"

	if len(conn) > 0 {
		c = conn[0]
	}

	schema := fmt.Sprintf("redis.%s", c)

	pool, ok := redisMap[schema]

	if !ok {
		return nil, fmt.Errorf("redis %s is not connected", schema)
	}

	return pool, nil
}

func (r *RedisPoolResource) dial() {
	r.mux.Lock()
	defer r.mux.Unlock()

	if r.pool != nil {
		return
	}

	poolMinActive := EnvInt(r.name, "poolMinActive", 10)
	poolMaxActive := EnvInt(r.name, "poolMaxActive", 20)
	poolIdleTimeout := EnvDuration(r.name, "poolIdleTimeout", time.Duration(60000)*time.Millisecond)

	r.pool = pools.NewResourcePool(func() (pools.Resource, error) {
		dsn := fmt.Sprintf("%s:%d", EnvString(r.name, "host", "localhost"), EnvInt("redis", "port", 6379))

		dialOptions := []redis.DialOption{
			redis.DialPassword(EnvString(r.name, "password", "")),
			redis.DialDatabase(EnvInt(r.name, "database", 0)),
			redis.DialConnectTimeout(EnvDuration(r.name, "connectTimeout", time.Duration(10000)*time.Millisecond)),
			redis.DialReadTimeout(EnvDuration(r.name, "readTimeout", time.Duration(10000)*time.Millisecond)),
			redis.DialWriteTimeout(EnvDuration(r.name, "writeTimeout", time.Duration(10000)*time.Millisecond)),
		}

		conn, err := redis.Dial("tcp", dsn, dialOptions...)

		if err != nil {
			return nil, err
		}

		return RedisResourceConn{conn}, nil
	}, poolMinActive, poolMaxActive, poolIdleTimeout*time.Millisecond)
}

// Get get a connection resource from the pool
func (r *RedisPoolResource) Get() (RedisResourceConn, error) {
	if r.pool.IsClosed() {
		r.dial()
	}

	ctx := context.TODO()
	resource, err := r.pool.Get(ctx)

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

	rc := resource.(RedisResourceConn)

	if err = rc.Err(); err != nil {
		r.pool.Put(rc)
		return rc, err
	}

	return rc, nil
}

// Put return a connection resource to the pool
func (r *RedisPoolResource) Put(rc RedisResourceConn) {
	r.pool.Put(rc)
}

// ScanJSON scans src to the struct pointed to by dest
func ScanJSON(reply interface{}, dest interface{}) error {
	bytes, err := redis.Bytes(reply, nil)

	if err != nil {
		return err
	}

	err = json.Unmarshal(bytes, dest)

	if err != nil {
		return err
	}

	return nil
}

// ScanJSONSlice scans src to the slice pointed to by dest
func ScanJSONSlice(reply interface{}, dest interface{}) error {
	bytes, err := redis.ByteSlices(reply, nil)

	if err != nil {
		return err
	}

	if len(bytes) == 0 {
		return nil
	}

	v := reflect.Indirect(reflect.ValueOf(dest))

	if v.Kind() != reflect.Slice {
		return errors.New("the dest must be a slice")
	}

	t := v.Type()
	v.Set(reflect.MakeSlice(t, 0, 0))

	for _, b := range bytes {
		elem := reflect.New(t.Elem()).Elem()
		err := json.Unmarshal(b, elem.Addr().Interface())

		if err != nil {
			return err
		}

		v.Set(reflect.Append(v, elem))
	}

	return nil
}
<|endoftext|>


<commit_before>package gocql

import (
	"log"
	"net"
	"time"
)

type HostInfo struct {
	Peer       string
	DataCenter string
	Rack       string
	HostId     string
	Tokens     []string
}

// Polls system.peers at a specific interval to find new hosts
type ringDescriber struct {
	dcFilter        string
	rackFilter      string
	prevHosts       []HostInfo
	prevPartitioner string
	session         *Session
	closeChan       chan bool
}

func (r *ringDescriber) GetHosts() (
	hosts []HostInfo,
	partitioner string,
	err error,
) {
	// we need conn to be the same because we need to query system.peers and system.local
	// on the same node to get the whole cluster
	conn := r.session.Pool.Pick(nil)
	if conn == nil {
		return r.prevHosts, r.prevPartitioner, nil
	}

	query := r.session.Query("SELECT data_center, rack, host_id, tokens, partitioner FROM system.local")
	iter := conn.executeQuery(query)

	host := HostInfo{}
	iter.Scan(&host.DataCenter, &host.Rack, &host.HostId, &host.Tokens, &partitioner)

	if err = iter.Close(); err != nil {
		return nil, "", err
	}

	addr, _, err := net.SplitHostPort(conn.Address())
	if err != nil {
		// this should not happen, ever, as this is the address that was dialed by conn, here
		// a panic makes sense, please report a bug if it occurs.
		panic(err)
	}

	host.Peer = addr

	hosts = []HostInfo{host}

	query = r.session.Query("SELECT peer, data_center, rack, host_id, tokens FROM system.peers")
	iter = conn.executeQuery(query)

	host = HostInfo{}
	for iter.Scan(&host.Peer, &host.DataCenter, &host.Rack, &host.HostId, &host.Tokens) {
		if r.matchFilter(&host) {
			hosts = append(hosts, host)
		}
		host = HostInfo{}
	}

	if err = iter.Close(); err != nil {
		return nil, "", err
	}

	r.prevHosts = hosts
	r.prevPartitioner = partitioner

	return hosts, partitioner, nil
}

func (r *ringDescriber) matchFilter(host *HostInfo) bool {

	if r.dcFilter != "" && r.dcFilter != host.DataCenter {
		return false
	}

	if r.rackFilter != "" && r.rackFilter != host.Rack {
		return false
	}

	return true
}

func (h *ringDescriber) run(sleep time.Duration) {
	if sleep == 0 {
		sleep = 30 * time.Second
	}

	for {
		select {
		case <-h.closeChan:
			return
		}
		// if we have 0 hosts this will return the previous list of hosts to
		// attempt to reconnect to the cluster otherwise we would never find
		// downed hosts again, could possibly have an optimisation to only
		// try to add new hosts if GetHosts didnt error and the hosts didnt change.
		hosts, partitioner, err := h.GetHosts()
		if err != nil {
			log.Println("RingDescriber: unable to get ring topology:", err)
		} else {
			h.session.Pool.SetHosts(hosts)
			if v, ok := h.session.Pool.(SetPartitioner); ok {
				v.SetPartitioner(partitioner)
			}
		}

		time.Sleep(sleep)
	}
}
<commit_msg>Moved select statement to end of loop<commit_after>package gocql

import (
	"log"
	"net"
	"time"
)

type HostInfo struct {
	Peer       string
	DataCenter string
	Rack       string
	HostId     string
	Tokens     []string
}

// Polls system.peers at a specific interval to find new hosts
type ringDescriber struct {
	dcFilter        string
	rackFilter      string
	prevHosts       []HostInfo
	prevPartitioner string
	session         *Session
	closeChan       chan bool
}

func (r *ringDescriber) GetHosts() (
	hosts []HostInfo,
	partitioner string,
	err error,
) {
	// we need conn to be the same because we need to query system.peers and system.local
	// on the same node to get the whole cluster
	conn := r.session.Pool.Pick(nil)
	if conn == nil {
		return r.prevHosts, r.prevPartitioner, nil
	}

	query := r.session.Query("SELECT data_center, rack, host_id, tokens, partitioner FROM system.local")
	iter := conn.executeQuery(query)

	host := HostInfo{}
	iter.Scan(&host.DataCenter, &host.Rack, &host.HostId, &host.Tokens, &partitioner)

	if err = iter.Close(); err != nil {
		return nil, "", err
	}

	addr, _, err := net.SplitHostPort(conn.Address())
	if err != nil {
		// this should not happen, ever, as this is the address that was dialed by conn, here
		// a panic makes sense, please report a bug if it occurs.
		panic(err)
	}

	host.Peer = addr

	hosts = []HostInfo{host}

	query = r.session.Query("SELECT peer, data_center, rack, host_id, tokens FROM system.peers")
	iter = conn.executeQuery(query)

	host = HostInfo{}
	for iter.Scan(&host.Peer, &host.DataCenter, &host.Rack, &host.HostId, &host.Tokens) {
		if r.matchFilter(&host) {
			hosts = append(hosts, host)
		}
		host = HostInfo{}
	}

	if err = iter.Close(); err != nil {
		return nil, "", err
	}

	r.prevHosts = hosts
	r.prevPartitioner = partitioner

	return hosts, partitioner, nil
}

func (r *ringDescriber) matchFilter(host *HostInfo) bool {

	if r.dcFilter != "" && r.dcFilter != host.DataCenter {
		return false
	}

	if r.rackFilter != "" && r.rackFilter != host.Rack {
		return false
	}

	return true
}

func (h *ringDescriber) run(sleep time.Duration) {
	if sleep == 0 {
		sleep = 30 * time.Second
	}

	for {
		// if we have 0 hosts this will return the previous list of hosts to
		// attempt to reconnect to the cluster otherwise we would never find
		// downed hosts again, could possibly have an optimisation to only
		// try to add new hosts if GetHosts didnt error and the hosts didnt change.
		hosts, partitioner, err := h.GetHosts()
		if err != nil {
			log.Println("RingDescriber: unable to get ring topology:", err)
		} else {
			h.session.Pool.SetHosts(hosts)
			if v, ok := h.session.Pool.(SetPartitioner); ok {
				v.SetPartitioner(partitioner)
			}
		}

		time.Sleep(sleep)

		select {
		case <-h.closeChan:
			return
		}
	}
}
<|endoftext|>


<commit_before>package ssgo

import (
	"encoding/json"
	"strconv"
)

//const (
//	ReplyOK          string = "ok"
//	ReplyNotFound    string = "not_found"
//	ReplyError       string = "error"
//	ReplyFail        string = "fail"
//	ReplyClientError string = "client_error"
//)

type Reply []string

type ReplyE struct {
	R Reply
	E error
}

type Entry struct {
	Key   string `json:"key,omitempty"`
	Value string `json:"value,omitempty"`
}

func (r Reply) String() string {

	if len(r) > 0 {
		return r[0]
	}

	return ""
}

func (r Reply) Int() int {
	return int(r.Int64())
}

func (r Reply) Int64() int64 {

	if len(r) < 1 {
		return 0
	}

	i64, err := strconv.ParseInt(r[0], 10, 64)
	if err == nil {
		return i64
	}

	return 0
}

func (r Reply) Uint() uint {
	return uint(r.Uint64())
}

func (r Reply) Uint64() uint64 {

	if len(r) < 1 {
		return 0
	}

	i64, err := strconv.ParseUint(r[0], 10, 64)
	if err == nil {
		return i64
	}

	return 0
}

func (r Reply) Float64() float64 {

	if len(r) < 1 {
		return 0
	}

	f64, err := strconv.ParseFloat(r[0], 64)
	if err == nil {
		return f64
	}

	return 0
}

func (r Reply) Bool() bool {

	if len(r) < 1 {
		return false
	}

	b, err := strconv.ParseBool(r[0])
	if err == nil {
		return b
	}

	return false
}

func (r Reply) List() []string {

	if len(r) < 1 {
		return []string{}
	}

	return r
}

func (r Reply) Hash() []Entry {

	hs := []Entry{}

	if len(r) < 2 {
		return hs
	}

	for i := 0; i < (len(r) - 1); i += 2 {
		hs = append(hs, Entry{r[i], r[i+1]})
	}

	return hs
}

func (r Reply) Map() map[string]string {

	m := map[string]string{}

	if len(r) < 2 {
		return m
	}

	for i := 0; i < (len(r) - 1); i += 2 {
		m[r[i]] = r[i+1]
	}

	return m
}

// Json returns the map that marshals from the reply bytes as json in response .
func (r Reply) Json(v interface{}) error {
	return json.Unmarshal([]byte(r.String()), &v)
}

func (r *Entry) Json(v interface{}) error {
	return json.Unmarshal([]byte(r.Value), &v)
}
<commit_msg>optimize Reply.Hash<commit_after>package ssgo

import (
	"encoding/json"
	"strconv"
)

//const (
//	ReplyOK          string = "ok"
//	ReplyNotFound    string = "not_found"
//	ReplyError       string = "error"
//	ReplyFail        string = "fail"
//	ReplyClientError string = "client_error"
//)

type Reply []string

type ReplyE struct {
	R Reply
	E error
}

type Entry struct {
	Key   string `json:"key,omitempty"`
	Value string `json:"value,omitempty"`
}

func (r Reply) String() string {

	if len(r) > 0 {
		return r[0]
	}

	return ""
}

func (r Reply) Int() int {
	return int(r.Int64())
}

func (r Reply) Int64() int64 {

	if len(r) < 1 {
		return 0
	}

	i64, err := strconv.ParseInt(r[0], 10, 64)
	if err == nil {
		return i64
	}

	return 0
}

func (r Reply) Uint() uint {
	return uint(r.Uint64())
}

func (r Reply) Uint64() uint64 {

	if len(r) < 1 {
		return 0
	}

	i64, err := strconv.ParseUint(r[0], 10, 64)
	if err == nil {
		return i64
	}

	return 0
}

func (r Reply) Float64() float64 {

	if len(r) < 1 {
		return 0
	}

	f64, err := strconv.ParseFloat(r[0], 64)
	if err == nil {
		return f64
	}

	return 0
}

func (r Reply) Bool() bool {

	if len(r) < 1 {
		return false
	}

	b, err := strconv.ParseBool(r[0])
	if err == nil {
		return b
	}

	return false
}

func (r Reply) List() []string {

	if len(r) < 1 {
		return []string{}
	}

	return r
}

func (r Reply) Hash() []*Entry {

	l := len(r)

	if l < 2 {
		return []*Entry{}
	}
	hs := make([]*Entry, 0, l / 2)

	for i := 0; i < (l - 1); i += 2 {
		hs = append(hs, &Entry{r[i], r[i+1]})
	}

	return hs
}

func (r Reply) Map() map[string]string {

	m := map[string]string{}

	if len(r) < 2 {
		return m
	}

	for i := 0; i < (len(r) - 1); i += 2 {
		m[r[i]] = r[i+1]
	}

	return m
}

// Json returns the map that marshals from the reply bytes as json in response .
func (r Reply) Json(v interface{}) error {
	return json.Unmarshal([]byte(r.String()), &v)
}

func (r *Entry) Json(v interface{}) error {
	return json.Unmarshal([]byte(r.Value), &v)
}
<|endoftext|>


<commit_before>package ghapi

import (
	"encoding/json"
	"strconv"
	"time"
)

const ctLayout = "2006-01-02T15:04:05Z"

type CustomTime struct {
	time.Time
}

func (ct *CustomTime) UnmarshalJSON(b []byte) error {
	if b[0] == '"' && b[len(b)-1] == '"' {
		b = b[1 : len(b)-1]
		time, err := time.Parse(ctLayout, string(b))
		if err != nil {
			return err
		}
		ct.Time = time
	} else if len(b) > 0 {
		secs, err := strconv.Atoi(string(b))
		if err != nil {
			return err
		}
		ct.Time = time.Unix(int64(secs), 0)
	}
	return nil
}

// RepositoryPayload contains information about the repository
type RepositoryPayload struct {
	ID int `json:"id"`
	// The short name of the repository.
	Name string `json:"name"`
	// The name of the repository including the owner (user/organization).
	FullName string `json:"full_name"`
	// TODO: What if the owner is an organization? Owner.Type field?
	Owner            User       `json:"owner"`
	Private          bool       `json:"private"`
	HTMLURL          string     `json:"html_url"`
	Fork             bool       `json:"fork"`
	URL              string     `json:"url"`
	ForksURL         string     `json:"forks_url"`
	KeysURL          string     `json:"keys"`
	CollaboratorsURL string     `json:"collaborators_url"`
	TeamsURL         string     `json:"teams_url"`
	HooksURL         string     `json:"hooks_url"`
	IssueEventsURL   string     `json:"issue_events_url"`
	EventURL         string     `json:"events_url"`
	AssigneesURL     string     `json:"assignees_url"`
	BranchesURL      string     `json:"branches_url"`
	TagsURL          string     `json:"tags_url"`
	BlobsURL         string     `json:"blobs_url"`
	GitTagsURL       string     `json:"git_tags_url"`
	GitRefsURL       string     `json:"git_refs_url"`
	TreesURL         string     `json:"trees_url"`
	StatusesURL      string     `json:"statuses_url"`
	LanguagesURL     string     `json:"languages_url"`
	StargazersURL    string     `json:"stargazers_url"`
	ContributorsURL  string     `json:"contributors_url"`
	SubscribersURL   string     `json:"subscribers_url"`
	SubscriptionURL  string     `json:"subscription_url"`
	CommitsURL       string     `json:"commits_url"`
	GitCommitsURL    string     `json:"git_commits_url"`
	CommentsURL      string     `json:"comments_url"`
	IssueCommentURL  string     `json:"issue_comment_url"`
	ContentsURL      string     `json:"contents_url"`
	CompareURL       string     `json:"compare_url"`
	MergesURL        string     `json:"merges_url"`
	ArchiveURL       string     `json:"archive_url"`
	DownloadsURL     string     `json:"downloads_url"`
	IssuesURL        string     `json:"issues_url"`
	PullsURL         string     `json:"pulls_url"`
	MilestonesURL    string     `json:"milestones_url"`
	NotificationsURL string     `json:"notifications_url"`
	LabelsURL        string     `json:"labels_url"`
	ReleasesURL      string     `json:"releases_url"`
	CreatedAt        CustomTime `json:"created_at"`
	UpdatedAt        CustomTime `json:"updated_at"`
	PushedAt         CustomTime `json:"pushed_at"`
	GitURL           string     `json:"git_url"`
	SSHURL           string     `json:"ssh_url"`
	CloneURL         string     `json:"clone_url"`
	SVNURL           string     `json:"svn_url"`
	// TODO: can be null
	HomePage        string `json:"homepage"`
	Size            int    `json:"size"`
	StargazersCount int    `json:"stargazers_count"`
	WatchersCount   int    `json:"watchers_count"`
	// TODO: can be null
	Language     string `json:"language"`
	HasIssues    bool   `json:"has_issues"`
	HasDownloads bool   `json:"has_downloads"`
	HasWiki      bool   `json:"has_wiki"`
	HasPages     bool   `json:"has_pages"`
	ForksCount   int    `json:"forks_count"`
	// TODO: can be null
	MirrorURL       string `json:"mirror_url"`
	OpenIssuesCount int    `json:"open_issues_count"`
	Forks           int    `json:"forks"`
	OpenIssues      int    `json:"open_issues"`
	Watchers        int    `json:"watchers"`
	DefaultBranch   string `json:"default_branch"`
}

func (api *RepositoryAPI) Get() (*RepositoryPayload, error) {
	url := api.getURL("/repos/:owner/:repo")

	resp, err := api.httpGet(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var repository RepositoryPayload

	j := json.NewDecoder(resp.Body)
	if err = j.Decode(&repository); err != nil {
		return nil, err
	}

	return &repository, nil
}
<commit_msg>add Fork/ForkAsync methods<commit_after>package ghapi

import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"
)

const ctLayout = "2006-01-02T15:04:05Z"

type CustomTime struct {
	time.Time
}

func (ct *CustomTime) UnmarshalJSON(b []byte) error {
	if b[0] == '"' && b[len(b)-1] == '"' {
		b = b[1 : len(b)-1]
		parsedTime, err := time.Parse(ctLayout, string(b))
		if err != nil {
			return err
		}
		ct.Time = parsedTime
	} else if len(b) > 0 {
		secs, err := strconv.Atoi(string(b))
		if err != nil {
			return err
		}
		ct.Time = time.Unix(int64(secs), 0)
	}
	return nil
}

// RepositoryPayload contains information about the repository
type RepositoryPayload struct {
	ID int `json:"id"`
	// The short name of the repository.
	Name string `json:"name"`
	// The name of the repository including the owner (user/organization).
	FullName string `json:"full_name"`
	// TODO: What if the owner is an organization? Owner.Type field?
	Owner            User       `json:"owner"`
	Private          bool       `json:"private"`
	HTMLURL          string     `json:"html_url"`
	Fork             bool       `json:"fork"`
	URL              string     `json:"url"`
	ForksURL         string     `json:"forks_url"`
	KeysURL          string     `json:"keys"`
	CollaboratorsURL string     `json:"collaborators_url"`
	TeamsURL         string     `json:"teams_url"`
	HooksURL         string     `json:"hooks_url"`
	IssueEventsURL   string     `json:"issue_events_url"`
	EventURL         string     `json:"events_url"`
	AssigneesURL     string     `json:"assignees_url"`
	BranchesURL      string     `json:"branches_url"`
	TagsURL          string     `json:"tags_url"`
	BlobsURL         string     `json:"blobs_url"`
	GitTagsURL       string     `json:"git_tags_url"`
	GitRefsURL       string     `json:"git_refs_url"`
	TreesURL         string     `json:"trees_url"`
	StatusesURL      string     `json:"statuses_url"`
	LanguagesURL     string     `json:"languages_url"`
	StargazersURL    string     `json:"stargazers_url"`
	ContributorsURL  string     `json:"contributors_url"`
	SubscribersURL   string     `json:"subscribers_url"`
	SubscriptionURL  string     `json:"subscription_url"`
	CommitsURL       string     `json:"commits_url"`
	GitCommitsURL    string     `json:"git_commits_url"`
	CommentsURL      string     `json:"comments_url"`
	IssueCommentURL  string     `json:"issue_comment_url"`
	ContentsURL      string     `json:"contents_url"`
	CompareURL       string     `json:"compare_url"`
	MergesURL        string     `json:"merges_url"`
	ArchiveURL       string     `json:"archive_url"`
	DownloadsURL     string     `json:"downloads_url"`
	IssuesURL        string     `json:"issues_url"`
	PullsURL         string     `json:"pulls_url"`
	MilestonesURL    string     `json:"milestones_url"`
	NotificationsURL string     `json:"notifications_url"`
	LabelsURL        string     `json:"labels_url"`
	ReleasesURL      string     `json:"releases_url"`
	CreatedAt        CustomTime `json:"created_at"`
	UpdatedAt        CustomTime `json:"updated_at"`
	PushedAt         CustomTime `json:"pushed_at"`
	GitURL           string     `json:"git_url"`
	SSHURL           string     `json:"ssh_url"`
	CloneURL         string     `json:"clone_url"`
	SVNURL           string     `json:"svn_url"`
	// TODO: can be null
	HomePage        string `json:"homepage"`
	Size            int    `json:"size"`
	StargazersCount int    `json:"stargazers_count"`
	WatchersCount   int    `json:"watchers_count"`
	// TODO: can be null
	Language     string `json:"language"`
	HasIssues    bool   `json:"has_issues"`
	HasDownloads bool   `json:"has_downloads"`
	HasWiki      bool   `json:"has_wiki"`
	HasPages     bool   `json:"has_pages"`
	ForksCount   int    `json:"forks_count"`
	// TODO: can be null
	MirrorURL       string `json:"mirror_url"`
	OpenIssuesCount int    `json:"open_issues_count"`
	Forks           int    `json:"forks"`
	OpenIssues      int    `json:"open_issues"`
	Watchers        int    `json:"watchers"`
	DefaultBranch   string `json:"default_branch"`
}

type ForkResponse struct {
	ID    int `json:"id"`
	Owner struct {
		Login             string `json:"login"`
		ID                int    `json:"id"`
		AvatarURL         string `json:"avatar_url"`
		GravatarID        string `json:"gravatar_id"`
		URL               string `json:"url"`
		HTMLURL           string `json:"html_url"`
		FollowersURL      string `json:"followers_url"`
		FollowingURL      string `json:"following_url"`
		GistsURL          string `json:"gists_url"`
		StarredURL        string `json:"starred_url"`
		SubscriptionsURL  string `json:"subscriptions_url"`
		OrganizationsURL  string `json:"organizations_url"`
		ReposURL          string `json:"repos_url"`
		EventsURL         string `json:"events_url"`
		ReceivedEventsURL string `json:"received_events_url"`
		Type              string `json:"type"`
		SiteAdmin         bool   `json:"site_admin"`
	} `json:"owner"`
	Name             string     `json:"name"`
	FullName         string     `json:"full_name"`
	Description      string     `json:"description"`
	Private          bool       `json:"private"`
	Fork             bool       `json:"fork"`
	URL              string     `json:"url"`
	HTMLURL          string     `json:"html_url"`
	ArchiveURL       string     `json:"archive_url"`
	AssigneesURL     string     `json:"assignees_url"`
	BlobsURL         string     `json:"blobs_url"`
	BranchesURL      string     `json:"branches_url"`
	CloneURL         string     `json:"clone_url"`
	CollaboratorsURL string     `json:"collaborators_url"`
	CommentsURL      string     `json:"comments_url"`
	CommitsURL       string     `json:"commits_url"`
	CompareURL       string     `json:"compare_url"`
	ContentsURL      string     `json:"contents_url"`
	ContributorsURL  string     `json:"contributors_url"`
	DeploymentsURL   string     `json:"deployments_url"`
	DownloadsURL     string     `json:"downloads_url"`
	EventsURL        string     `json:"events_url"`
	ForksURL         string     `json:"forks_url"`
	GitCommitsURL    string     `json:"git_commits_url"`
	GitRefsURL       string     `json:"git_refs_url"`
	GitTagsURL       string     `json:"git_tags_url"`
	GitURL           string     `json:"git_url"`
	HooksURL         string     `json:"hooks_url"`
	IssueCommentURL  string     `json:"issue_comment_url"`
	IssueEventsURL   string     `json:"issue_events_url"`
	IssuesURL        string     `json:"issues_url"`
	KeysURL          string     `json:"keys_url"`
	LabelsURL        string     `json:"labels_url"`
	LanguagesURL     string     `json:"languages_url"`
	MergesURL        string     `json:"merges_url"`
	MilestonesURL    string     `json:"milestones_url"`
	MirrorURL        string     `json:"mirror_url"`
	NotificationsURL string     `json:"notifications_url"`
	PullsURL         string     `json:"pulls_url"`
	ReleasesURL      string     `json:"releases_url"`
	SSHURL           string     `json:"ssh_url"`
	StargazersURL    string     `json:"stargazers_url"`
	StatusesURL      string     `json:"statuses_url"`
	SubscribersURL   string     `json:"subscribers_url"`
	SubscriptionURL  string     `json:"subscription_url"`
	SvnURL           string     `json:"svn_url"`
	TagsURL          string     `json:"tags_url"`
	TeamsURL         string     `json:"teams_url"`
	TreesURL         string     `json:"trees_url"`
	Homepage         string     `json:"homepage"`
	Language         string     `json:"language"`
	ForksCount       int        `json:"forks_count"`
	StargazersCount  int        `json:"stargazers_count"`
	WatchersCount    int        `json:"watchers_count"`
	Size             int        `json:"size"`
	DefaultBranch    string     `json:"default_branch"`
	OpenIssuesCount  int        `json:"open_issues_count"`
	HasIssues        bool       `json:"has_issues"`
	HasWiki          bool       `json:"has_wiki"`
	HasPages         bool       `json:"has_pages"`
	HasDownloads     bool       `json:"has_downloads"`
	PushedAt         CustomTime `json:"pushed_at"`
	CreatedAt        CustomTime `json:"created_at"`
	UpdatedAt        CustomTime `json:"updated_at"`
	Permissions      struct {
		Admin bool `json:"admin"`
		Push  bool `json:"push"`
		Pull  bool `json:"pull"`
	} `json:"permissions"`
}

type RepositoryCommit struct {
	URL         string `json:"url"`
	SHA         string `json:"sha"`
	HTMLURL     string `json:"html_url"`
	CommentsURL string `json:"comments_url"`
	Commit      struct {
		URL    string `json:"url"`
		Author struct {
			Name  string    `json:"name"`
			Email string    `json:"email"`
			Date  time.Time `json:"date"`
		} `json:"author"`
		Committer struct {
			Name  string    `json:"name"`
			Email string    `json:"email"`
			Date  time.Time `json:"date"`
		} `json:"committer"`
		Message string `json:"message"`
		Tree    struct {
			URL string `json:"url"`
			SHA string `json:"sha"`
		} `json:"tree"`
		CommentCount int `json:"comment_count"`
		Verification struct {
			Verified  bool   `json:"verified"`
			Reason    string `json:"reason"`
			Signature string `json:"signature"`
			Payload   string `json:"payload"`
		} `json:"verification"`
	} `json:"commit"`
	Author struct {
		Login             string `json:"login"`
		ID                int    `json:"id"`
		AvatarURL         string `json:"avatar_url"`
		GravatarID        string `json:"gravatar_id"`
		URL               string `json:"url"`
		HTMLURL           string `json:"html_url"`
		FollowersURL      string `json:"followers_url"`
		FollowingURL      string `json:"following_url"`
		GistsURL          string `json:"gists_url"`
		StarredURL        string `json:"starred_url"`
		SubscriptionsURL  string `json:"subscriptions_url"`
		OrganizationsURL  string `json:"organizations_url"`
		ReposURL          string `json:"repos_url"`
		EventsURL         string `json:"events_url"`
		ReceivedEventsURL string `json:"received_events_url"`
		Type              string `json:"type"`
		SiteAdmin         bool   `json:"site_admin"`
	} `json:"author"`
	Committer struct {
		Login             string `json:"login"`
		ID                int    `json:"id"`
		AvatarURL         string `json:"avatar_url"`
		GravatarID        string `json:"gravatar_id"`
		URL               string `json:"url"`
		HTMLURL           string `json:"html_url"`
		FollowersURL      string `json:"followers_url"`
		FollowingURL      string `json:"following_url"`
		GistsURL          string `json:"gists_url"`
		StarredURL        string `json:"starred_url"`
		SubscriptionsURL  string `json:"subscriptions_url"`
		OrganizationsURL  string `json:"organizations_url"`
		ReposURL          string `json:"repos_url"`
		EventsURL         string `json:"events_url"`
		ReceivedEventsURL string `json:"received_events_url"`
		Type              string `json:"type"`
		SiteAdmin         bool   `json:"site_admin"`
	} `json:"committer"`
	Parents []struct {
		URL string `json:"url"`
		SHA string `json:"sha"`
	} `json:"parents"`
}

// Get returns the repository information.
func (api *RepositoryAPI) Get() (*RepositoryPayload, error) {
	url := api.getURL("/repos/:owner/:repo")

	resp, err := api.httpGet(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var repository RepositoryPayload

	j := json.NewDecoder(resp.Body)
	if err = j.Decode(&repository); err != nil {
		return nil, err
	}

	return &repository, nil
}

// ForkAsync forks the repository into the user's account.
// Forking a Repository happens asynchronously.
// Therefore, you may have to wait a short period before accessing the git objects.
func (api *RepositoryAPI) ForkAsync() (*ForkResponse, error) {
	url := api.getURL("/repos/:owner/:repo/forks")

	resp, err := api.httpPost(url, "")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var forkResponse ForkResponse

	j := json.NewDecoder(resp.Body)
	if err = j.Decode(&forkResponse); err != nil {
		return nil, err
	}

	return &forkResponse, nil
}

// Fork performs a synchronous fork operation with a timeout period. See ForkAsync and IsReady methods for
// more details.
func (api *RepositoryAPI) Fork(timeout time.Duration) (*ForkResponse, error) {
	timeoutChan := time.After(timeout)

	forkResponse, err := api.ForkAsync()
	if err != nil {
		return nil, err
	}

	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			if ready, err := api.IsReady(); err != nil {
				return forkResponse, err
			} else if ready {
				return forkResponse, nil
			}
		case <-timeoutChan:
			return forkResponse, fmt.Errorf("timeout (%v) waiting for fork of %s/%s to complete",
				timeout, api.Owner, api.Repository)
		}
	}
}

// GetCommits returns commits for the repository.
func (api *RepositoryAPI) GetCommits(page int) ([]RepositoryCommit, error) {
	url := api.getURL("/repos/:owner/:repo/commits")

	// TODO (judwhite)
	// Link: <https://api.github.com/resource?page=2>; rel="next",
	//       <https://api.github.com/resource?page=5>; rel="last"

	resp, err := api.httpGet(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	commits := make([]RepositoryCommit, 0)

	j := json.NewDecoder(resp.Body)
	if err = j.Decode(&commits); err != nil {
		return nil, err
	}

	return commits, nil
}

// Exists returns true if the repository exists.
func (api *RepositoryAPI) Exists() (bool, error) {
	_, err := api.Get()
	if err != nil {
		if Is404(err) {
			return false, nil
		}
		return false, err
	}
	return true, nil
}

// IsReady returns true if the repository is "ready", which usually means a fork operation has completed.
// It does this by trying to list the first page of commits on the repository; if "/repos/:owner/:repo/commits"
// returns 409, the repository is not yet ready.
//
// This method is used internally by the Fork method. It can be used to check if a call to ForkAsync has completed
// the fork operation.
func (api *RepositoryAPI) IsReady() (bool, error) {
	_, err := api.GetCommits(1)
	if err != nil {
		if IsHTTPError(err, 409) {
			return false, nil
		}
		return false, err
	}
	return true, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
// resty source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

// Package resty provides simple HTTP and REST client for Go inspired by Ruby rest-client.
package resty

// Version # of resty
const Version = "1.3"
<commit_msg>version bump to v1.4-edge [ci skip]<commit_after>// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
// resty source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

// Package resty provides simple HTTP and REST client for Go inspired by Ruby rest-client.
package resty

// Version # of resty
const Version = "1.4-edge"
<|endoftext|>


<commit_before>package mars

import (
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"time"

	"github.com/agtorre/gocolorize"
	"github.com/robfig/config"
)

const (
	MarsImportPath     = "github.com/roblillack/mars"
	defaultLoggerFlags = log.Ldate | log.Ltime | log.Lshortfile
)

type marsLogs struct {
	c gocolorize.Colorize
	w io.Writer
}

func (r *marsLogs) Write(p []byte) (n int, err error) {
	return r.w.Write([]byte(r.c.Paint(string(p))))
}

var (
	// ConfigFile specifies the path of the main configuration file relative to BasePath, e.g. "conf/app.conf"
	ConfigFile = path.Join("conf", "app.conf")
	// MimeTypesFile specifies the path of the optional MIME type configuration file relative to BasePath, e.g. "conf/mime-types.conf"
	MimeTypesFile = path.Join("conf", "mime-types.conf")
	// RoutesFile specified the path of the route configuration file relative to BasePath, e.g. "conf/routes"
	RoutesFile = path.Join("conf", "routes")
	// ViewPath specifies the name of directory where all the templates are located relative to BasePath, e.g. "views"
	ViewsPath = "views"

	Config     = NewEmptyConfig()
	MimeConfig = NewEmptyConfig()

	// App details
	AppName  = "(not set)" // e.g. "sample"
	AppRoot  = ""          // e.g. "/app1"
	BasePath = "."         // e.g. "/Users/robfig/gocode/src/corp/sample"

	RunMode = "prod"
	DevMode = false

	// Server config.
	//
	// Alert: This is how the app is configured, which may be different from
	// the current process reality.  For example, if the app is configured for
	// port 9000, HttpPort will always be 9000, even though in dev mode it is
	// run on a random port and proxied.
	HttpPort    = 9000
	HttpAddr    = ""    // e.g. "", "127.0.0.1"
	HttpSsl     = false // e.g. true if using ssl
	HttpSslCert = ""    // e.g. "/path/to/cert.pem"
	HttpSslKey  = ""    // e.g. "/path/to/key.pem"

	// All cookies dropped by the framework begin with this prefix.
	CookiePrefix = "MARS"
	// Cookie domain
	CookieDomain = ""
	// Cookie flags
	CookieHttpOnly = false
	CookieSecure   = false

	// DisableCSRF disables CSRF checking altogether. See CSRFFilter for more information.
	DisableCSRF = false

	//Logger colors
	colors = map[string]gocolorize.Colorize{
		"trace": gocolorize.NewColor("magenta"),
		"info":  gocolorize.NewColor("green"),
		"warn":  gocolorize.NewColor("yellow"),
		"error": gocolorize.NewColor("red"),
	}

	// Loggers
	DisabledLogger = log.New(ioutil.Discard, "", 0)

	TRACE = DisabledLogger
	INFO  = log.New(&marsLogs{c: colors["info"], w: os.Stderr}, "INFO  ", defaultLoggerFlags)
	WARN  = log.New(&marsLogs{c: colors["warn"], w: os.Stderr}, "WARN  ", defaultLoggerFlags)
	ERROR = log.New(&marsLogs{c: colors["error"], w: os.Stderr}, "ERROR ", defaultLoggerFlags)

	MaxAge = time.Hour * 24 // MaxAge specifies the time browsers shall cache static content served using Static.Serve

	// Private
	secretKey []byte // Key used to sign cookies. An empty key disables signing.
)

func SetAppSecret(secret string) {
	secretKey = []byte(secret)
}

func init() {
	log.SetFlags(defaultLoggerFlags)
}

// InitDefaults initializes Mars based on runtime-loading of config files.
//
// Params:
//   mode - the run mode, which determines which app.conf settings are used.
//   basePath - the path to the configuration, messages, and view directories
func InitDefaults(mode, basePath string) {
	RunMode = mode

	if runtime.GOOS == "windows" {
		gocolorize.SetPlain(true)
	}

	BasePath = filepath.FromSlash(basePath)

	cfgPath := filepath.Join(BasePath, ConfigFile)
	if _, err := os.Stat(cfgPath); !os.IsNotExist(err) {
		var err error
		Config, err = LoadConfig(cfgPath)
		if err != nil || Config == nil {
			log.Fatalln("Failed to load app.conf:", err)
		}
	}

	MimeConfig, _ = LoadConfig(path.Join(BasePath, MimeTypesFile))

	// Ensure that the selected runmode appears in app.conf.
	// If empty string is passed as the mode, treat it as "DEFAULT"
	if mode == "" {
		mode = config.DEFAULT_SECTION
	}
	if Config.HasSection(mode) {
		Config.SetSection(mode)
	}

	// Configure properties from app.conf
	DevMode = Config.BoolDefault("mode.dev", DevMode)
	HttpPort = Config.IntDefault("http.port", HttpPort)
	HttpAddr = Config.StringDefault("http.addr", HttpAddr)
	HttpSsl = Config.BoolDefault("http.ssl", HttpSsl)
	HttpSslCert = Config.StringDefault("http.sslcert", HttpSslCert)
	HttpSslKey = Config.StringDefault("http.sslkey", HttpSslKey)

	if HttpSsl {
		if HttpSslCert == "" {
			log.Fatalln("No http.sslcert provided.")
		}
		if HttpSslKey == "" {
			log.Fatalln("No http.sslkey provided.")
		}
	}

	AppName = Config.StringDefault("app.name", AppName)
	AppRoot = Config.StringDefault("app.root", AppRoot)
	CookiePrefix = Config.StringDefault("cookie.prefix", CookiePrefix)
	CookieDomain = Config.StringDefault("cookie.domain", CookieDomain)
	CookieHttpOnly = Config.BoolDefault("cookie.httponly", CookieHttpOnly)
	CookieSecure = Config.BoolDefault("cookie.secure", CookieSecure)

	if s := Config.StringDefault("app.secret", ""); s != "" {
		SetAppSecret(s)
	}

	// Configure logging
	if !Config.BoolDefault("log.colorize", true) {
		gocolorize.SetPlain(true)
	}

	TRACE = getLogger("trace", TRACE)
	INFO = getLogger("info", INFO)
	WARN = getLogger("warn", WARN)
	ERROR = getLogger("error", ERROR)

	// The "watch" config variable can turn on and off all watching.
	// (As a convenient way to control it all together.)
	if Config.BoolDefault("watch", true) {
		MainWatcher = NewWatcher()
		Filters = append([]Filter{WatchFilter}, Filters...)
	}

	if MainTemplateLoader == nil {
		SetupViews()
	}
	if MainRouter == nil {
		SetupRouter()
	}

	INFO.Printf("Initialized Mars v%s (%s) for %s", VERSION, BUILD_DATE, MINIMUM_GO)

	runStartupHooks()
}

// SetupViews will create a template loader for all the templates provided in ViewsPath
func SetupViews() {
	MainTemplateLoader = NewTemplateLoader([]string{path.Join(BasePath, ViewsPath)})
	if err := MainTemplateLoader.Refresh(); err != nil {
		ERROR.Fatalln(err.Error())
	}

	// If desired (or by default), create a watcher for templates and routes.
	// The watcher calls Refresh() on things on the first request.
	if MainWatcher != nil && Config.BoolDefault("watch.templates", true) {
		MainWatcher.Listen(MainTemplateLoader, MainTemplateLoader.paths...)
	}
}

// SetupRouter will create the router of the application based on the information
// provided in RoutesFile and the controllers and actions which have been registered
// using RegisterController.
func SetupRouter() {
	MainRouter = NewRouter(filepath.Join(BasePath, RoutesFile))
	if err := MainRouter.Refresh(); err != nil {
		ERROR.Fatalln(err.Error())
	}

	// If desired (or by default), create a watcher for templates and routes.
	// The watcher calls Refresh() on things on the first request.
	if MainWatcher != nil && Config.BoolDefault("watch.routes", true) {
		MainWatcher.Listen(MainRouter, MainRouter.path)
	}
}

// Create a logger using log.* directives in app.conf plus the current settings
// on the default logger.
func getLogger(name string, original *log.Logger) *log.Logger {
	var logger *log.Logger

	// Create a logger with the requested output. (default to stderr)
	output := Config.StringDefault("log."+name+".output", "")

	switch output {
	case "":
		return original
	case "stdout":
		logger = newLogger(&marsLogs{c: colors[name], w: os.Stdout})
	case "stderr":
		logger = newLogger(&marsLogs{c: colors[name], w: os.Stderr})
	case "off":
		return DisabledLogger
	default:
		file, err := os.OpenFile(output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalln("Failed to open log file", output, ":", err)
		}
		logger = newLogger(file)
	}

	// Set the prefix / flags.
	flags, found := Config.Int("log." + name + ".flags")
	if found {
		logger.SetFlags(flags)
	}

	prefix, found := Config.String("log." + name + ".prefix")
	if found {
		logger.SetPrefix(prefix)
	}

	return logger
}

func newLogger(wr io.Writer) *log.Logger {
	return log.New(wr, "", defaultLoggerFlags)
}
<commit_msg>Allow setting absolute ConfigFile path.<commit_after>package mars

import (
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"time"

	"github.com/agtorre/gocolorize"
	"github.com/robfig/config"
)

const (
	MarsImportPath     = "github.com/roblillack/mars"
	defaultLoggerFlags = log.Ldate | log.Ltime | log.Lshortfile
)

type marsLogs struct {
	c gocolorize.Colorize
	w io.Writer
}

func (r *marsLogs) Write(p []byte) (n int, err error) {
	return r.w.Write([]byte(r.c.Paint(string(p))))
}

var (
	// ConfigFile specifies the path of the main configuration file relative to BasePath, e.g. "conf/app.conf"
	ConfigFile = path.Join("conf", "app.conf")
	// MimeTypesFile specifies the path of the optional MIME type configuration file relative to BasePath, e.g. "conf/mime-types.conf"
	MimeTypesFile = path.Join("conf", "mime-types.conf")
	// RoutesFile specified the path of the route configuration file relative to BasePath, e.g. "conf/routes"
	RoutesFile = path.Join("conf", "routes")
	// ViewPath specifies the name of directory where all the templates are located relative to BasePath, e.g. "views"
	ViewsPath = "views"

	Config     = NewEmptyConfig()
	MimeConfig = NewEmptyConfig()

	// App details
	AppName  = "(not set)" // e.g. "sample"
	AppRoot  = ""          // e.g. "/app1"
	BasePath = "."         // e.g. "/Users/robfig/gocode/src/corp/sample"

	RunMode = "prod"
	DevMode = false

	// Server config.
	//
	// Alert: This is how the app is configured, which may be different from
	// the current process reality.  For example, if the app is configured for
	// port 9000, HttpPort will always be 9000, even though in dev mode it is
	// run on a random port and proxied.
	HttpPort    = 9000
	HttpAddr    = ""    // e.g. "", "127.0.0.1"
	HttpSsl     = false // e.g. true if using ssl
	HttpSslCert = ""    // e.g. "/path/to/cert.pem"
	HttpSslKey  = ""    // e.g. "/path/to/key.pem"

	// All cookies dropped by the framework begin with this prefix.
	CookiePrefix = "MARS"
	// Cookie domain
	CookieDomain = ""
	// Cookie flags
	CookieHttpOnly = false
	CookieSecure   = false

	// DisableCSRF disables CSRF checking altogether. See CSRFFilter for more information.
	DisableCSRF = false

	//Logger colors
	colors = map[string]gocolorize.Colorize{
		"trace": gocolorize.NewColor("magenta"),
		"info":  gocolorize.NewColor("green"),
		"warn":  gocolorize.NewColor("yellow"),
		"error": gocolorize.NewColor("red"),
	}

	// Loggers
	DisabledLogger = log.New(ioutil.Discard, "", 0)

	TRACE = DisabledLogger
	INFO  = log.New(&marsLogs{c: colors["info"], w: os.Stderr}, "INFO  ", defaultLoggerFlags)
	WARN  = log.New(&marsLogs{c: colors["warn"], w: os.Stderr}, "WARN  ", defaultLoggerFlags)
	ERROR = log.New(&marsLogs{c: colors["error"], w: os.Stderr}, "ERROR ", defaultLoggerFlags)

	MaxAge = time.Hour * 24 // MaxAge specifies the time browsers shall cache static content served using Static.Serve

	// Private
	secretKey []byte // Key used to sign cookies. An empty key disables signing.
)

func SetAppSecret(secret string) {
	secretKey = []byte(secret)
}

func init() {
	log.SetFlags(defaultLoggerFlags)
}

// InitDefaults initializes Mars based on runtime-loading of config files.
//
// Params:
//   mode - the run mode, which determines which app.conf settings are used.
//   basePath - the path to the configuration, messages, and view directories
func InitDefaults(mode, basePath string) {
	RunMode = mode

	if runtime.GOOS == "windows" {
		gocolorize.SetPlain(true)
	}

	BasePath = filepath.FromSlash(basePath)

	var cfgPath string
	if filepath.IsAbs(ConfigFile) {
		cfgPath = ConfigFile
	} else {
		cfgPath = filepath.Join(BasePath, ConfigFile)
	}

	if _, err := os.Stat(cfgPath); !os.IsNotExist(err) {
		var err error
		Config, err = LoadConfig(cfgPath)
		if err != nil || Config == nil {
			log.Fatalln("Failed to load app.conf:", err)
		}
	}

	MimeConfig, _ = LoadConfig(path.Join(BasePath, MimeTypesFile))

	// Ensure that the selected runmode appears in app.conf.
	// If empty string is passed as the mode, treat it as "DEFAULT"
	if mode == "" {
		mode = config.DEFAULT_SECTION
	}
	if Config.HasSection(mode) {
		Config.SetSection(mode)
	}

	// Configure properties from app.conf
	DevMode = Config.BoolDefault("mode.dev", DevMode)
	HttpPort = Config.IntDefault("http.port", HttpPort)
	HttpAddr = Config.StringDefault("http.addr", HttpAddr)
	HttpSsl = Config.BoolDefault("http.ssl", HttpSsl)
	HttpSslCert = Config.StringDefault("http.sslcert", HttpSslCert)
	HttpSslKey = Config.StringDefault("http.sslkey", HttpSslKey)

	if HttpSsl {
		if HttpSslCert == "" {
			log.Fatalln("No http.sslcert provided.")
		}
		if HttpSslKey == "" {
			log.Fatalln("No http.sslkey provided.")
		}
	}

	AppName = Config.StringDefault("app.name", AppName)
	AppRoot = Config.StringDefault("app.root", AppRoot)
	CookiePrefix = Config.StringDefault("cookie.prefix", CookiePrefix)
	CookieDomain = Config.StringDefault("cookie.domain", CookieDomain)
	CookieHttpOnly = Config.BoolDefault("cookie.httponly", CookieHttpOnly)
	CookieSecure = Config.BoolDefault("cookie.secure", CookieSecure)

	if s := Config.StringDefault("app.secret", ""); s != "" {
		SetAppSecret(s)
	}

	// Configure logging
	if !Config.BoolDefault("log.colorize", true) {
		gocolorize.SetPlain(true)
	}

	TRACE = getLogger("trace", TRACE)
	INFO = getLogger("info", INFO)
	WARN = getLogger("warn", WARN)
	ERROR = getLogger("error", ERROR)

	// The "watch" config variable can turn on and off all watching.
	// (As a convenient way to control it all together.)
	if Config.BoolDefault("watch", true) {
		MainWatcher = NewWatcher()
		Filters = append([]Filter{WatchFilter}, Filters...)
	}

	if MainTemplateLoader == nil {
		SetupViews()
	}
	if MainRouter == nil {
		SetupRouter()
	}

	INFO.Printf("Initialized Mars v%s (%s) for %s", VERSION, BUILD_DATE, MINIMUM_GO)

	runStartupHooks()
}

// SetupViews will create a template loader for all the templates provided in ViewsPath
func SetupViews() {
	MainTemplateLoader = NewTemplateLoader([]string{path.Join(BasePath, ViewsPath)})
	if err := MainTemplateLoader.Refresh(); err != nil {
		ERROR.Fatalln(err.Error())
	}

	// If desired (or by default), create a watcher for templates and routes.
	// The watcher calls Refresh() on things on the first request.
	if MainWatcher != nil && Config.BoolDefault("watch.templates", true) {
		MainWatcher.Listen(MainTemplateLoader, MainTemplateLoader.paths...)
	}
}

// SetupRouter will create the router of the application based on the information
// provided in RoutesFile and the controllers and actions which have been registered
// using RegisterController.
func SetupRouter() {
	MainRouter = NewRouter(filepath.Join(BasePath, RoutesFile))
	if err := MainRouter.Refresh(); err != nil {
		ERROR.Fatalln(err.Error())
	}

	// If desired (or by default), create a watcher for templates and routes.
	// The watcher calls Refresh() on things on the first request.
	if MainWatcher != nil && Config.BoolDefault("watch.routes", true) {
		MainWatcher.Listen(MainRouter, MainRouter.path)
	}
}

// Create a logger using log.* directives in app.conf plus the current settings
// on the default logger.
func getLogger(name string, original *log.Logger) *log.Logger {
	var logger *log.Logger

	// Create a logger with the requested output. (default to stderr)
	output := Config.StringDefault("log."+name+".output", "")

	switch output {
	case "":
		return original
	case "stdout":
		logger = newLogger(&marsLogs{c: colors[name], w: os.Stdout})
	case "stderr":
		logger = newLogger(&marsLogs{c: colors[name], w: os.Stderr})
	case "off":
		return DisabledLogger
	default:
		file, err := os.OpenFile(output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalln("Failed to open log file", output, ":", err)
		}
		logger = newLogger(file)
	}

	// Set the prefix / flags.
	flags, found := Config.Int("log." + name + ".flags")
	if found {
		logger.SetFlags(flags)
	}

	prefix, found := Config.String("log." + name + ".prefix")
	if found {
		logger.SetPrefix(prefix)
	}

	return logger
}

func newLogger(wr io.Writer) *log.Logger {
	return log.New(wr, "", defaultLoggerFlags)
}
<|endoftext|>


<commit_before>// Http image server
package http

import (
	"fmt"
	"github.com/pierrre/imageserver"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

var inmHeaderRegexp, _ = regexp.Compile("^\"(.+)\"$")

var expiresHeaderLocation, _ = time.LoadLocation("GMT")

// Http image server
//
// Only GET and HEAD methods are supported.
//
// Supports ETag/If-None-Match (status code 304).
// It doesn't check if the image really exists.
//
// Status codes: 200 (everything is ok), 400 (user error), 500 (internal error).
//
// If Expire is defined, the "Expires" header is set.
//
// The ErrFunc function allows to handler internal errors.
//
// The HeaderFunc function allows to set custom headers.
type Server struct {
	Parser      Parser
	ImageServer *imageserver.Server

	Expire time.Duration // optional

	RequestFunc func(*http.Request) error               //optional
	HeaderFunc  func(http.Header, *http.Request, error) // optional
	ErrorFunc   func(error, *http.Request)              //optional
}

func (server *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	if request.Method != "GET" && request.Method != "HEAD" {
		server.sendError(writer, request, NewError(http.StatusMethodNotAllowed))
		return
	}

	if server.RequestFunc != nil {
		if err := server.RequestFunc(request); err != nil {
			server.sendError(writer, request, err)
		}
	}

	parameters := make(imageserver.Parameters)
	if err := server.Parser.Parse(request, parameters); err != nil {
		server.sendError(writer, request, err)
		return
	}

	if server.checkNotModified(writer, request, parameters) {
		return
	}

	image, err := server.ImageServer.Get(parameters)
	if err != nil {
		server.sendError(writer, request, err)
		return
	}

	if err := server.sendImage(writer, request, parameters, image); err != nil {
		server.callErrFunc(err, request)
		return
	}
}

func (server *Server) checkNotModified(writer http.ResponseWriter, request *http.Request, parameters imageserver.Parameters) bool {
	inmHeader := request.Header.Get("If-None-Match")
	if len(inmHeader) == 0 {
		return false
	}

	matches := inmHeaderRegexp.FindStringSubmatch(inmHeader)
	if matches == nil {
		return false
	}

	inm := matches[1]
	if inm != parameters.Hash() {
		return false
	}

	server.setImageHeaderCommon(writer, request, parameters)
	writer.WriteHeader(http.StatusNotModified)
	return true
}

func (server *Server) sendImage(writer http.ResponseWriter, request *http.Request, parameters imageserver.Parameters, image *imageserver.Image) error {
	server.setImageHeaderCommon(writer, request, parameters)

	if len(image.Type) > 0 {
		writer.Header().Set("Content-Type", "image/"+image.Type)
	}

	writer.Header().Set("Content-Length", strconv.Itoa(len(image.Data)))

	if request.Method == "GET" {
		if _, err := writer.Write(image.Data); err != nil {
			return err
		}
	}

	return nil
}

func (server *Server) setImageHeaderCommon(writer http.ResponseWriter, request *http.Request, parameters imageserver.Parameters) {
	header := writer.Header()

	header.Set("Cache-Control", "public")

	header.Set("ETag", fmt.Sprintf("\"%s\"", parameters.Hash()))

	if server.Expire != 0 {
		t := time.Now()
		t = t.Add(server.Expire)
		t = t.In(expiresHeaderLocation)
		header.Set("Expires", t.Format(time.RFC1123))
	}

	server.callHeaderFunc(header, request, nil)
}

func (server *Server) sendError(writer http.ResponseWriter, request *http.Request, err error) {
	var code int
	var message string

	switch err := err.(type) {
	case *imageserver.Error:
		code = http.StatusBadRequest
		message = err.Error()
	case *Error:
		code = err.Code
		message = err.Error()
	default:
		code = http.StatusInternalServerError
		message = http.StatusText(code)

		server.callErrFunc(err, request)
	}

	server.callHeaderFunc(writer.Header(), request, err)

	http.Error(writer, message, code)
}

func (server *Server) callErrFunc(err error, request *http.Request) {
	if server.ErrorFunc != nil {
		server.ErrorFunc(err, request)
	}
}

func (server *Server) callHeaderFunc(header http.Header, request *http.Request, err error) {
	if server.HeaderFunc != nil {
		server.HeaderFunc(header, request, err)
	}
}
<commit_msg>Comment<commit_after>// Http image server
package http

import (
	"fmt"
	"github.com/pierrre/imageserver"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

var inmHeaderRegexp, _ = regexp.Compile("^\"(.+)\"$")

var expiresHeaderLocation, _ = time.LoadLocation("GMT")

// Http image server
//
// Only GET and HEAD methods are supported.
//
// Supports ETag/If-None-Match (status code 304).
// It doesn't check if the image really exists.
//
// Status codes: 200 (everything is ok), 400 (user error), 500 (internal error).
//
// If Expire is defined, the "Expires" header is set.
//
// The ErrFunc function allows to handler internal errors.
//
// The HeaderFunc function allows to set custom headers.
type Server struct {
	Parser      Parser
	ImageServer *imageserver.Server

	Expire time.Duration // optional

	RequestFunc func(*http.Request) error               // optional
	HeaderFunc  func(http.Header, *http.Request, error) // optional
	ErrorFunc   func(error, *http.Request)              // optional
}

func (server *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	if request.Method != "GET" && request.Method != "HEAD" {
		server.sendError(writer, request, NewError(http.StatusMethodNotAllowed))
		return
	}

	if server.RequestFunc != nil {
		if err := server.RequestFunc(request); err != nil {
			server.sendError(writer, request, err)
		}
	}

	parameters := make(imageserver.Parameters)
	if err := server.Parser.Parse(request, parameters); err != nil {
		server.sendError(writer, request, err)
		return
	}

	if server.checkNotModified(writer, request, parameters) {
		return
	}

	image, err := server.ImageServer.Get(parameters)
	if err != nil {
		server.sendError(writer, request, err)
		return
	}

	if err := server.sendImage(writer, request, parameters, image); err != nil {
		server.callErrFunc(err, request)
		return
	}
}

func (server *Server) checkNotModified(writer http.ResponseWriter, request *http.Request, parameters imageserver.Parameters) bool {
	inmHeader := request.Header.Get("If-None-Match")
	if len(inmHeader) == 0 {
		return false
	}

	matches := inmHeaderRegexp.FindStringSubmatch(inmHeader)
	if matches == nil {
		return false
	}

	inm := matches[1]
	if inm != parameters.Hash() {
		return false
	}

	server.setImageHeaderCommon(writer, request, parameters)
	writer.WriteHeader(http.StatusNotModified)
	return true
}

func (server *Server) sendImage(writer http.ResponseWriter, request *http.Request, parameters imageserver.Parameters, image *imageserver.Image) error {
	server.setImageHeaderCommon(writer, request, parameters)

	if len(image.Type) > 0 {
		writer.Header().Set("Content-Type", "image/"+image.Type)
	}

	writer.Header().Set("Content-Length", strconv.Itoa(len(image.Data)))

	if request.Method == "GET" {
		if _, err := writer.Write(image.Data); err != nil {
			return err
		}
	}

	return nil
}

func (server *Server) setImageHeaderCommon(writer http.ResponseWriter, request *http.Request, parameters imageserver.Parameters) {
	header := writer.Header()

	header.Set("Cache-Control", "public")

	header.Set("ETag", fmt.Sprintf("\"%s\"", parameters.Hash()))

	if server.Expire != 0 {
		t := time.Now()
		t = t.Add(server.Expire)
		t = t.In(expiresHeaderLocation)
		header.Set("Expires", t.Format(time.RFC1123))
	}

	server.callHeaderFunc(header, request, nil)
}

func (server *Server) sendError(writer http.ResponseWriter, request *http.Request, err error) {
	var code int
	var message string

	switch err := err.(type) {
	case *imageserver.Error:
		code = http.StatusBadRequest
		message = err.Error()
	case *Error:
		code = err.Code
		message = err.Error()
	default:
		code = http.StatusInternalServerError
		message = http.StatusText(code)

		server.callErrFunc(err, request)
	}

	server.callHeaderFunc(writer.Header(), request, err)

	http.Error(writer, message, code)
}

func (server *Server) callErrFunc(err error, request *http.Request) {
	if server.ErrorFunc != nil {
		server.ErrorFunc(err, request)
	}
}

func (server *Server) callHeaderFunc(header http.Header, request *http.Request, err error) {
	if server.HeaderFunc != nil {
		server.HeaderFunc(header, request, err)
	}
}
<|endoftext|>


<commit_before>// Package hyperloglog implements the HyperLogLog algorithm for
// cardinality estimation. In English: it counts things. It counts
// things using very small amounts of memory compared to the number of
// objects it is counting.
//
// For a full description of the algorithm, see the paper HyperLogLog:
// the analysis of a near-optimal cardinality estimation algorithm by
// Flajolet, et. al.
package hyperloglog

import (
	"fmt"
	"math"
)

var (
	exp32 = math.Pow(2, 32)
)

type HyperLogLog struct {
	m         uint    // Number of registers
	b         uint32  // Number of bits used to determine register index
	alpha     float64 // Bias correction constant
	registers []uint8
}

// Compute bias correction alpha_m.
func get_alpha(m uint) (result float64) {
	switch m {
	case 16:
		result = 0.673
	case 32:
		result = 0.697
	case 64:
		result = 0.709
	default:
		result = 0.7213 / (1.0 + 1.079/float64(m))
	}
	return result
}

// Return a new HyperLogLog with the given number of registers. More
// registers leads to lower error in your estimated count, at the
// expense of memory.
//
// Choose a power of two number of registers, depending on the amount
// of memory you're willing to use and the error you're willing to
// tolerate. Each register uses one byte of memory.
//
// Approximate error will be:
//     1.04 / sqrt(registers)
//
func New(registers uint) (*HyperLogLog, error) {
	if (registers & (registers - 1)) != 0 {
		return nil, fmt.Errorf("number of registers %d not a power of two", registers)
	}
	h := &HyperLogLog{}
	h.m = registers
	h.b = uint32(math.Ceil(math.Log2(float64(registers))))
	h.alpha = get_alpha(registers)
	h.Reset()
	return h, nil
}

// Reset all internal variables and set the count to zero.
func (h *HyperLogLog) Reset() {
	h.registers = make([]uint8, h.m)
}

// Calculate the position of the leftmost 1-bit.
func rho(val uint32, max uint32) uint8 {
	r := uint32(1)
	for val&0x80000000 == 0 && r <= max {
		r++
		val <<= 1
	}
	return uint8(r)
}

// Add to the count. val should be a 32 bit unsigned integer from a
// good hash function.
func (h *HyperLogLog) Add(val uint32) {
	k := 32 - h.b
	r := rho(val<<h.b, k)
	j := val >> uint(k)
	if r > h.registers[j] {
		h.registers[j] = r
	}
}

// Get the estimated count.
func (h *HyperLogLog) Count() uint64 {
	sum := 0.0
	for _, val := range h.registers {
		sum += 1.0 / math.Pow(2.0, float64(val))
	}
	estimate := h.alpha * float64(h.m*h.m) / sum
	if estimate <= 5.0/2.0*float64(h.m) {
		// Small range correction
		v := 0
		for _, r := range h.registers {
			if r == 0 {
				v++
			}
		}
		if v > 0 {
			estimate = float64(h.m) * math.Log(float64(h.m)/float64(v))
		}
	} else if estimate > 1.0/30.0*exp32 {
		// Large range correction
		estimate = -exp32 * math.Log(1-estimate/exp32)
	}
	return uint64(estimate)
}

// Merge another HyperLogLog into this one. The number of registers in
// each must be the same.
func (h1 *HyperLogLog) Merge(h2 *HyperLogLog) error {
	if h1.m != h2.m {
		return fmt.Errorf("number of registers doesn't match: %d != %d",
			h1.m, h2.m)
	}
	for j, r := range h2.registers {
		if r > h1.registers[j] {
			h1.registers[j] = r
		}
	}
	return nil
}
<commit_msg>Stop casting all over the place<commit_after>// Package hyperloglog implements the HyperLogLog algorithm for
// cardinality estimation. In English: it counts things. It counts
// things using very small amounts of memory compared to the number of
// objects it is counting.
//
// For a full description of the algorithm, see the paper HyperLogLog:
// the analysis of a near-optimal cardinality estimation algorithm by
// Flajolet, et. al.
package hyperloglog

import (
	"fmt"
	"math"
)

var (
	exp32 = math.Pow(2, 32)
)

type HyperLogLog struct {
	m         uint    // Number of registers
	b         uint32  // Number of bits used to determine register index
	alpha     float64 // Bias correction constant
	registers []uint8
}

// Compute bias correction alpha_m.
func get_alpha(m uint) (result float64) {
	switch m {
	case 16:
		result = 0.673
	case 32:
		result = 0.697
	case 64:
		result = 0.709
	default:
		result = 0.7213 / (1.0 + 1.079/float64(m))
	}
	return result
}

// Return a new HyperLogLog with the given number of registers. More
// registers leads to lower error in your estimated count, at the
// expense of memory.
//
// Choose a power of two number of registers, depending on the amount
// of memory you're willing to use and the error you're willing to
// tolerate. Each register uses one byte of memory.
//
// Approximate error will be:
//     1.04 / sqrt(registers)
//
func New(registers uint) (*HyperLogLog, error) {
	if (registers & (registers - 1)) != 0 {
		return nil, fmt.Errorf("number of registers %d not a power of two", registers)
	}
	h := &HyperLogLog{}
	h.m = registers
	h.b = uint32(math.Ceil(math.Log2(float64(registers))))
	h.alpha = get_alpha(registers)
	h.Reset()
	return h, nil
}

// Reset all internal variables and set the count to zero.
func (h *HyperLogLog) Reset() {
	h.registers = make([]uint8, h.m)
}

// Calculate the position of the leftmost 1-bit.
func rho(val uint32, max uint32) uint8 {
	r := uint32(1)
	for val&0x80000000 == 0 && r <= max {
		r++
		val <<= 1
	}
	return uint8(r)
}

// Add to the count. val should be a 32 bit unsigned integer from a
// good hash function.
func (h *HyperLogLog) Add(val uint32) {
	k := 32 - h.b
	r := rho(val<<h.b, k)
	j := val >> uint(k)
	if r > h.registers[j] {
		h.registers[j] = r
	}
}

// Get the estimated count.
func (h *HyperLogLog) Count() uint64 {
	sum := 0.0
	m := float64(h.m)
	for _, val := range h.registers {
		sum += 1.0 / math.Pow(2.0, float64(val))
	}
	estimate := h.alpha * m * m / sum
	if estimate <= 5.0/2.0*m {
		// Small range correction
		v := 0
		for _, r := range h.registers {
			if r == 0 {
				v++
			}
		}
		if v > 0 {
			estimate = m * math.Log(m/float64(v))
		}
	} else if estimate > 1.0/30.0*exp32 {
		// Large range correction
		estimate = -exp32 * math.Log(1-estimate/exp32)
	}
	return uint64(estimate)
}

// Merge another HyperLogLog into this one. The number of registers in
// each must be the same.
func (h1 *HyperLogLog) Merge(h2 *HyperLogLog) error {
	if h1.m != h2.m {
		return fmt.Errorf("number of registers doesn't match: %d != %d",
			h1.m, h2.m)
	}
	for j, r := range h2.registers {
		if r > h1.registers[j] {
			h1.registers[j] = r
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package ethutil

import (
	"math/big"
	"os"
	"testing"
)

func TestOS(t *testing.T) {
	res := IsWindows()

	if res && (os.PathSeparator != '\\' || os.PathListSeparator != ';') {
		t.Error("IsWindows is", res, "but path is", os.PathSeparator)
	}

	if !res && (os.PathSeparator == '\\' && os.PathListSeparator == ';') {
		t.Error("IsWindows is", res, "but path is", os.PathSeparator)
	}
}

func TestWindonziePath(t *testing.T) {
	path := "/opt/eth/test/file.ext"
	res := WindonizePath(path)
	iswindowspath := os.PathSeparator == '\\'

	if !iswindowspath && string(res[0]) != "/" {
		t.Error("Got", res)
	}

	if iswindowspath && string(res[0]) == "/" {
		t.Error("Got", res)
	}
}

func TestCommon(t *testing.T) {
	ether := CurrencyToString(BigPow(10, 19))
	finney := CurrencyToString(BigPow(10, 16))
	szabo := CurrencyToString(BigPow(10, 13))
	vito := CurrencyToString(BigPow(10, 10))
	turing := CurrencyToString(BigPow(10, 7))
	eins := CurrencyToString(BigPow(10, 4))
	wei := CurrencyToString(big.NewInt(10))

	if ether != "10 Ether" {
		t.Error("Got", ether)
	}

	if finney != "10 Finney" {
		t.Error("Got", finney)
	}

	if szabo != "10 Szabo" {
		t.Error("Got", szabo)
	}

	if vito != "10 Shannon" {
		t.Error("Got", vito)
	}

	if turing != "10 Babbage" {
		t.Error("Got", turing)
	}

	if eins != "10 Ada" {
		t.Error("Got", eins)
	}

	if wei != "10 Wei" {
		t.Error("Got", wei)
	}
}
<commit_msg>Update variable name to match unit name<commit_after>package ethutil

import (
	"math/big"
	"os"
	"testing"
)

func TestOS(t *testing.T) {
	res := IsWindows()

	if res && (os.PathSeparator != '\\' || os.PathListSeparator != ';') {
		t.Error("IsWindows is", res, "but path is", os.PathSeparator)
	}

	if !res && (os.PathSeparator == '\\' && os.PathListSeparator == ';') {
		t.Error("IsWindows is", res, "but path is", os.PathSeparator)
	}
}

func TestWindonziePath(t *testing.T) {
	path := "/opt/eth/test/file.ext"
	res := WindonizePath(path)
	iswindowspath := os.PathSeparator == '\\'

	if !iswindowspath && string(res[0]) != "/" {
		t.Error("Got", res)
	}

	if iswindowspath && string(res[0]) == "/" {
		t.Error("Got", res)
	}
}

func TestCommon(t *testing.T) {
	ether := CurrencyToString(BigPow(10, 19))
	finney := CurrencyToString(BigPow(10, 16))
	szabo := CurrencyToString(BigPow(10, 13))
	shannon := CurrencyToString(BigPow(10, 10))
	babbage := CurrencyToString(BigPow(10, 7))
	ada := CurrencyToString(BigPow(10, 4))
	wei := CurrencyToString(big.NewInt(10))

	if ether != "10 Ether" {
		t.Error("Got", ether)
	}

	if finney != "10 Finney" {
		t.Error("Got", finney)
	}

	if szabo != "10 Szabo" {
		t.Error("Got", szabo)
	}

	if shannon != "10 Shannon" {
		t.Error("Got", shannon)
	}

	if babbage != "10 Babbage" {
		t.Error("Got", babbage)
	}

	if ada != "10 Ada" {
		t.Error("Got", ada)
	}

	if wei != "10 Wei" {
		t.Error("Got", wei)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 The Bazel 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 main

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/bazelbuild/bazel-watcher/bazel"
	"github.com/fsnotify/fsnotify"
)

var b *bazel.Bazel

func usage() {
	fmt.Printf(`ibazel

A file watcher for Bazel. Whenever a source file used in a specified
target, run, build, or test the specified targets.

Usage:

ibazel build|test|run targets...

Example:

ibazel test //path/to/my/testing:target
ibazel test //path/to/my/testing/targets/...
ibazel run //path/to/my/runnable:target
ibazel build //path/to/my/buildable:target

`)
}

func main() {

	if len(os.Args) < 3 {
		usage()
		return
	}

	b = bazel.New()

	command := os.Args[1]
	target := os.Args[2]

	query := fmt.Sprintf("kind('source file', deps('%s'))", target)

	toWatch := queryForSourceFiles(query)

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		fmt.Printf("Watcher error: %v", err)
		return
	}
	defer watcher.Close()

	for _, line := range toWatch {
		fmt.Printf("Line: %s\n", line)
		err = watcher.Add(line)
		if err != nil {
			fmt.Printf("Error watching: %v", err)
			return
		}
	}

	var commandToRun func(*bazel.Bazel, string)
	switch command {
	case "build":
		fmt.Printf("Building %s\n", target)
		commandToRun = build
	case "test":
		fmt.Printf("Testing %s\n", target)
		commandToRun = test
	case "run":
		fmt.Printf("Running %s\n", target)
		commandToRun = run
	default:
		fmt.Printf("Asked me to perform %s. I don't know how to do that.", command)
		return
	}

	// Listen to the events and trigger action based on the response code.
	go func() {
		for {
			select {
			case _ = <-watcher.Events:
				fmt.Printf("Files changed rebuilding...\n")
				commandToRun(b, target)
			case err := <-watcher.Errors:
				fmt.Println("Error:", err)
			}
		}
	}()

	// Kick things off by sending an event to make the first run happen.
	watcher.Events <- fsnotify.Event{}

	// Wait for the file to change for 24 hours. If it doesn't quit.
	time.Sleep(24 * time.Hour)
}

func queryForSourceFiles(query string) []string {
	res, err := b.Query(query)
	if err != nil {
		fmt.Printf("Error running Bazel %s\n", err)
	}

	toWatch := make([]string, 0, 10000)
	for _, line := range res {
		if strings.HasPrefix(line, "@") {
			continue
		}

		toWatch = append(toWatch, strings.Replace(strings.TrimPrefix(line, "//"), ":", "/", 1))
	}
	return toWatch
}

func build(b *bazel.Bazel, target string) {
	b.Cancel()
	b.WriteToStderr(true)
	b.WriteToStdout(true)
	err := b.Build(target)
	if err != nil {
		fmt.Printf("Build error: %v", err)
		return
	}
}

func test(b *bazel.Bazel, target string) {
	b.Cancel()
	b.WriteToStderr(true)
	b.WriteToStdout(true)
	err := b.Test(target)
	if err != nil {
		fmt.Printf("Build error: %v", err)
		return
	}
}

func run(b *bazel.Bazel, target string) {
	b.Cancel()
	b.WriteToStderr(true)
	b.WriteToStdout(true)
	// Start run in a goroutine so that it doesn't block.
	go b.Run(target)
}
<commit_msg>Add a debounce of 100ms to ibazel actions. (#7)<commit_after>// Copyright 2017 The Bazel 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 main

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/bazelbuild/bazel-watcher/bazel"
	"github.com/fsnotify/fsnotify"
)

type State string

const (
	DEBOUNCE_QUERY State = "DEBOUNCE_QUERY"
	QUERY          State = "QUERY"
	WAIT           State = "WAIT"
	DEBOUNCE_RUN   State = "DEBOUNCE_RUN"
	RUN            State = "RUN"
	QUIT           State = "QUIT"
)

const debounceDuration = 100 * time.Millisecond
const sourceQuery = "kind('source file', deps(set(%s)))"
const buildQuery = "buildfiles(deps(set(%s)))"

func usage() {
	fmt.Printf(`ibazel

A file watcher for Bazel. Whenever a source file used in a specified
target, run, build, or test the specified targets.

Usage:

ibazel build|test|run targets...

Example:

ibazel test //path/to/my/testing:target
ibazel test //path/to/my/testing/targets/...
ibazel run //path/to/my/runnable:target
ibazel build //path/to/my/buildable:target

`)
}

func main() {

	if len(os.Args) < 3 {
		usage()
		return
	}

	command := os.Args[1]
	target := os.Args[2]

	// Even though we are going to recreate this when the query happens, create
	// the pointer we will use to refer to the watchers right now.
	buildFileWatcher, err := fsnotify.NewWatcher()
	if err != nil {
		fmt.Printf("Watcher error: %v", err)
		return
	}
	defer buildFileWatcher.Close()

	sourceFileWatcher, err := fsnotify.NewWatcher()
	if err != nil {
		fmt.Printf("Watcher error: %v", err)
		return
	}
	defer sourceFileWatcher.Close()

	var commandToRun func(string)
	switch command {
	case "build":
		fmt.Printf("Building %s\n", target)
		commandToRun = build
	case "test":
		fmt.Printf("Testing %s\n", target)
		commandToRun = test
	case "run":
		fmt.Printf("Running %s\n", target)
		commandToRun = run
	default:
		fmt.Printf("Asked me to perform %s. I don't know how to do that.", command)
		return
	}

	state := QUERY
	for {
		fmt.Printf("State: %s\n", state)
		switch state {
		case WAIT:
			select {
			case <-sourceFileWatcher.Events:
				fmt.Printf("Detected source change. Rebuilding...\n")
				state = DEBOUNCE_RUN
			case <-buildFileWatcher.Events:
				fmt.Printf("Detected build graph change. Requerying...\n")
				state = DEBOUNCE_QUERY
			}
		case DEBOUNCE_QUERY:
			select {
			case <-buildFileWatcher.Events:
				state = DEBOUNCE_QUERY
			case <-time.After(debounceDuration):
				state = QUERY
			}
		case QUERY:
			// Query for which files to watch.
			fmt.Printf("Querying for BUILD files...\n")
			watchFiles(fmt.Sprintf(buildQuery, target), buildFileWatcher)
			fmt.Printf("Querying for source files...\n")
			watchFiles(fmt.Sprintf(sourceQuery, target), sourceFileWatcher)
			state = RUN
		case DEBOUNCE_RUN:
			select {
			case <-sourceFileWatcher.Events:
				state = DEBOUNCE_RUN
			case <-time.After(debounceDuration):
				state = RUN
			}
		case RUN:
			state = WAIT
			commandToRun(target)
		}
	}
}

func queryForSourceFiles(query string) []string {
	b := bazel.New()
	b.WriteToStderr(false)
	b.WriteToStdout(false)

	res, err := b.Query(query)
	if err != nil {
		fmt.Printf("Error running Bazel %s\n", err)
	}

	toWatch := make([]string, 0, 10000)
	for _, line := range res {
		if strings.HasPrefix(line, "@") {
			continue
		}
		if strings.HasPrefix(line, "//external") {
			continue
		}

		// For files that are served from the root they will being with "//:". This
		// is a problematic string because, for example, "//:demo.sh" will become
		// "/demo.sh" which is in the root of the filesystem and is unlikely to exist.
		if strings.HasPrefix(line, "//:") {
			line = line[3:]
		}

		toWatch = append(toWatch, strings.Replace(strings.TrimPrefix(line, "//"), ":", "/", 1))
	}

	return toWatch
}

func watchFiles(query string, watcher *fsnotify.Watcher) {
	toWatch := queryForSourceFiles(query)

	// TODO: Figure out how to unwatch files that are no longer included

	for _, line := range toWatch {
		fmt.Printf("Watching: %s\n", line)
		err := watcher.Add(line)
		if err != nil {
			fmt.Printf("Error watching file %v\nError: %v\n", line, err)
			continue
		}
	}
}

func build(target string) {
	b := bazel.New()

	b.Cancel()
	b.WriteToStderr(true)
	b.WriteToStdout(true)
	err := b.Build(target)
	if err != nil {
		fmt.Printf("Build error: %v", err)
		return
	}
}

func test(target string) {
	b := bazel.New()

	b.Cancel()
	b.WriteToStderr(true)
	b.WriteToStdout(true)
	err := b.Test(target)
	if err != nil {
		fmt.Printf("Build error: %v", err)
		return
	}
}

func run(target string) {
	b := bazel.New()

	b.Cancel()
	b.WriteToStderr(true)
	b.WriteToStdout(true)

	// Start run in a goroutine so that it doesn't block watching for files that
	// have changed.
	go b.Run(target)
}
<|endoftext|>