<commit_before>package rtnetlink

import (
	"net"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/jsimonetti/rtnetlink/internal/unix"
)

// Tests will only pass on little endian machines

func TestRouteMessageMarshalBinary(t *testing.T) {
	skipBigEndian(t)

	timeout := uint32(255)
	tests := []struct {
		name string
		m    Message
		b    []byte
		err  error
	}{
		{
			name: "empty",
			m:    &RouteMessage{},
			b: []byte{
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x00, 0x00, 0x00, 0x00,
			},
		},
		{
			name: "no attributes",
			m: &RouteMessage{
				Family:    unix.AF_INET,
				DstLength: 8,
				Type:      unix.RTN_UNICAST,
			},
			b: []byte{
				0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
				0x00, 0x00, 0x00, 0x00,
			},
		},
		{
			name: "attributes",
			m: &RouteMessage{
				Attributes: RouteAttributes{
					Dst:      net.ParseIP("10.0.0.0"),
					Gateway:  net.ParseIP("10.10.10.10"),
					OutIface: 4,
					Expires:  &timeout,
					Metrics: &RouteMetrics{
						MTU: 1500,
					},
				},
			},
			b: []byte{
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
				0x0a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00,
				0x0a, 0x0a, 0x0a, 0x0a, 0x08, 0x00, 0x04, 0x00,
				0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00,
				0xff, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x80,
				0x08, 0x00, 0x02, 0x00, 0xdc, 0x05, 0x00, 0x00,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b, err := tt.m.MarshalBinary()

			if want, got := tt.err, err; want != got {
				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
			}
			if err != nil {
				return
			}

			if diff := cmp.Diff(tt.b, b); diff != "" {
				t.Fatalf("unexpected RouteMessage bytes (-want +got):\n%s", diff)
			}
		})
	}
}

func TestRouteMessageUnmarshalBinary(t *testing.T) {
	skipBigEndian(t)

	timeout := uint32(1000)
	tests := []struct {
		name string
		b    []byte
		m    Message
		err  error
	}{
		{
			name: "empty",
			err:  errInvalidRouteMessage,
		},
		{
			name: "short",
			b:    make([]byte, 3),
			err:  errInvalidRouteMessage,
		},
		{
			name: "invalid attr",
			b: []byte{
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00,
				0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x08, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
			},
			err: errInvalidRouteMessageAttr,
		},
		{
			name: "data",
			b: []byte{
				0x02, 0x08, 0x00, 0x00, 0xfe, 0x04, 0x00, 0x01,
				0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
				0x0a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00,
				0x0a, 0x64, 0x0a, 0x01, 0x08, 0x00, 0x04, 0x00,
				0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00,
				0xe8, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x80,
				0x08, 0x00, 0x02, 0x00, 0xdc, 0x05, 0x00, 0x00,
			},
			m: &RouteMessage{
				Family:    2,
				DstLength: 8,
				Table:     unix.RT_TABLE_MAIN,
				Protocol:  unix.RTPROT_STATIC,
				Scope:     unix.RT_SCOPE_UNIVERSE,
				Type:      unix.RTN_UNICAST,
				Attributes: RouteAttributes{
					Dst:      net.IP{0x0a, 0x00, 0x00, 0x00},
					Src:      net.IP{0x0a, 0x64, 0x0a, 0x01},
					OutIface: 5,
					Expires:  &timeout,
					Metrics: &RouteMetrics{
						MTU: 1500,
					},
				},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			m := &RouteMessage{}
			err := (m).UnmarshalBinary(tt.b)

			if want, got := tt.err, err; want != got {
				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
			}
			if err != nil {
				return
			}

			if diff := cmp.Diff(tt.m, m); diff != "" {
				t.Fatalf("unexpected RouteMessage (-want +got):\n%s", diff)
			}
		})
	}
}
<commit_msg>rtnetlink: full test coverage for RouteMessage/Attributes parsing (#83)<commit_after>package rtnetlink

import (
	"net"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/jsimonetti/rtnetlink/internal/unix"
)

// Tests will only pass on little endian machines

func TestRouteMessageMarshalBinary(t *testing.T) {
	skipBigEndian(t)

	timeout := uint32(255)
	tests := []struct {
		name string
		m    Message
		b    []byte
		err  error
	}{
		{
			name: "empty",
			m:    &RouteMessage{},
			b: []byte{
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x00, 0x00, 0x00, 0x00,
			},
		},
		{
			name: "no attributes",
			m: &RouteMessage{
				Family:    unix.AF_INET,
				DstLength: 8,
				Type:      unix.RTN_UNICAST,
			},
			b: []byte{
				0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
				0x00, 0x00, 0x00, 0x00,
			},
		},
		{
			name: "attributes",
			m: &RouteMessage{
				Attributes: RouteAttributes{
					Dst:      net.ParseIP("10.0.0.0"),
					Gateway:  net.ParseIP("10.10.10.10"),
					OutIface: 4,
					Expires:  &timeout,
					Metrics: &RouteMetrics{
						MTU: 1500,
					},
				},
			},
			b: []byte{
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
				0x0a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00,
				0x0a, 0x0a, 0x0a, 0x0a, 0x08, 0x00, 0x04, 0x00,
				0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00,
				0xff, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x80,
				0x08, 0x00, 0x02, 0x00, 0xdc, 0x05, 0x00, 0x00,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b, err := tt.m.MarshalBinary()

			if want, got := tt.err, err; want != got {
				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
			}
			if err != nil {
				return
			}

			if diff := cmp.Diff(tt.b, b); diff != "" {
				t.Fatalf("unexpected RouteMessage bytes (-want +got):\n%s", diff)
			}
		})
	}
}

func TestRouteMessageUnmarshalBinary(t *testing.T) {
	skipBigEndian(t)

	timeout := uint32(1000)
	tests := []struct {
		name string
		b    []byte
		m    Message
		err  error
	}{
		{
			name: "empty",
			err:  errInvalidRouteMessage,
		},
		{
			name: "short",
			b:    make([]byte, 3),
			err:  errInvalidRouteMessage,
		},
		{
			name: "invalid attr",
			b: []byte{
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00,
				0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x08, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
			},
			err: errInvalidRouteMessageAttr,
		},
		{
			name: "full",
			b: []byte{
				// RouteMessage struct literal
				//
				// Family
				0x02,
				// DstLength
				0x08,
				// SrcLength
				0x00,
				// Tos
				0x00,
				// Table
				0xfe,
				// Protocol
				0x04,
				// Scope
				0x00,
				// Type
				0x01,
				// Flags
				0x00, 0x00, 0x00, 0x00,
				// RouteAttributes
				// 2 bytes length, 2 bytes type, N bytes value
				//
				// Dst
				0x08, 0x00, 0x01, 0x00,
				0x0a, 0x00, 0x00, 0x00,
				// Src
				0x08, 0x00, 0x07, 0x00,
				0x0a, 0x64, 0x0a, 0x01,
				// Gateway
				0x08, 0x00, 0x05, 0x00,
				0x0a, 0x00, 0x00, 0x01,
				// OutIface
				0x08, 0x00, 0x04, 0x00,
				0x05, 0x00, 0x00, 0x00,
				// Priority
				0x08, 0x00, 0x06, 0x00,
				0x01, 0x00, 0x00, 0x00,
				// Table
				0x08, 0x00, 0x0f, 0x00,
				0x02, 0x00, 0x00, 0x00,
				// Mark
				0x08, 0x00, 0x10, 0x00,
				0x03, 0x00, 0x00, 0x00,
				// Expires
				0x08, 0x00, 0x17, 0x00,
				0xe8, 0x03, 0x00, 0x00,
				// RouteMetrics
				// Length must be manually adjusted as more fields are added.
				0x24, 0x00, 0x08, 0x80,
				// AdvMSS
				0x08, 0x00, 0x08, 0x00,
				0x01, 0x00, 0x00, 0x00,
				// Features
				0x08, 0x00, 0x0c, 0x00,
				0xff, 0xff, 0xff, 0xff,
				// InitCwnd
				0x08, 0x00, 0x0b, 0x00,
				0x02, 0x00, 0x00, 0x00,
				// MTU
				0x08, 0x00, 0x02, 0x00,
				0xdc, 0x05, 0x00, 0x00,
			},
			m: &RouteMessage{
				Family:    2,
				DstLength: 8,
				Table:     unix.RT_TABLE_MAIN,
				Protocol:  unix.RTPROT_STATIC,
				Scope:     unix.RT_SCOPE_UNIVERSE,
				Type:      unix.RTN_UNICAST,
				Attributes: RouteAttributes{
					Dst:      net.IPv4(10, 0, 0, 0),
					Src:      net.IPv4(10, 100, 10, 1),
					Gateway:  net.IPv4(10, 0, 0, 1),
					OutIface: 5,
					Priority: 1,
					Table:    2,
					Mark:     3,
					Expires:  &timeout,
					Metrics: &RouteMetrics{
						AdvMSS:   1,
						Features: 0xffffffff,
						InitCwnd: 2,
						MTU:      1500,
					},
				},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			m := &RouteMessage{}
			err := (m).UnmarshalBinary(tt.b)

			if want, got := tt.err, err; want != got {
				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
			}
			if err != nil {
				return
			}

			if diff := cmp.Diff(tt.m, m); diff != "" {
				t.Fatalf("unexpected RouteMessage (-want +got):\n%s", diff)
			}
		})
	}
}
<|endoftext|>


<commit_before>// Package trigram is a dumb trigram index
package trigram

import (
	"sort"
)

// T is a trigram
type T uint32

func (t T) String() string {
	b := [3]byte{byte(t >> 16), byte(t >> 8), byte(t)}
	return string(b[:])
}

// DocID is a document ID
type DocID uint32

// Index is a trigram index
type Index map[T][]DocID

// a special (and invalid) trigram that holds all the document IDs
const tAllDocIDs T = 0xFFFFFFFF

// Extract returns a list of trigrams in s
func Extract(s string, trigrams []T) []T {

	for i := 0; i <= len(s)-3; i++ {
		t := T(uint32(s[i])<<16 | uint32(s[i+1])<<8 | uint32(s[i+2]))
		trigrams = appendIfUnique(trigrams, t)
	}

	return trigrams
}

func appendIfUnique(t []T, n T) []T {
	for _, v := range t {
		if v == n {
			return t
		}
	}

	return append(t, n)
}

// NewIndex returns an index for the strings in docs
func NewIndex(docs []string) Index {

	idx := make(Index)

	var allDocIDs []DocID

	var trigrams []T

	for id, d := range docs {
		ts := Extract(d, trigrams)
		docid := DocID(id)
		allDocIDs = append(allDocIDs, docid)
		for _, t := range ts {
			idx[t] = append(idx[t], docid)
		}
		trigrams = trigrams[:0]
	}

	idx[tAllDocIDs] = allDocIDs

	return idx
}

// Add adds a new string to the search index
func (idx Index) Add(s string) DocID {

	id := DocID(len(idx[tAllDocIDs]))

	ts := Extract(s, nil)
	for _, t := range ts {
		idx[t] = append(idx[t], id)
	}

	idx[tAllDocIDs] = append(idx[tAllDocIDs], id)

	return id
}

// for sorting
type docList []DocID

func (d docList) Len() int           { return len(d) }
func (d docList) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
func (d docList) Less(i, j int) bool { return d[i] < d[j] }

// Sort ensures all the document IDs are in order.
func (idx Index) Sort() {
	for _, v := range idx {
		dl := docList(v)
		if !sort.IsSorted(dl) {
			sort.Sort(dl)
		}
	}
}

// Query returns a list of document IDs that match the trigrams in the query s
func (idx Index) Query(s string) []DocID {
	ts := Extract(s, nil)
	return idx.QueryTrigrams(ts)
}

type tfList struct {
	tri  []T
	freq []int
}

func (tf tfList) Len() int { return len(tf.tri) }
func (tf tfList) Swap(i, j int) {
	tf.tri[i], tf.tri[j] = tf.tri[j], tf.tri[i]
	tf.freq[i], tf.freq[j] = tf.freq[j], tf.freq[i]
}
func (tf tfList) Less(i, j int) bool { return tf.freq[i] < tf.freq[j] }

// QueryTrigrams returns a list of document IDs that match the trigram set ts
func (idx Index) QueryTrigrams(ts []T) []DocID {

	if len(ts) == 0 {
		return idx[tAllDocIDs]
	}

	var freq []int

	for _, t := range ts {
		ln := len(idx[t])
		if ln == 0 {
			return nil
		}
		freq = append(freq, ln)
	}

	sort.Sort(tfList{ts, freq})

	ids := idx.Filter(idx[ts[0]], ts[1:])

	return ids
}

// Filter removes documents that don't contain the specified trigrams
func (idx Index) Filter(docs []DocID, ts []T) []DocID {
	for _, t := range ts {
		docs = intersect(docs, idx[t])
	}

	return docs
}

func intersect(a, b []DocID) []DocID {

	// TODO(dgryski): reduce allocations by reusing A

	var aidx, bidx int

	var result []DocID

scan:
	for aidx < len(a) && bidx < len(b) {
		if a[aidx] == b[bidx] {
			result = append(result, a[aidx])
			aidx++
			bidx++
			if aidx >= len(a) || bidx >= len(b) {
				break scan
			}
		}

		for a[aidx] < b[bidx] {
			aidx++
			if aidx >= len(a) {
				break scan
			}
		}

		for bidx < len(b) && a[aidx] > b[bidx] {
			bidx++
			if bidx >= len(b) {
				break scan
			}
		}
	}

	return result
}
<commit_msg>Remove O(n^2) loop from trigram indexing<commit_after>// Package trigram is a dumb trigram index
package trigram

import (
	"sort"
)

// T is a trigram
type T uint32

func (t T) String() string {
	b := [3]byte{byte(t >> 16), byte(t >> 8), byte(t)}
	return string(b[:])
}

// DocID is a document ID
type DocID uint32

// Index is a trigram index
type Index map[T][]DocID

// a special (and invalid) trigram that holds all the document IDs
const tAllDocIDs T = 0xFFFFFFFF

// Extract returns a list of all the unique trigrams in s
func Extract(s string, trigrams []T) []T {

	for i := 0; i <= len(s)-3; i++ {
		t := T(uint32(s[i])<<16 | uint32(s[i+1])<<8 | uint32(s[i+2]))
		trigrams = appendIfUnique(trigrams, t)
	}

	return trigrams
}

// ExtractAll returns a list of all the trigrams in s
func ExtractAll(s string, trigrams []T) []T {

	for i := 0; i <= len(s)-3; i++ {
		t := T(uint32(s[i])<<16 | uint32(s[i+1])<<8 | uint32(s[i+2]))
		trigrams = append(trigrams, t)
	}

	return trigrams
}

func appendIfUnique(t []T, n T) []T {
	for _, v := range t {
		if v == n {
			return t
		}
	}

	return append(t, n)
}

// NewIndex returns an index for the strings in docs
func NewIndex(docs []string) Index {

	idx := make(Index)

	var allDocIDs []DocID

	var trigrams []T

	for id, d := range docs {
		ts := ExtractAll(d, trigrams)
		docid := DocID(id)
		allDocIDs = append(allDocIDs, docid)
		for _, t := range ts {
			idxt := idx[t]
			l := len(idxt)
			if l == 0 || idxt[l-1] != docid {
				idx[t] = append(idxt, docid)
			}
		}
		trigrams = trigrams[:0]
	}

	idx[tAllDocIDs] = allDocIDs

	return idx
}

// Add adds a new string to the search index
func (idx Index) Add(s string) DocID {
	id := DocID(len(idx[tAllDocIDs]))

	ts := ExtractAll(s, nil)
	for _, t := range ts {
		idxt := idx[t]
		l := len(idxt)
		if l == 0 || idxt[l-1] != id {
			idx[t] = append(idxt, id)
		}
	}

	idx[tAllDocIDs] = append(idx[tAllDocIDs], id)

	return id
}

// for sorting
type docList []DocID

func (d docList) Len() int           { return len(d) }
func (d docList) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
func (d docList) Less(i, j int) bool { return d[i] < d[j] }

// Sort ensures all the document IDs are in order.
func (idx Index) Sort() {
	for _, v := range idx {
		dl := docList(v)
		if !sort.IsSorted(dl) {
			sort.Sort(dl)
		}
	}
}

// Query returns a list of document IDs that match the trigrams in the query s
func (idx Index) Query(s string) []DocID {
	ts := Extract(s, nil)
	return idx.QueryTrigrams(ts)
}

type tfList struct {
	tri  []T
	freq []int
}

func (tf tfList) Len() int { return len(tf.tri) }
func (tf tfList) Swap(i, j int) {
	tf.tri[i], tf.tri[j] = tf.tri[j], tf.tri[i]
	tf.freq[i], tf.freq[j] = tf.freq[j], tf.freq[i]
}
func (tf tfList) Less(i, j int) bool { return tf.freq[i] < tf.freq[j] }

// QueryTrigrams returns a list of document IDs that match the trigram set ts
func (idx Index) QueryTrigrams(ts []T) []DocID {

	if len(ts) == 0 {
		return idx[tAllDocIDs]
	}

	var freq []int

	for _, t := range ts {
		ln := len(idx[t])
		if ln == 0 {
			return nil
		}
		freq = append(freq, ln)
	}

	sort.Sort(tfList{ts, freq})

	ids := idx.Filter(idx[ts[0]], ts[1:])

	return ids
}

// Filter removes documents that don't contain the specified trigrams
func (idx Index) Filter(docs []DocID, ts []T) []DocID {
	for _, t := range ts {
		docs = intersect(docs, idx[t])
	}

	return docs
}

func intersect(a, b []DocID) []DocID {

	// TODO(dgryski): reduce allocations by reusing A

	var aidx, bidx int

	var result []DocID

scan:
	for aidx < len(a) && bidx < len(b) {
		if a[aidx] == b[bidx] {
			result = append(result, a[aidx])
			aidx++
			bidx++
			if aidx >= len(a) || bidx >= len(b) {
				break scan
			}
		}

		for a[aidx] < b[bidx] {
			aidx++
			if aidx >= len(a) {
				break scan
			}
		}

		for bidx < len(b) && a[aidx] > b[bidx] {
			bidx++
			if bidx >= len(b) {
				break scan
			}
		}
	}

	return result
}
<|endoftext|>


<commit_before>// Package xsrf is a container for the gorilla csrf package
package xsrf

import (
	"net/http"

	"github.com/gorilla/csrf"
	"github.com/stowelly/core/view"
)

// Info holds the config.
type Info struct {
	AuthKey string
	Secure  bool
}

// Token sets token in the template to the CSRF token.
func Token(w http.ResponseWriter, r *http.Request, v *view.Info) {
	w.Header().Set("X-CSRF-Token", csrf.Token(r))
}
<commit_msg>csrf token stuff<commit_after>// Package xsrf is a container for the gorilla csrf package
package xsrf

import (
	"net/http"

	"github.com/gorilla/csrf"
	"github.com/stowelly/core/view"
)

// Info holds the config.
type Info struct {
	AuthKey string
	Secure  bool
}

// Token sets token in the template to the CSRF token.
func Token(w http.ResponseWriter, r *http.Request, v *view.Info) {
	w.Header().Set("X-CSRF-Token", csrf.Token(r))
	v.Vars["token"] = csrf.Token(r)
}
<|endoftext|>


<commit_before>package db

import (
	"database/sql/driver"
	"time"
)

// ISO8601 is a time.Time layout for the ISO8601 format
const ISO8601 = "2006-01-02T15:04:05-0700"

// Time represents a time.Time that uses ISO8601 for json input/output
// instead of RFC3339
type Time struct {
	time.Time
}

// Now returns the current local time.
func Now() *Time {
	return &Time{Time: time.Now()}
}

// Value - Implementation of valuer for database/sql
func (t *Time) Value() (driver.Value, error) {
	if t == nil {
		return nil, nil
	}

	return t.Format(ISO8601), nil
}

// Scan - Implement the database/sql scanner interface
func (t *Time) Scan(value interface{}) error {
	if value != nil {
		t.Time = value.(time.Time)
	}
	return nil
}

// MarshalJSON implements the json.Marshaler interface
func (t Time) MarshalJSON() ([]byte, error) {
	return []byte(`"` + t.Format(ISO8601) + `"`), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface
func (t *Time) UnmarshalJSON(data []byte) (err error) {
	t.Time, err = time.Parse(`"`+ISO8601+`"`, string(data))
	return
}

// Equal check if the given date is equal to the current one
func (t *Time) Equal(u Time) bool {
	return t.Time.Equal(u.Time)
}
<commit_msg>Fix(db.Time): Fix Time.Equal() params<commit_after>package db

import (
	"database/sql/driver"
	"time"
)

// ISO8601 is a time.Time layout for the ISO8601 format
const ISO8601 = "2006-01-02T15:04:05-0700"

// Time represents a time.Time that uses ISO8601 for json input/output
// instead of RFC3339
type Time struct {
	time.Time
}

// Now returns the current local time.
func Now() *Time {
	return &Time{Time: time.Now()}
}

// Value - Implementation of valuer for database/sql
func (t *Time) Value() (driver.Value, error) {
	if t == nil {
		return nil, nil
	}

	return t.Format(ISO8601), nil
}

// Scan - Implement the database/sql scanner interface
func (t *Time) Scan(value interface{}) error {
	if value != nil {
		t.Time = value.(time.Time)
	}
	return nil
}

// MarshalJSON implements the json.Marshaler interface
func (t Time) MarshalJSON() ([]byte, error) {
	return []byte(`"` + t.Format(ISO8601) + `"`), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface
func (t *Time) UnmarshalJSON(data []byte) (err error) {
	t.Time, err = time.Parse(`"`+ISO8601+`"`, string(data))
	return
}

// Equal check if the given date is equal to the current one
func (t *Time) Equal(u *Time) bool {
	return t.Time.Equal(u.Time)
}
<|endoftext|>


<commit_before>package store

import (
	"github.com/danjac/podbaby/store/Godeps/_workspace/src/github.com/jmoiron/sqlx"
)

// BookmarkWriter handles all writes to bookmark data store
type BookmarkWriter interface {
	Create(DataHandler, int, int) error
	Delete(DataHandler, int, int) error
}

// BookmarkReader handles all reads from bookmark data store
type BookmarkReader interface {
	SelectByUserID(DataHandler, *[]int, int) error
}

// BookmarkStore handles manages interactions with bookmark data store
type BookmarkStore interface {
	BookmarkReader
	BookmarkWriter
}

type bookmarkSQLStore struct {
	BookmarkReader
	BookmarkWriter
}

func newBookmarkStore() BookmarkStore {
	return &bookmarkSQLStore{
		BookmarkReader: &bookmarkSQLReader{},
		BookmarkWriter: &bookmarkSQLWriter{},
	}
}

type bookmarkSQLReader struct{}

func (r *bookmarkSQLReader) SelectByUserID(dh DataHandler, result *[]int, userID int) error {
	q := "SELECT DISTINCT podcast_id FROM bookmarks WHERE user_id=$1 ORDER BY podcast_id DESC"
	return handleError(sqlx.Select(dh, result, q, userID), q)
}

type bookmarkSQLWriter struct{}

func (db *bookmarkSQLWriter) Create(dh DataHandler, podcastID, userID int) error {
	q := "INSERT INTO bookmarks(podcast_id, user_id) VALUES($1, $2)"
	_, err := dh.Exec(q, podcastID, userID)
	return handleError(err, q)
}

func (db *bookmarkSQLWriter) Delete(dh DataHandler, podcastID, userID int) error {
	q := "DELETE FROM bookmarks WHERE podcast_id=$1 AND user_id=$2"
	_, err := dh.Exec(q, podcastID, userID)
	return handleError(err, q)
}
<commit_msg>Fix bookmarks ordering<commit_after>package store

import (
	"github.com/danjac/podbaby/store/Godeps/_workspace/src/github.com/jmoiron/sqlx"
)

// BookmarkWriter handles all writes to bookmark data store
type BookmarkWriter interface {
	Create(DataHandler, int, int) error
	Delete(DataHandler, int, int) error
}

// BookmarkReader handles all reads from bookmark data store
type BookmarkReader interface {
	SelectByUserID(DataHandler, *[]int, int) error
}

// BookmarkStore handles manages interactions with bookmark data store
type BookmarkStore interface {
	BookmarkReader
	BookmarkWriter
}

type bookmarkSQLStore struct {
	BookmarkReader
	BookmarkWriter
}

func newBookmarkStore() BookmarkStore {
	return &bookmarkSQLStore{
		BookmarkReader: &bookmarkSQLReader{},
		BookmarkWriter: &bookmarkSQLWriter{},
	}
}

type bookmarkSQLReader struct{}

func (r *bookmarkSQLReader) SelectByUserID(dh DataHandler, result *[]int, userID int) error {
	q := "SELECT podcast_id FROM bookmarks WHERE user_id=$1 ORDER BY id DESC"
	return handleError(sqlx.Select(dh, result, q, userID), q)
}

type bookmarkSQLWriter struct{}

func (db *bookmarkSQLWriter) Create(dh DataHandler, podcastID, userID int) error {
	q := "INSERT INTO bookmarks(podcast_id, user_id) VALUES($1, $2)"
	_, err := dh.Exec(q, podcastID, userID)
	return handleError(err, q)
}

func (db *bookmarkSQLWriter) Delete(dh DataHandler, podcastID, userID int) error {
	q := "DELETE FROM bookmarks WHERE podcast_id=$1 AND user_id=$2"
	_, err := dh.Exec(q, podcastID, userID)
	return handleError(err, q)
}
<|endoftext|>


<commit_before>package ast

import (
	"fmt"
	"log"
	"math"
	"regexp"
	"strings"

	"github.com/wellington/sass/token"
)

var (
	regEql = regexp.MustCompile("\\s*(\\*?=)\\s*").ReplaceAll
	regBkt = regexp.MustCompile("\\s*(\\[)\\s*(\\S+)\\s*(\\])").ReplaceAll
)

// Resolves walks selector operations removing nested Op by prepending X
// on Y.
func (stmt *SelStmt) Resolve(fset *token.FileSet) {
	if stmt.Sel == nil {
		panic(fmt.Errorf("invalid selector: % #v\n", stmt))
	}
	s := &sel{
		parent: stmt.Parent,
		stmt:   stmt,
		prec:   token.LowestPrec + 1,
		parts:  make(map[token.Pos]*BasicLit),
	}
	fmt.Println("Selector Resolve")
	Print(fset, s.stmt.Sel)
	// This could be more efficient, it should inspect precision of
	// the top node
	for prec := token.UnaryPrec; prec > 1; prec-- {
		// Walk the selectors resolving ops found at the active
		// precision
		if s.parent != nil {
			s.inject = true
		}
		s.prec = prec
		Walk(s, s.stmt.Sel)
	}

	// stmt.Resolved = stmt.Sel.(*BasicLit)
	var vals []string
	for i, part := range s.parts {
		fmt.Printf("%d: % #v\n", i, part)
		vals = append(vals, part.Value)
	}
	val := strings.Join(vals, " ")
	stmt.Resolved = &BasicLit{Value: val}
	fmt.Println("Resolver Output", val)
}

type sel struct {
	stmt   *SelStmt
	parent *SelStmt
	parts  map[token.Pos]*BasicLit
	prec   int    // Resolve each precendence in order
	stack  []Expr // Nesting stack
	inject bool   // inject parent to start
}

func (s *sel) add(pos token.Pos, lit *BasicLit) {
	s.parts[pos] = lit
	// FIXME: walk through all available positions and remove
	// any higher than pos. This indicates a reduce happened
	// and something was reported prematurely
	for i := range s.parts {
		if i > pos {
			delete(s.parts, i)
		}
	}
}

var amper = "&"

func ghettoResolvedParentInject(delim string, pval string, nodes ...string) string {
	fmt.Printf(`=ghetto=============================
     op: %q
 parent: %q
 childs: %q
====================================
`,
		delim, pval, nodes,
	)
	if len(nodes) > 3 {
		panic("too many")
	}
	gdelim := ", "
	if len(pval) > 0 {
		sdelim := ", "
		parts := strings.Split(pval, sdelim)
		ret := make([]string, 0, len(parts)*len(nodes))
		for i := range parts {
			for j := range nodes {
				// if no &, prepend to start
				var s string
				if strings.Contains(nodes[j], amper) {
					// ret = append(ret, parts[i]+delim+nodes[j])

					s = strings.Replace(nodes[j], "&", parts[i], -1)
				} else {
					s = parts[i] + delim + nodes[j]
				}
				ret = append(ret, s)
			}
		}
		fmt.Printf(`=ghetto return======================
 %q
====================================
`, ret)
		return strings.Join(ret, gdelim)
	}
	return strings.Join(nodes, gdelim)
}

// FIXME: have no way to merge trees right now, so ghetto style
func ghettoParentInject(delim string, parent *SelStmt, nodes ...string) string {
	var pval string
	if parent != nil {
		pval = parent.Resolved.Value
	}
	return ghettoResolvedParentInject(delim, pval, nodes...)
}

func (s *sel) Visit(node Node) Visitor {
	// fmt.Printf("Visit %T: % #v\n", node, node)
	var pos token.Pos
	var add *BasicLit
	delim := " "
	defer func() {
		if add == nil {
			return
		}
		if add.Kind == token.ILLEGAL {
			log.Println("Warning invalid Kind for", add)
		}
		// Do not add Lits with invalid positions
		if pos >= 0 {
			s.add(pos, add)
			fmt.Printf("adding %s at %d: % #v\n", add.Kind, pos, add)
		}
	}()

	switch v := node.(type) {
	case *UnaryExpr:
		// UnaryExpr come in two flavors & (backref) and + ~ > (operators).
		// In any case, it must be nested selector or it is an error.
		if s.parent == nil {
			// TODO: pass through parser's exception logic
			log.Fatal("unary operator must be a nested selector",
				node.Pos())
		}
		if v.Visited {
			return nil
		}
		if s.prec < 5 {
			panic(fmt.Errorf("invalid nest token: %s prec: %d", v.Op, s.prec))
		}
		if s.prec != 5 {
			return nil
		}

		v.Visited = true

		plit := ExprCopy(s.parent.Resolved).(*BasicLit)
		plit.Kind = token.STRING
		plit.ValuePos = -1
		pos = v.OpPos
		switch v.Op {
		case token.NEST:
			add = s.switchExpr(v)
		case token.GTR, token.TIL, token.ADD:
			fmt.Println("unary binary add!")
			add = s.switchExpr(v)
		default:
			log.Fatal("invalid unary operation: ", v.Op)
		}
		return nil
	case *BasicLit:
		if v.Kind == token.ILLEGAL {
			return nil
		}
		if s.prec != 2 {
			return nil
		}

		if s.inject && s.parent != nil {
			v.Value = ghettoParentInject(delim, s.parent, v.Value)
		}
		add = v
		return nil
	case *BinaryExpr:
		pos = v.Pos()
		switch v.Op {
		case token.ADD, token.GTR, token.TIL:
			if s.prec < 4 {
				return nil
				panic(fmt.Errorf("invalid Op token: %s prec: %d", v.Op, s.prec))
			}
			if s.prec != 4 {
				return s
			}
			add = s.joinBinary(v)
		case token.COMMA:
			if s.prec < 3 {
				return nil
				panic(fmt.Errorf("invalid group token: %s prec: %d", v.Op, s.prec))
			}
			if s.prec != 3 {
				return nil
			}

			litX := s.switchExpr(v.X)
			litY := s.switchExpr(v.Y)
			// Now to piece together both operations
			// xs := strings.Split(litX.Value, ","+delim)
			// ys := strings.Split(litY.Value, ","+delim)
			lits := append(
				strings.Split(litX.Value, ","+delim),
				strings.Split(litY.Value, ","+delim)...)
			_ = lits
			// sx := ghettoParentInject(delim, s.parent, lits...) //litX.Value, litY.Value)
			// sx := litX.Value + ", " + litY.Value

			sx := mergeLits(","+delim, litX.Value, litY.Value)
			add = &BasicLit{
				Kind:     token.STRING,
				ValuePos: pos,
				Value:    sx,
			}
			return nil
		}

		// v.Op = token.ILLEGAL
		return nil
	}

	return s
}

// after parent multiplication, lits are out of order. Fix the ordering
// Examples of out of orderness
// [1 3] [2] => [1 2 3]
// [1 3] [2 4] => [1 2 3 4]
func mergeLits(delim, left, right string) string {
	lefts, rights := strings.Split(left, delim), strings.Split(right, delim)
	ll, lr := len(lefts), len(rights)
	fmt.Printf("reordering %d %d\nleft: %q\nrigh: %q\n",
		ll, lr, lefts, rights)

	if math.Remainder(float64(ll), float64(lr)) > 0 {
		panic(fmt.Errorf("Incompatible lengths left:%d right:%d", ll, lr))
	}
	var ss []string
	mod := ll / lr
	for i := range lefts {
		ss = append(ss, lefts[i])
		if (i+1)%mod == 0 {
			ss = append(ss, rights[i/mod])
		}
	}
	fmt.Printf("%q\n", ss)
	r := strings.Join(ss, delim)
	fmt.Println("mergeLits returns", r)
	return r
}

func parseBackRef(delim string, parent *BasicLit, in *BasicLit) *BasicLit {
	fmt.Printf("parseBackRef % #v\n", in)
	if in.Value == "&" {
		return ExprCopy(parent).(*BasicLit)
	}
	pval := parent.Value
	ret := ghettoResolvedParentInject(delim, pval, in.Value)
	return &BasicLit{
		Kind:     token.STRING,
		Value:    ret,
		ValuePos: in.Pos(),
	}
}

func (s *sel) switchExpr(expr Expr) *BasicLit {
	fmt.Printf("switchExpr %T: % #v\n", expr, expr)
	delim := " "
	switch v := expr.(type) {
	case *BasicLit:
		copy := ExprCopy(expr).(*BasicLit)
		copy.ValuePos = v.ValuePos
		copy.Value = ghettoParentInject(" ", s.parent, v.Value)
		return copy
	case *UnaryExpr:
		plit := parseBackRef(delim+v.Op.String()+delim, s.parent.Resolved, v.X.(*BasicLit))
		fmt.Printf("switchExpr exit % #v\n", plit)
		return plit
	case *BinaryExpr:
		fmt.Printf("switching bin\n  X:% #v\n  Y:% #v\n", v.X, v.Y)
		return s.joinBinary(v)
	default:
		panic(fmt.Errorf("switch expr: % #v\n", v))
	}
}

func (s *sel) joinBinary(bin *BinaryExpr) *BasicLit {
	fmt.Println("joinBinary")
	var x, y *BasicLit
	// If either are Unary, must use ghetto math to multiply them
	_, unx := bin.X.(*UnaryExpr)
	_, uny := bin.Y.(*UnaryExpr)
	_, _ = unx, uny
	delim := " " // This will change with compiler mode
	switch bin.Op {
	case token.COMMA:
		delim = "," + delim
	default:
		delim = delim + bin.Op.String() + delim
	}

	x = s.switchExpr(bin.X)
	y = s.switchExpr(bin.Y)
	fmt.Printf("joining with (%q)\n  X: % #v\n  Y: % #v\n", delim, x, y)
	var val string
	if unx && uny {
		fmt.Println("join unx&uny\nleft:", x.Value, "\nright:", y.Value)
		val = ghettoResolvedParentInject(delim, x.Value, y.Value)
	} else if unx {
		fmt.Println("join unx")
		// This is actually a unary operation, treat as so
		un := &UnaryExpr{}
		un.Op = bin.Op
		un.OpPos = bin.OpPos
		un.X = bin.Y
		fmt.Printf("unary switch (%q): % #v", bin.Op, bin.Y)
		return s.switchExpr(un)
		// This won't actually work, but hey have fun kid
		val = ghettoResolvedParentInject(delim, y.Value, x.Value)
	} else if bin.Op == token.COMMA {
		val = mergeLits(delim, x.Value, y.Value)
	} else {
		fmt.Println("join other")
		vals := []string{x.Value, y.Value}
		val = strings.Join(vals, delim)
	}

	lit := &BasicLit{
		ValuePos: bin.Pos(),
		Value:    val,
		Kind:     token.STRING,
	}
	fmt.Printf("binJoined: %s\n", val)
	return lit
}
<commit_msg>minor cleanup<commit_after>package ast

import (
	"fmt"
	"log"
	"math"
	"regexp"
	"strings"

	"github.com/wellington/sass/token"
)

var (
	regEql = regexp.MustCompile("\\s*(\\*?=)\\s*").ReplaceAll
	regBkt = regexp.MustCompile("\\s*(\\[)\\s*(\\S+)\\s*(\\])").ReplaceAll
)

// Resolves walks selector operations removing nested Op by prepending X
// on Y.
func (stmt *SelStmt) Resolve(fset *token.FileSet) {
	if stmt.Sel == nil {
		panic(fmt.Errorf("invalid selector: % #v\n", stmt))
	}
	s := &sel{
		parent: stmt.Parent,
		stmt:   stmt,
		prec:   token.LowestPrec + 1,
		parts:  make(map[token.Pos]*BasicLit),
	}
	fmt.Println("Selector Resolve")
	Print(fset, s.stmt.Sel)
	// This could be more efficient, it should inspect precision of
	// the top node
	for prec := token.UnaryPrec; prec > 1; prec-- {
		// Walk the selectors resolving ops found at the active
		// precision
		if s.parent != nil {
			s.inject = true
		}
		s.prec = prec
		Walk(s, s.stmt.Sel)
	}

	// stmt.Resolved = stmt.Sel.(*BasicLit)
	var vals []string
	for i, part := range s.parts {
		fmt.Printf("%d: % #v\n", i, part)
		vals = append(vals, part.Value)
	}
	val := strings.Join(vals, " ")
	stmt.Resolved = &BasicLit{Value: val}
	fmt.Println("Resolver Output", val)
}

type sel struct {
	stmt   *SelStmt
	parent *SelStmt
	parts  map[token.Pos]*BasicLit
	prec   int    // Resolve each precendence in order
	stack  []Expr // Nesting stack
	inject bool   // inject parent to start
}

func (s *sel) add(pos token.Pos, lit *BasicLit) {
	s.parts[pos] = lit
	// FIXME: walk through all available positions and remove
	// any higher than pos. This indicates a reduce happened
	// and something was reported prematurely
	for i := range s.parts {
		if i > pos {
			delete(s.parts, i)
		}
	}
}

var amper = "&"

func ghettoResolvedParentInject(delim string, pval string, nodes ...string) string {
	fmt.Printf(`=ghetto=============================
     op: %q
 parent: %q
 childs: %q
====================================
`,
		delim, pval, nodes,
	)
	gdelim := ", "

	if len(pval) == 0 {
		return strings.Join(nodes, gdelim)
	}

	sdelim := ", "
	parts := strings.Split(pval, sdelim)
	ret := make([]string, 0, len(parts)*len(nodes))
	var s string
	for i := range parts {
		for j := range nodes {
			// When no & is present, & is implicit ie. `& parts[i]`
			if strings.Contains(nodes[j], amper) {
				s = strings.Replace(nodes[j], "&", parts[i], -1)
			} else {
				s = parts[i] + delim + nodes[j]
			}
			ret = append(ret, s)
		}
	}
	fmt.Printf(`=ghetto return======================
 %q
====================================
`, ret)
	return strings.Join(ret, gdelim)
}

// FIXME: have no way to merge trees right now, so ghetto style
func ghettoParentInject(delim string, parent *SelStmt, nodes ...string) string {
	var pval string
	if parent != nil {
		pval = parent.Resolved.Value
	}
	return ghettoResolvedParentInject(delim, pval, nodes...)
}

func (s *sel) Visit(node Node) Visitor {
	// fmt.Printf("Visit %T: % #v\n", node, node)
	var pos token.Pos
	var add *BasicLit
	delim := " "
	defer func() {
		if add == nil {
			return
		}
		if add.Kind == token.ILLEGAL {
			log.Println("Warning invalid Kind for", add)
		}
		// Do not add Lits with invalid positions
		if pos >= 0 {
			s.add(pos, add)
			fmt.Printf("adding %s at %d: % #v\n", add.Kind, pos, add)
		}
	}()

	switch v := node.(type) {
	case *UnaryExpr:
		// UnaryExpr come in two flavors & (backref) and + ~ > (operators).
		// In any case, it must be nested selector or it is an error.
		if s.parent == nil {
			// TODO: pass through parser's exception logic
			log.Fatal("unary operator must be a nested selector",
				node.Pos())
		}
		if v.Visited {
			return nil
		}
		if s.prec < 5 {
			panic(fmt.Errorf("invalid nest token: %s prec: %d", v.Op, s.prec))
		}
		if s.prec != 5 {
			return nil
		}

		v.Visited = true

		plit := ExprCopy(s.parent.Resolved).(*BasicLit)
		plit.Kind = token.STRING
		plit.ValuePos = -1
		pos = v.OpPos
		switch v.Op {
		case token.NEST:
			add = s.switchExpr(v)
		case token.GTR, token.TIL, token.ADD:
			fmt.Println("unary binary add!")
			add = s.switchExpr(v)
		default:
			log.Fatal("invalid unary operation: ", v.Op)
		}
		return nil
	case *BasicLit:
		if v.Kind == token.ILLEGAL {
			return nil
		}
		if s.prec != 2 {
			return nil
		}

		if s.inject && s.parent != nil {
			v.Value = ghettoParentInject(delim, s.parent, v.Value)
		}
		add = v
		return nil
	case *BinaryExpr:
		pos = v.Pos()
		switch v.Op {
		case token.ADD, token.GTR, token.TIL:
			if s.prec < 4 {
				return nil
				panic(fmt.Errorf("invalid Op token: %s prec: %d", v.Op, s.prec))
			}
			if s.prec != 4 {
				return s
			}
			add = s.joinBinary(v)
		case token.COMMA:
			if s.prec < 3 {
				return nil
				panic(fmt.Errorf("invalid group token: %s prec: %d", v.Op, s.prec))
			}
			if s.prec != 3 {
				return nil
			}

			litX := s.switchExpr(v.X)
			litY := s.switchExpr(v.Y)
			sx := mergeLits(","+delim, litX.Value, litY.Value)
			add = &BasicLit{
				Kind:     token.STRING,
				ValuePos: pos,
				Value:    sx,
			}
		}
		return nil
	}

	return s
}

// after parent multiplication, lits are out of order. Fix the ordering
// Examples of out of orderness
// [1 3] [2] => [1 2 3]
// [1 3] [2 4] => [1 2 3 4]
func mergeLits(delim, left, right string) string {
	lefts, rights := strings.Split(left, delim), strings.Split(right, delim)
	ll, lr := len(lefts), len(rights)
	fmt.Printf("reordering %d %d\nleft: %q\nrigh: %q\n",
		ll, lr, lefts, rights)

	if math.Remainder(float64(ll), float64(lr)) > 0 {
		panic(fmt.Errorf("Incompatible lengths left:%d right:%d", ll, lr))
	}
	var ss []string
	mod := ll / lr
	for i := range lefts {
		ss = append(ss, lefts[i])
		if (i+1)%mod == 0 {
			ss = append(ss, rights[i/mod])
		}
	}
	fmt.Printf("%q\n", ss)
	r := strings.Join(ss, delim)
	fmt.Println("mergeLits returns", r)
	return r
}

func parseBackRef(delim string, parent *BasicLit, in *BasicLit) *BasicLit {
	fmt.Printf("parseBackRef % #v\n", in)
	if in.Value == "&" {
		return ExprCopy(parent).(*BasicLit)
	}
	pval := parent.Value
	ret := ghettoResolvedParentInject(delim, pval, in.Value)
	return &BasicLit{
		Kind:     token.STRING,
		Value:    ret,
		ValuePos: in.Pos(),
	}
}

func (s *sel) switchExpr(expr Expr) *BasicLit {
	fmt.Printf("switchExpr %T: % #v\n", expr, expr)
	delim := " "
	switch v := expr.(type) {
	case *BasicLit:
		copy := ExprCopy(expr).(*BasicLit)
		copy.ValuePos = v.ValuePos
		copy.Value = ghettoParentInject(" ", s.parent, v.Value)
		return copy
	case *UnaryExpr:
		plit := parseBackRef(delim+v.Op.String()+delim, s.parent.Resolved, v.X.(*BasicLit))
		fmt.Printf("switchExpr exit % #v\n", plit)
		return plit
	case *BinaryExpr:
		fmt.Printf("switching bin\n  X:% #v\n  Y:% #v\n", v.X, v.Y)
		return s.joinBinary(v)
	default:
		panic(fmt.Errorf("switch expr: % #v\n", v))
	}
}

func (s *sel) joinBinary(bin *BinaryExpr) *BasicLit {
	fmt.Println("joinBinary")
	var x, y *BasicLit
	// If either are Unary, must use ghetto math to multiply them
	_, unx := bin.X.(*UnaryExpr)
	_, uny := bin.Y.(*UnaryExpr)
	_, _ = unx, uny
	delim := " " // This will change with compiler mode
	switch bin.Op {
	case token.COMMA:
		delim = "," + delim
	default:
		delim = delim + bin.Op.String() + delim
	}

	x = s.switchExpr(bin.X)
	y = s.switchExpr(bin.Y)
	fmt.Printf("joining with (%q)\n  X: % #v\n  Y: % #v\n", delim, x, y)
	var val string
	if unx && uny {
		fmt.Println("join unx&uny\nleft:", x.Value, "\nright:", y.Value)
		val = ghettoResolvedParentInject(delim, x.Value, y.Value)
	} else if unx {
		fmt.Println("join unx")
		// This is actually a unary operation, treat as so
		un := &UnaryExpr{}
		un.Op = bin.Op
		un.OpPos = bin.OpPos
		un.X = bin.Y
		fmt.Printf("unary switch (%q): % #v", bin.Op, bin.Y)
		return s.switchExpr(un)
	} else if bin.Op == token.COMMA {
		val = mergeLits(delim, x.Value, y.Value)
	} else {
		fmt.Println("join other")
		vals := []string{x.Value, y.Value}
		val = strings.Join(vals, delim)
	}

	lit := &BasicLit{
		ValuePos: bin.Pos(),
		Value:    val,
		Kind:     token.STRING,
	}
	fmt.Printf("binJoined: %s\n", val)
	return lit
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package atom provides simple wrappers around numerics to enforce atomic
// access.
package atomic

import "sync/atomic"

// Int32 is an atomic wrapper around an int32.
type Int32 struct{ int32 }

// Load atomically loads the wrapped value.
func (i *Int32) Load() int32 {
	return atomic.LoadInt32(&i.int32)
}

// Add atomically adds to the wrapped int32 and returns the new value.
func (i *Int32) Add(n int32) int32 {
	return atomic.AddInt32(&i.int32, n)
}

// Inc atomically increments the wrapped int32 and returns the new value.
func (i *Int32) Inc() int32 {
	return i.Add(1)
}

// Dec atomically decrements the wrapped int32 and returns the new value.
func (i *Int32) Dec() int32 {
	return i.Add(-1)
}

// CAS is an atomic compare-and-swap.
func (i *Int32) CAS(old, new int32) bool {
	return atomic.CompareAndSwapInt32(&i.int32, old, new)
}

// Store atomically stores the passed value.
func (i *Int32) Store(n int32) {
	atomic.StoreInt32(&i.int32, n)
}

// Swap atomically swaps the wrapped int32 and returns the old value.
func (i *Int32) Swap(n int32) int32 {
	return atomic.SwapInt32(&i.int32, n)
}

// Int64 is an atomic wrapper around an int64.
type Int64 struct{ int64 }

// Load atomically loads the wrapped value.
func (i *Int64) Load() int64 {
	return atomic.LoadInt64(&i.int64)
}

// Add atomically adds to the wrapped int64 and returns the new value.
func (i *Int64) Add(n int64) int64 {
	return atomic.AddInt64(&i.int64, n)
}

// Inc atomically increments the wrapped int64 and returns the new value.
func (i *Int64) Inc() int64 {
	return i.Add(1)
}

// Dec atomically decrements the wrapped int64 and returns the new value.
func (i *Int64) Dec() int64 {
	return i.Add(-1)
}

// CAS is an atomic compare-and-swap.
func (i *Int64) CAS(old, new int64) bool {
	return atomic.CompareAndSwapInt64(&i.int64, old, new)
}

// Store atomically stores the passed value.
func (i *Int64) Store(n int64) {
	atomic.StoreInt64(&i.int64, n)
}

// Swap atomically swaps the wrapped int64 and returns the old value.
func (i *Int64) Swap(n int64) int64 {
	return atomic.SwapInt64(&i.int64, n)
}

// Uint32 is an atomic wrapper around an uint32.
type Uint32 struct{ uint32 }

// Load atomically loads the wrapped value.
func (i *Uint32) Load() uint32 {
	return atomic.LoadUint32(&i.uint32)
}

// Add atomically adds to the wrapped uint32 and returns the new value.
func (i *Uint32) Add(n uint32) uint32 {
	return atomic.AddUint32(&i.uint32, n)
}

// Inc atomically increments the wrapped uint32 and returns the new value.
func (i *Uint32) Inc() uint32 {
	return i.Add(1)
}

// Dec atomically decrements the wrapped int32 and returns the new value.
func (i *Uint32) Dec() uint32 {
	return i.Add(^uint32(0))
}

// CAS is an atomic compare-and-swap.
func (i *Uint32) CAS(old, new uint32) bool {
	return atomic.CompareAndSwapUint32(&i.uint32, old, new)
}

// Store atomically stores the passed value.
func (i *Uint32) Store(n uint32) {
	atomic.StoreUint32(&i.uint32, n)
}

// Swap atomically swaps the wrapped uint32 and returns the old value.
func (i *Uint32) Swap(n uint32) uint32 {
	return atomic.SwapUint32(&i.uint32, n)
}

// Uint64 is an atomic wrapper around a uint64.
type Uint64 struct{ uint64 }

// Load atomically loads the wrapped value.
func (i *Uint64) Load() uint64 {
	return atomic.LoadUint64(&i.uint64)
}

// Add atomically adds to the wrapped uint64 and returns the new value.
func (i *Uint64) Add(n uint64) uint64 {
	return atomic.AddUint64(&i.uint64, n)
}

// Inc atomically increments the wrapped uint64 and returns the new value.
func (i *Uint64) Inc() uint64 {
	return i.Add(1)
}

// Dec atomically decrements the wrapped uint64 and returns the new value.
func (i *Uint64) Dec() uint64 {
	return i.Add(^uint64(0))
}

// CAS is an atomic compare-and-swap.
func (i *Uint64) CAS(old, new uint64) bool {
	return atomic.CompareAndSwapUint64(&i.uint64, old, new)
}

// Store atomically stores the passed value.
func (i *Uint64) Store(n uint64) {
	atomic.StoreUint64(&i.uint64, n)
}

// Swap atomically swaps the wrapped uint64 and returns the old value.
func (i *Uint64) Swap(n uint64) uint64 {
	return atomic.SwapUint64(&i.uint64, n)
}
<commit_msg>Fix comment<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package atomic provides simple wrappers around numerics to enforce atomic
// access.
package atomic

import "sync/atomic"

// Int32 is an atomic wrapper around an int32.
type Int32 struct{ int32 }

// Load atomically loads the wrapped value.
func (i *Int32) Load() int32 {
	return atomic.LoadInt32(&i.int32)
}

// Add atomically adds to the wrapped int32 and returns the new value.
func (i *Int32) Add(n int32) int32 {
	return atomic.AddInt32(&i.int32, n)
}

// Inc atomically increments the wrapped int32 and returns the new value.
func (i *Int32) Inc() int32 {
	return i.Add(1)
}

// Dec atomically decrements the wrapped int32 and returns the new value.
func (i *Int32) Dec() int32 {
	return i.Add(-1)
}

// CAS is an atomic compare-and-swap.
func (i *Int32) CAS(old, new int32) bool {
	return atomic.CompareAndSwapInt32(&i.int32, old, new)
}

// Store atomically stores the passed value.
func (i *Int32) Store(n int32) {
	atomic.StoreInt32(&i.int32, n)
}

// Swap atomically swaps the wrapped int32 and returns the old value.
func (i *Int32) Swap(n int32) int32 {
	return atomic.SwapInt32(&i.int32, n)
}

// Int64 is an atomic wrapper around an int64.
type Int64 struct{ int64 }

// Load atomically loads the wrapped value.
func (i *Int64) Load() int64 {
	return atomic.LoadInt64(&i.int64)
}

// Add atomically adds to the wrapped int64 and returns the new value.
func (i *Int64) Add(n int64) int64 {
	return atomic.AddInt64(&i.int64, n)
}

// Inc atomically increments the wrapped int64 and returns the new value.
func (i *Int64) Inc() int64 {
	return i.Add(1)
}

// Dec atomically decrements the wrapped int64 and returns the new value.
func (i *Int64) Dec() int64 {
	return i.Add(-1)
}

// CAS is an atomic compare-and-swap.
func (i *Int64) CAS(old, new int64) bool {
	return atomic.CompareAndSwapInt64(&i.int64, old, new)
}

// Store atomically stores the passed value.
func (i *Int64) Store(n int64) {
	atomic.StoreInt64(&i.int64, n)
}

// Swap atomically swaps the wrapped int64 and returns the old value.
func (i *Int64) Swap(n int64) int64 {
	return atomic.SwapInt64(&i.int64, n)
}

// Uint32 is an atomic wrapper around an uint32.
type Uint32 struct{ uint32 }

// Load atomically loads the wrapped value.
func (i *Uint32) Load() uint32 {
	return atomic.LoadUint32(&i.uint32)
}

// Add atomically adds to the wrapped uint32 and returns the new value.
func (i *Uint32) Add(n uint32) uint32 {
	return atomic.AddUint32(&i.uint32, n)
}

// Inc atomically increments the wrapped uint32 and returns the new value.
func (i *Uint32) Inc() uint32 {
	return i.Add(1)
}

// Dec atomically decrements the wrapped int32 and returns the new value.
func (i *Uint32) Dec() uint32 {
	return i.Add(^uint32(0))
}

// CAS is an atomic compare-and-swap.
func (i *Uint32) CAS(old, new uint32) bool {
	return atomic.CompareAndSwapUint32(&i.uint32, old, new)
}

// Store atomically stores the passed value.
func (i *Uint32) Store(n uint32) {
	atomic.StoreUint32(&i.uint32, n)
}

// Swap atomically swaps the wrapped uint32 and returns the old value.
func (i *Uint32) Swap(n uint32) uint32 {
	return atomic.SwapUint32(&i.uint32, n)
}

// Uint64 is an atomic wrapper around a uint64.
type Uint64 struct{ uint64 }

// Load atomically loads the wrapped value.
func (i *Uint64) Load() uint64 {
	return atomic.LoadUint64(&i.uint64)
}

// Add atomically adds to the wrapped uint64 and returns the new value.
func (i *Uint64) Add(n uint64) uint64 {
	return atomic.AddUint64(&i.uint64, n)
}

// Inc atomically increments the wrapped uint64 and returns the new value.
func (i *Uint64) Inc() uint64 {
	return i.Add(1)
}

// Dec atomically decrements the wrapped uint64 and returns the new value.
func (i *Uint64) Dec() uint64 {
	return i.Add(^uint64(0))
}

// CAS is an atomic compare-and-swap.
func (i *Uint64) CAS(old, new uint64) bool {
	return atomic.CompareAndSwapUint64(&i.uint64, old, new)
}

// Store atomically stores the passed value.
func (i *Uint64) Store(n uint64) {
	atomic.StoreUint64(&i.uint64, n)
}

// Swap atomically swaps the wrapped uint64 and returns the old value.
func (i *Uint64) Swap(n uint64) uint64 {
	return atomic.SwapUint64(&i.uint64, n)
}
<|endoftext|>


<commit_before>package http

import (
	log "github.com/Sirupsen/logrus"
	"github.com/loadimpact/speedboat/runner"
	"github.com/valyala/fasthttp"
	"math"
	"time"
)

type context struct {
	client *fasthttp.Client
}

type RequestArgs struct {
	Follow bool `json:"follow"`
	Report bool `json:"report"`
}

func New() map[string]interface{} {
	ctx := &context{
		client: &fasthttp.Client{
			Dial:                fasthttp.Dial,
			MaxIdleConnDuration: time.Duration(0),
			MaxConnsPerHost:     math.MaxInt64,
		},
	}
	return map[string]interface{}{
		"get":     ctx.Get,
		"request": ctx.Request,
	}
}

func (ctx *context) Get(url string, args RequestArgs) <-chan runner.Result {
	return ctx.Request("GET", url, args)
}

func (ctx *context) Request(method, url string, args RequestArgs) <-chan runner.Result {
	log.WithFields(log.Fields{
		"follow": args.Follow,
		"report": args.Report,
	}).Info("Aaaa")
	ch := make(chan runner.Result, 1)
	go func() {
		defer close(ch)

		req := fasthttp.AcquireRequest()
		defer fasthttp.ReleaseRequest(req)

		res := fasthttp.AcquireResponse()
		defer fasthttp.ReleaseResponse(res)

		req.SetRequestURI(url)
		req.Header.SetMethod(method)

		startTime := time.Now()
		err := ctx.client.Do(req, res)
		duration := time.Since(startTime)

		ch <- runner.Result{Error: err, Time: duration}
	}()
	return ch
}
<commit_msg>POST + bodies<commit_after>package http

import (
	log "github.com/Sirupsen/logrus"
	"github.com/loadimpact/speedboat/runner"
	"github.com/valyala/fasthttp"
	"math"
	"time"
)

type context struct {
	client *fasthttp.Client
}

type RequestArgs struct {
	Follow bool `json:"follow"`
	Report bool `json:"report"`
}

func New() map[string]interface{} {
	ctx := &context{
		client: &fasthttp.Client{
			Dial:                fasthttp.Dial,
			MaxIdleConnDuration: time.Duration(0),
			MaxConnsPerHost:     math.MaxInt64,
		},
	}
	return map[string]interface{}{
		"get":     ctx.Get,
		"post":    ctx.Post,
		"request": ctx.Request,
	}
}

func (ctx *context) Get(url string, args RequestArgs) <-chan runner.Result {
	return ctx.Request("GET", url, "", args)
}

func (ctx *context) Post(url, body string, args RequestArgs) <-chan runner.Result {
	return ctx.Request("POST", url, body, args)
}

func (ctx *context) Request(method, url, body string, args RequestArgs) <-chan runner.Result {
	log.WithFields(log.Fields{
		"method": method,
		"url":    url,
		"follow": args.Follow,
		"report": args.Report,
	}).Debug("Request")
	ch := make(chan runner.Result, 1)
	go func() {
		defer close(ch)

		req := fasthttp.AcquireRequest()
		defer fasthttp.ReleaseRequest(req)

		res := fasthttp.AcquireResponse()
		defer fasthttp.ReleaseResponse(res)

		req.SetRequestURI(url)
		req.Header.SetMethod(method)
		req.SetBodyString(body)

		startTime := time.Now()
		err := ctx.client.Do(req, res)
		duration := time.Since(startTime)

		ch <- runner.Result{Error: err, Time: duration}
	}()
	return ch
}
<|endoftext|>


<commit_before>/*
 * ZDNS Copyright 2016 Regents of the University of Michigan
 *
 * 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 (
	"flag"
	"os"
	"runtime"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/zmap/zdns"
	_ "github.com/zmap/zdns/modules/a"
	_ "github.com/zmap/zdns/modules/aaaa"
	_ "github.com/zmap/zdns/modules/alookup"
	_ "github.com/zmap/zdns/modules/any"
	_ "github.com/zmap/zdns/modules/axfr"
	_ "github.com/zmap/zdns/modules/caa"
	_ "github.com/zmap/zdns/modules/cname"
	_ "github.com/zmap/zdns/modules/dmarc"
	_ "github.com/zmap/zdns/modules/mx"
	_ "github.com/zmap/zdns/modules/mxlookup"
	_ "github.com/zmap/zdns/modules/ns"
	_ "github.com/zmap/zdns/modules/nslookup"
	_ "github.com/zmap/zdns/modules/ptr"
	_ "github.com/zmap/zdns/modules/soa"
	_ "github.com/zmap/zdns/modules/spf"
	_ "github.com/zmap/zdns/modules/spfrr"
	_ "github.com/zmap/zdns/modules/txt"
	_ "github.com/zmap/zdns/modules/zone"
)

func main() {

	var gc zdns.GlobalConf
	// global flags relevant to every lookup module
	flags := flag.NewFlagSet("flags", flag.ExitOnError)
	flags.IntVar(&gc.Threads, "threads", 1000, "number of lightweight go threads")
	flags.IntVar(&gc.GoMaxProcs, "go-processes", 0, "number of OS processes (GOMAXPROCS)")
	flags.StringVar(&gc.NamePrefix, "prefix", "", "name to be prepended to what's passed in (e.g., www.)")
	flags.BoolVar(&gc.AlexaFormat, "alexa", false, "is input file from Alexa Top Million download")
	flags.StringVar(&gc.InputFilePath, "input-file", "-", "names to read")
	flags.StringVar(&gc.OutputFilePath, "output-file", "-", "where should JSON output be saved")
	flags.StringVar(&gc.MetadataFilePath, "metadata-file", "", "where should JSON metadata be saved")
	flags.StringVar(&gc.LogFilePath, "log-file", "", "where should JSON logs be saved")
	flags.IntVar(&gc.Verbosity, "verbosity", 3, "log verbosity: 1 (lowest)--5 (highest)")
	servers_string := flags.String("name-servers", "", "comma-delimited list of DNS servers to use")
	config_file := flags.String("conf-file", "/etc/resolv.conf", "config file for DNS servers")
	timeout := flags.Int("timeout", 10, "timeout for resolving an individual name")
	// allow module to initialize and add its own flags before we parse
	if len(os.Args) < 2 {
		log.Fatal("No lookup module specified. Valid modules: ", zdns.ValidlookupsString())
	}
	gc.Module = strings.ToUpper(os.Args[1])
	factory := zdns.GetLookup(gc.Module)
	if factory == nil {
		log.Fatal("Invalid lookup module specified. Valid modules: ", zdns.ValidlookupsString())
	}
	factory.AddFlags(flags)
	flags.Parse(os.Args[2:])
	// Do some basic sanity checking
	// setup global logging
	if gc.LogFilePath != "" {
		f, err := os.OpenFile(gc.LogFilePath, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			log.Fatalf("Unable to open log file (%s): %s", gc.LogFilePath, err.Error())
		}
		log.SetOutput(f)
	}
	// Translate the assigned verbosity level to a logrus log level.
	switch gc.Verbosity {
	case 1: // Fatal
		log.SetLevel(log.FatalLevel)
	case 2: // Error
		log.SetLevel(log.ErrorLevel)
	case 3: // Warnings  (default)
		log.SetLevel(log.WarnLevel)
	case 4: // Information
		log.SetLevel(log.InfoLevel)
	case 5: // Debugging
		log.SetLevel(log.DebugLevel)
	default:
		log.Fatal("Unknown verbosity level specified. Must be between 1 (lowest)--5 (highest)")
	}
	// complete post facto global initialization based on command line arguments
	gc.Timeout = time.Duration(time.Second * time.Duration(*timeout))
	if *servers_string == "" {
		// figure out default OS name servers
		ns, err := zdns.GetDNSServers(*config_file)
		if err != nil {
			log.Fatal("Unable to fetch correct name servers:", err.Error())
		}
		gc.NameServers = ns
		gc.NameServersSpecified = false
		log.Info("no name servers specified. will use: ", strings.Join(gc.NameServers, ", "))
	} else {
		gc.NameServers = strings.Split(*servers_string, ",")
		gc.NameServersSpecified = true
	}
	if gc.GoMaxProcs < 0 {
		log.Fatal("Invalid argument for --go-processes. Must be >1.")
	}
	if gc.GoMaxProcs != 0 {
		runtime.GOMAXPROCS(gc.GoMaxProcs)
	}
	// some modules require multiple passes over a file (this is really just the case for zone files)
	if !factory.AllowStdIn() && gc.InputFilePath == "-" {
		log.Fatal("Specified module does not allow reading from stdin")
	}

	// allow the factory to initialize itself
	if err := factory.Initialize(&gc); err != nil {
		log.Fatal("Factory was unable to initialize:", err.Error())
	}
	// run it.
	if err := zdns.DoLookups(&factory, &gc); err != nil {
		log.Fatal("Unable to run lookups:", err.Error())
	}
	// allow the factory to initialize itself
	if err := factory.Finalize(); err != nil {
		log.Fatal("Factory was unable to finalize:", err.Error())
	}
}
<commit_msg>Allow 'zdns -h' to work even without a lookup module<commit_after>/*
 * ZDNS Copyright 2016 Regents of the University of Michigan
 *
 * 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 (
	"flag"
	"os"
	"runtime"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/zmap/zdns"
	_ "github.com/zmap/zdns/modules/a"
	_ "github.com/zmap/zdns/modules/aaaa"
	_ "github.com/zmap/zdns/modules/alookup"
	_ "github.com/zmap/zdns/modules/any"
	_ "github.com/zmap/zdns/modules/axfr"
	_ "github.com/zmap/zdns/modules/caa"
	_ "github.com/zmap/zdns/modules/cname"
	_ "github.com/zmap/zdns/modules/dmarc"
	_ "github.com/zmap/zdns/modules/mx"
	_ "github.com/zmap/zdns/modules/mxlookup"
	_ "github.com/zmap/zdns/modules/ns"
	_ "github.com/zmap/zdns/modules/nslookup"
	_ "github.com/zmap/zdns/modules/ptr"
	_ "github.com/zmap/zdns/modules/soa"
	_ "github.com/zmap/zdns/modules/spf"
	_ "github.com/zmap/zdns/modules/spfrr"
	_ "github.com/zmap/zdns/modules/txt"
	_ "github.com/zmap/zdns/modules/zone"
)

func main() {

	var gc zdns.GlobalConf
	// global flags relevant to every lookup module
	flags := flag.NewFlagSet("flags", flag.ExitOnError)
	flags.IntVar(&gc.Threads, "threads", 1000, "number of lightweight go threads")
	flags.IntVar(&gc.GoMaxProcs, "go-processes", 0, "number of OS processes (GOMAXPROCS)")
	flags.StringVar(&gc.NamePrefix, "prefix", "", "name to be prepended to what's passed in (e.g., www.)")
	flags.BoolVar(&gc.AlexaFormat, "alexa", false, "is input file from Alexa Top Million download")
	flags.StringVar(&gc.InputFilePath, "input-file", "-", "names to read")
	flags.StringVar(&gc.OutputFilePath, "output-file", "-", "where should JSON output be saved")
	flags.StringVar(&gc.MetadataFilePath, "metadata-file", "", "where should JSON metadata be saved")
	flags.StringVar(&gc.LogFilePath, "log-file", "", "where should JSON logs be saved")
	flags.IntVar(&gc.Verbosity, "verbosity", 3, "log verbosity: 1 (lowest)--5 (highest)")
	servers_string := flags.String("name-servers", "", "comma-delimited list of DNS servers to use")
	config_file := flags.String("conf-file", "/etc/resolv.conf", "config file for DNS servers")
	timeout := flags.Int("timeout", 10, "timeout for resolving an individual name")
	// allow module to initialize and add its own flags before we parse
	if len(os.Args) < 2 {
		log.Fatal("No lookup module specified. Valid modules: ", zdns.ValidlookupsString())
	}
	gc.Module = strings.ToUpper(os.Args[1])
	factory := zdns.GetLookup(gc.Module)
	if factory == nil {
		flags.Parse(os.Args[1:])
		log.Fatal("Invalid lookup module specified. Valid modules: ", zdns.ValidlookupsString())
	}
	factory.AddFlags(flags)
	flags.Parse(os.Args[2:])
	// Do some basic sanity checking
	// setup global logging
	if gc.LogFilePath != "" {
		f, err := os.OpenFile(gc.LogFilePath, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			log.Fatalf("Unable to open log file (%s): %s", gc.LogFilePath, err.Error())
		}
		log.SetOutput(f)
	}
	// Translate the assigned verbosity level to a logrus log level.
	switch gc.Verbosity {
	case 1: // Fatal
		log.SetLevel(log.FatalLevel)
	case 2: // Error
		log.SetLevel(log.ErrorLevel)
	case 3: // Warnings  (default)
		log.SetLevel(log.WarnLevel)
	case 4: // Information
		log.SetLevel(log.InfoLevel)
	case 5: // Debugging
		log.SetLevel(log.DebugLevel)
	default:
		log.Fatal("Unknown verbosity level specified. Must be between 1 (lowest)--5 (highest)")
	}
	// complete post facto global initialization based on command line arguments
	gc.Timeout = time.Duration(time.Second * time.Duration(*timeout))
	if *servers_string == "" {
		// figure out default OS name servers
		ns, err := zdns.GetDNSServers(*config_file)
		if err != nil {
			log.Fatal("Unable to fetch correct name servers:", err.Error())
		}
		gc.NameServers = ns
		gc.NameServersSpecified = false
		log.Info("no name servers specified. will use: ", strings.Join(gc.NameServers, ", "))
	} else {
		gc.NameServers = strings.Split(*servers_string, ",")
		gc.NameServersSpecified = true
	}
	if gc.GoMaxProcs < 0 {
		log.Fatal("Invalid argument for --go-processes. Must be >1.")
	}
	if gc.GoMaxProcs != 0 {
		runtime.GOMAXPROCS(gc.GoMaxProcs)
	}
	// some modules require multiple passes over a file (this is really just the case for zone files)
	if !factory.AllowStdIn() && gc.InputFilePath == "-" {
		log.Fatal("Specified module does not allow reading from stdin")
	}

	// allow the factory to initialize itself
	if err := factory.Initialize(&gc); err != nil {
		log.Fatal("Factory was unable to initialize:", err.Error())
	}
	// run it.
	if err := zdns.DoLookups(&factory, &gc); err != nil {
		log.Fatal("Unable to run lookups:", err.Error())
	}
	// allow the factory to initialize itself
	if err := factory.Finalize(); err != nil {
		log.Fatal("Factory was unable to finalize:", err.Error())
	}
}
<|endoftext|>


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

package rpc

import (
	"bufio"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"net"
	"net/http"
	"sync"
	"time"
)

// ServerError represents an error that has been returned from
// the remote side of the RPC connection.
type ServerError string

func (e ServerError) Error() string {
	return string(e)
}

var ErrShutdown = errors.New("connection is shut down")
var ErrTimeout = errors.New("operation is timeout")

// Call represents an active RPC.
type Call struct {
	Cmd   uint32      // The name of the service and method to call.
	Seq   uint32      // sequence of current call
	Args  interface{} // The argument to the function (*struct).
	Reply interface{} // The reply from the function (*struct).
	Error error       // After completion, the error status.
	Done  chan *Call  // Strobes when call is complete.
	timer *time.Timer
}

// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
// with a single Client, and a Client may be used by
// multiple goroutines simultaneously.
type Client struct {
	codec ClientCodec

	reqMutex sync.Mutex // protects following
	request  Request

	mutex    sync.Mutex // protects following
	seq      uint32
	pending  map[uint32]*Call
	closing  bool // user has called Close
	shutdown bool // server has told us to stop
}

// A ClientCodec implements writing of RPC requests and
// reading of RPC responses for the client side of an RPC session.
// The client calls WriteRequest to write a request to the connection
// and calls ReadResponseHeader and ReadResponseBody in pairs
// to read responses.  The client calls Close when finished with the
// connection. ReadResponseBody may be called with a nil
// argument to force the body of the response to be read and then
// discarded.
type ClientCodec interface {
	// WriteRequest must be safe for concurrent use by multiple goroutines.
	WriteRequest(*Request, interface{}) error
	ReadResponseHeader(*Response) error
	ReadResponseBody(interface{}) error

	Close() error
}

func (client *Client) send(call *Call) {
	client.reqMutex.Lock()
	defer client.reqMutex.Unlock()

	// Register this call.
	client.mutex.Lock()
	if client.shutdown || client.closing {
		call.Error = ErrShutdown
		client.mutex.Unlock()
		call.done()
		return
	}
	seq := client.seq
	call.Seq = seq
	client.seq++
	client.pending[seq] = call
	client.mutex.Unlock()

	// Encode and send the request.
	client.request.Seq = seq
	client.request.Cmd = call.Cmd
	err := client.codec.WriteRequest(&client.request, call.Args)
	if err != nil {
		client.mutex.Lock()
		call = client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()
		if call != nil {
			call.Error = err
			call.done()
		}
	}
}

func (client *Client) input() {
	var err error
	var response Response
	for err == nil {
		response = Response{}
		err = client.codec.ReadResponseHeader(&response)
		if err != nil {
			break
		}
		seq := response.Seq
		client.mutex.Lock()
		call := client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()

		switch {
		case call == nil:
			// We've got no pending call. That usually means that
			// WriteRequest partially failed, and call was already
			// removed; response is a server telling us about an
			// error reading request body. We should still attempt
			// to read error body, but there's no one to give it to.
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error body: " + err.Error())
			}
		case response.Error != 0:
			// We've got an error response. Give this to the request;
			// any subsequent requests will get the ReadResponseBody
			// error if there is one.
			call.Error = Error(response.Error)
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error body: " + err.Error())
			}
			call.done()
		default:
			err = client.codec.ReadResponseBody(call.Reply)
			if err != nil {
				call.Error = errors.New("reading body " + err.Error())
			}
			call.done()
		}
	}
	// Terminate pending calls.
	client.reqMutex.Lock()
	client.mutex.Lock()
	client.shutdown = true
	closing := client.closing
	if err == io.EOF {
		if closing {
			err = ErrShutdown
		} else {
			err = io.ErrUnexpectedEOF
		}
	}
	for _, call := range client.pending {
		call.Error = err
		call.done()
	}
	client.mutex.Unlock()
	client.reqMutex.Unlock()
	if debugLog && err != io.EOF && !closing {
		log.Println("rpc: client protocol error:", err)
	}
}

func (call *Call) done() {
	if call.timer != nil {
		call.timer.Stop()
	}
	select {
	case call.Done <- call:
		// ok
	default:
		// We don't want to block here.  It is the caller's responsibility to make
		// sure the channel has enough buffer space. See comment in Go().
		if debugLog {
			log.Println("rpc: discarding Call reply due to insufficient Done chan capacity")
		}
	}
}

// NewClient returns a new Client to handle requests to the
// set of services at the other end of the connection.
// It adds a buffer to the write side of the connection so
// the header and payload are sent as a unit.
func NewClient(conn io.ReadWriteCloser) *Client {
	encBuf := bufio.NewWriter(conn)
	client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf}
	return NewClientWithCodec(client)
}

// NewClientWithCodec is like NewClient but uses the specified
// codec to encode requests and decode responses.
func NewClientWithCodec(codec ClientCodec) *Client {
	client := &Client{
		codec:   codec,
		pending: make(map[uint32]*Call),
	}
	go client.input()
	return client
}

type gobClientCodec struct {
	rwc    io.ReadWriteCloser
	dec    *gob.Decoder
	enc    *gob.Encoder
	encBuf *bufio.Writer
}

func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err error) {
	if err = c.enc.Encode(r); err != nil {
		return
	}
	if err = c.enc.Encode(body); err != nil {
		return
	}
	return c.encBuf.Flush()
}

func (c *gobClientCodec) ReadResponseHeader(r *Response) error {
	return c.dec.Decode(r)
}

func (c *gobClientCodec) ReadResponseBody(body interface{}) error {
	return c.dec.Decode(body)
}

func (c *gobClientCodec) Close() error {
	return c.rwc.Close()
}

// DialHTTP connects to an HTTP RPC server at the specified network address
// listening on the default HTTP RPC path.
func DialHTTP(network, address string) (*Client, error) {
	return DialHTTPPath(network, address, DefaultRPCPath)
}

// DialHTTPPath connects to an HTTP RPC server
// at the specified network address and path.
func DialHTTPPath(network, address, path string) (*Client, error) {
	var err error
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")

	// Require successful HTTP response
	// before switching to RPC protocol.
	resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
	if err == nil && resp.Status == connected {
		return NewClient(conn), nil
	}
	if err == nil {
		err = errors.New("unexpected HTTP response: " + resp.Status)
	}
	conn.Close()
	return nil, &net.OpError{
		Op:   "dial-http",
		Net:  network + " " + address,
		Addr: nil,
		Err:  err,
	}
}

// Dial connects to an RPC server at the specified network address.
func Dial(network, address string) (*Client, error) {
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	return NewClient(conn), nil
}

func (client *Client) Close() error {
	client.mutex.Lock()
	if client.closing {
		client.mutex.Unlock()
		return ErrShutdown
	}
	client.closing = true
	client.mutex.Unlock()
	return client.codec.Close()
}

// Go invokes the function asynchronously.  It returns the Call structure representing
// the invocation.  The done channel will signal when the call is complete by returning
// the same Call object.  If done is nil, Go will allocate a new channel.
// If non-nil, done must be buffered or Go will deliberately crash.
func (client *Client) Go(cmd uint32, args interface{}, reply interface{}, done chan *Call) *Call {
	call := new(Call)
	call.Cmd = cmd
	call.Args = args
	call.Reply = reply
	if done == nil {
		done = make(chan *Call, 10) // buffered.
	} else {
		// If caller passes done != nil, it must arrange that
		// done has enough buffer for the number of simultaneous
		// RPCs that will be using that channel.  If the channel
		// is totally unbuffered, it's best not to run at all.
		if cap(done) == 0 {
			log.Panic("rpc: done channel is unbuffered")
		}
	}
	call.Done = done
	client.send(call)
	return call
}

func (client *Client) GoWithTimeout(cmd uint32, args interface{}, reply interface{}, done chan *Call, d time.Duration) *Call {
	call := client.Go(cmd, args, reply, done)
	call.timer = time.AfterFunc(d, func() {
		var ok bool
		// delete pending call
		client.mutex.Lock()
		if _, ok = client.pending[call.Seq]; ok {
			delete(client.pending, call.Seq)
		}
		client.mutex.Unlock()
		if ok {
			call.Error = ErrTimeout
			call.done()
		}
	})
	return call
}

// Call invokes the named function, waits for it to complete, and returns its error status.
func (client *Client) Call(cmd uint32, args interface{}, reply interface{}) error {
	call := <-client.Go(cmd, args, reply, make(chan *Call, 1)).Done
	return call.Error
}

// Call invokes the named function, waits for it to complete, and returns its error status.
// If timeout occurs, it returns ErrTimeout
func (client *Client) CallWithTimeout(cmd uint32, args interface{}, reply interface{}, d time.Duration) error {
	call := client.Go(cmd, args, reply, make(chan *Call, 1))
	call.timer = time.NewTimer(d)

	var err error
	select {
	case call = <-call.Done:
		err = call.Error
	case _ = <-call.timer.C:
		err = ErrTimeout
		// delete pending call
		client.mutex.Lock()
		delete(client.pending, call.Seq)
		client.mutex.Unlock()
	}

	return err
}
<commit_msg>support notify<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rpc

import (
	"bufio"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"net"
	"net/http"
	"reflect"
	"sync"
	"time"
)

// ServerError represents an error that has been returned from
// the remote side of the RPC connection.
type ServerError string

func (e ServerError) Error() string {
	return string(e)
}

var ErrShutdown = errors.New("connection is shut down")
var ErrTimeout = errors.New("operation is timeout")

// Call represents an active RPC.
type Call struct {
	Cmd   uint32      // The name of the service and method to call.
	Seq   uint32      // sequence of current call
	Args  interface{} // The argument to the function (*struct).
	Reply interface{} // The reply from the function (*struct).
	Error error       // After completion, the error status.
	Done  chan *Call  // Strobes when call is complete.
	timer *time.Timer
}

// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
// with a single Client, and a Client may be used by
// multiple goroutines simultaneously.
type Client struct {
	codec ClientCodec

	reqMutex sync.Mutex // protects following
	request  Request

	mutex    sync.Mutex // protects following
	seq      uint32
	pending  map[uint32]*Call
	ntf      map[uint32]reflect.Type
	closing  bool // user has called Close
	shutdown bool // server has told us to stop
}

// A ClientCodec implements writing of RPC requests and
// reading of RPC responses for the client side of an RPC session.
// The client calls WriteRequest to write a request to the connection
// and calls ReadResponseHeader and ReadResponseBody in pairs
// to read responses.  The client calls Close when finished with the
// connection. ReadResponseBody may be called with a nil
// argument to force the body of the response to be read and then
// discarded.
type ClientCodec interface {
	// WriteRequest must be safe for concurrent use by multiple goroutines.
	WriteRequest(*Request, interface{}) error
	ReadResponseHeader(*Response) error
	ReadResponseBody(interface{}) error

	Close() error
}

func (client *Client) send(call *Call) {
	client.reqMutex.Lock()
	defer client.reqMutex.Unlock()

	// Register this call.
	client.mutex.Lock()
	if client.shutdown || client.closing {
		call.Error = ErrShutdown
		client.mutex.Unlock()
		call.done()
		return
	}
	seq := client.seq
	call.Seq = seq
	client.seq++
	client.pending[seq] = call
	client.mutex.Unlock()

	// Encode and send the request.
	client.request.Seq = seq
	client.request.Cmd = call.Cmd
	err := client.codec.WriteRequest(&client.request, call.Args)
	if err != nil {
		client.mutex.Lock()
		call = client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()
		if call != nil {
			call.Error = err
			call.done()
		}
	}
}

func (client *Client) input() {
	var err error
	var response Response
	for err == nil {
		response = Response{}
		err = client.codec.ReadResponseHeader(&response)
		if err != nil {
			break
		}
		seq := response.Seq
		client.mutex.Lock()
		call := client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()

		switch {
		case seq == 0:
			if ntf_typ, ok := client.ntf[response.Cmd]; ok {
				ntf_val := reflect.New(ntf_typ)
				err = client.codec.ReadResponseBody(ntf_val)
				if err != nil {
					err = errors.New("reading error ntf body: " + err.Error())
				}
			} else {
				// unknow ntf, just discard...
			}
		case call == nil:
			// We've got no pending call. That usually means that
			// WriteRequest partially failed, and call was already
			// removed; response is a server telling us about an
			// error reading request body. We should still attempt
			// to read error body, but there's no one to give it to.
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error body: " + err.Error())
			}
		case response.Error != 0:
			// We've got an error response. Give this to the request;
			// any subsequent requests will get the ReadResponseBody
			// error if there is one.
			call.Error = Error(response.Error)
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error body: " + err.Error())
			}
			call.done()
		default:
			err = client.codec.ReadResponseBody(call.Reply)
			if err != nil {
				call.Error = errors.New("reading body " + err.Error())
			}
			call.done()
		}
	}
	// Terminate pending calls.
	client.reqMutex.Lock()
	client.mutex.Lock()
	client.shutdown = true
	closing := client.closing
	if err == io.EOF {
		if closing {
			err = ErrShutdown
		} else {
			err = io.ErrUnexpectedEOF
		}
	}
	for _, call := range client.pending {
		call.Error = err
		call.done()
	}
	client.mutex.Unlock()
	client.reqMutex.Unlock()
	if debugLog && err != io.EOF && !closing {
		log.Println("rpc: client protocol error:", err)
	}
}

func (call *Call) done() {
	if call.timer != nil {
		call.timer.Stop()
	}
	select {
	case call.Done <- call:
		// ok
	default:
		// We don't want to block here.  It is the caller's responsibility to make
		// sure the channel has enough buffer space. See comment in Go().
		if debugLog {
			log.Println("rpc: discarding Call reply due to insufficient Done chan capacity")
		}
	}
}

// NewClient returns a new Client to handle requests to the
// set of services at the other end of the connection.
// It adds a buffer to the write side of the connection so
// the header and payload are sent as a unit.
func NewClient(conn io.ReadWriteCloser) *Client {
	encBuf := bufio.NewWriter(conn)
	client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf}
	return NewClientWithCodec(client)
}

// NewClientWithCodec is like NewClient but uses the specified
// codec to encode requests and decode responses.
func NewClientWithCodec(codec ClientCodec) *Client {
	client := &Client{
		codec:   codec,
		pending: make(map[uint32]*Call),
		ntf:     make(map[uint32]reflect.Type),
	}
	go client.input()
	return client
}

type gobClientCodec struct {
	rwc    io.ReadWriteCloser
	dec    *gob.Decoder
	enc    *gob.Encoder
	encBuf *bufio.Writer
}

func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err error) {
	if err = c.enc.Encode(r); err != nil {
		return
	}
	if err = c.enc.Encode(body); err != nil {
		return
	}
	return c.encBuf.Flush()
}

func (c *gobClientCodec) ReadResponseHeader(r *Response) error {
	return c.dec.Decode(r)
}

func (c *gobClientCodec) ReadResponseBody(body interface{}) error {
	return c.dec.Decode(body)
}

func (c *gobClientCodec) Close() error {
	return c.rwc.Close()
}

// DialHTTP connects to an HTTP RPC server at the specified network address
// listening on the default HTTP RPC path.
func DialHTTP(network, address string) (*Client, error) {
	return DialHTTPPath(network, address, DefaultRPCPath)
}

// DialHTTPPath connects to an HTTP RPC server
// at the specified network address and path.
func DialHTTPPath(network, address, path string) (*Client, error) {
	var err error
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")

	// Require successful HTTP response
	// before switching to RPC protocol.
	resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
	if err == nil && resp.Status == connected {
		return NewClient(conn), nil
	}
	if err == nil {
		err = errors.New("unexpected HTTP response: " + resp.Status)
	}
	conn.Close()
	return nil, &net.OpError{
		Op:   "dial-http",
		Net:  network + " " + address,
		Addr: nil,
		Err:  err,
	}
}

// Dial connects to an RPC server at the specified network address.
func Dial(network, address string) (*Client, error) {
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	return NewClient(conn), nil
}

func (client *Client) Close() error {
	client.mutex.Lock()
	if client.closing {
		client.mutex.Unlock()
		return ErrShutdown
	}
	client.closing = true
	client.mutex.Unlock()
	return client.codec.Close()
}

// Go invokes the function asynchronously.  It returns the Call structure representing
// the invocation.  The done channel will signal when the call is complete by returning
// the same Call object.  If done is nil, Go will allocate a new channel.
// If non-nil, done must be buffered or Go will deliberately crash.
func (client *Client) Go(cmd uint32, args interface{}, reply interface{}, done chan *Call) *Call {
	call := new(Call)
	call.Cmd = cmd
	call.Args = args
	call.Reply = reply
	if done == nil {
		done = make(chan *Call, 10) // buffered.
	} else {
		// If caller passes done != nil, it must arrange that
		// done has enough buffer for the number of simultaneous
		// RPCs that will be using that channel.  If the channel
		// is totally unbuffered, it's best not to run at all.
		if cap(done) == 0 {
			log.Panic("rpc: done channel is unbuffered")
		}
	}
	call.Done = done
	client.send(call)
	return call
}

func (client *Client) GoWithTimeout(cmd uint32, args interface{}, reply interface{}, done chan *Call, d time.Duration) *Call {
	call := client.Go(cmd, args, reply, done)
	call.timer = time.AfterFunc(d, func() {
		var ok bool
		// delete pending call
		client.mutex.Lock()
		if _, ok = client.pending[call.Seq]; ok {
			delete(client.pending, call.Seq)
		}
		client.mutex.Unlock()
		if ok {
			call.Error = ErrTimeout
			call.done()
		}
	})
	return call
}

// Call invokes the named function, waits for it to complete, and returns its error status.
func (client *Client) Call(cmd uint32, args interface{}, reply interface{}) error {
	call := <-client.Go(cmd, args, reply, make(chan *Call, 1)).Done
	return call.Error
}

// Call invokes the named function, waits for it to complete, and returns its error status.
// If timeout occurs, it returns ErrTimeout
func (client *Client) CallWithTimeout(cmd uint32, args interface{}, reply interface{}, d time.Duration) error {
	call := client.Go(cmd, args, reply, make(chan *Call, 1))
	call.timer = time.NewTimer(d)

	var err error
	select {
	case call = <-call.Done:
		err = call.Error
	case _ = <-call.timer.C:
		err = ErrTimeout
		// delete pending call
		client.mutex.Lock()
		delete(client.pending, call.Seq)
		client.mutex.Unlock()
	}

	return err
}

func (client *Client) OnNotify(cmd uint32, reply interface{}) {
	typ := reflect.TypeOf(reply)
	client.ntf[cmd] = typ
}
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Nan Deng
 *
 * 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 rpc

import "net"

type Result struct {
	Error   string        `json:"error,omitempty"`
	Results []*ConnResult `json:"results,omitempty"`
}

func (self *Result) SetError(err error) {
	if self == nil || err == nil {
		return
	}
	self.Error = err.Error()
}

func (self *Result) NrResults() int {
	if self == nil {
		return 0
	}
	return len(self.Results)
}

func (self *Result) NrSuccess() int {
	if self == nil {
		return 0
	}
	ret := 0
	for _, r := range self.Results {
		if r.Error == "" {
			ret++
		}
	}
	return ret
}

func (self *Result) Join(r *Result) {
	if self == nil {
		return
	}
	if r == nil {
		return
	}
	if self.Error != "" {
		return
	}
	if r.Error != "" {
		self.Error = r.Error
		return
	}
	self.Results = append(self.Results, r.Results...)
}

type connDescriptor interface {
	RemoteAddr() net.Addr
	Service() string
	Username() string
	UniqId() string
	Visible() bool
}

func (self *Result) Append(c connDescriptor, err error) {
	if self == nil {
		return
	}
	if self.Results == nil {
		self.Results = make([]*ConnResult, 0, 10)
	}
	r := new(ConnResult)
	r.ConnId = c.UniqId()
	if err != nil {
		r.Error = err.Error()
	}
	r.Visible = c.Visible()
	r.Username = c.Username()
	r.Service = c.Service()
	r.Address = c.RemoteAddr().String()
	self.Results = append(self.Results, r)
}

type ConnResult struct {
	Address  string `json:"address"`
	ConnId   string `json:"conn-id"`
	Error    string `json:"error,omitempty"`
	Visible  bool   `json:"visible"`
	Username string `josn:"username"`
	Service  string `json:"service"`
}
<commit_msg>trying to fix #14<commit_after>/*
 * Copyright 2013 Nan Deng
 *
 * 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 rpc

import "net"

type Result struct {
	Error   string        `json:"error,omitempty"`
	Results []*ConnResult `json:"results,omitempty"`
}

func (self *Result) SetError(err error) {
	if self == nil || err == nil {
		return
	}
	self.Error = err.Error()
}

func (self *Result) NrResults() int {
	if self == nil {
		return 0
	}
	return len(self.Results)
}

func (self *Result) NrSuccess() int {
	if self == nil {
		return 0
	}
	ret := 0
	for _, r := range self.Results {
		if r.Error == "" {
			ret++
		}
	}
	return ret
}

func (self *Result) NrSuccessForUser(string service, string user) int {
	if self == nil {
		return 0
	}
	ret := 0
	for _, r := range self.Results {
		if r.Service == service && r.Username == user && r.Error == "" {
			ret += 1
		}
	}
	return ret
}

func (self *Result) Join(r *Result) {
	if self == nil {
		return
	}
	if r == nil {
		return
	}
	if self.Error != "" {
		return
	}
	if r.Error != "" {
		self.Error = r.Error
		return
	}
	self.Results = append(self.Results, r.Results...)
}

type connDescriptor interface {
	RemoteAddr() net.Addr
	Service() string
	Username() string
	UniqId() string
	Visible() bool
}

func (self *Result) Append(c connDescriptor, err error) {
	if self == nil {
		return
	}
	if self.Results == nil {
		self.Results = make([]*ConnResult, 0, 10)
	}
	r := new(ConnResult)
	r.ConnId = c.UniqId()
	if err != nil {
		r.Error = err.Error()
	}
	r.Visible = c.Visible()
	r.Username = c.Username()
	r.Service = c.Service()
	r.Address = c.RemoteAddr().String()
	self.Results = append(self.Results, r)
}

type ConnResult struct {
	Address  string `json:"address"`
	ConnId   string `json:"conn-id"`
	Error    string `json:"error,omitempty"`
	Visible  bool   `json:"visible"`
	Username string `josn:"username"`
	Service  string `json:"service"`
}
<|endoftext|>


<commit_before>package source

import "fmt"

// Pos represents a single position in a source file, by addressing the
// start byte of a unicode character encoded in UTF-8.
//
// Pos is generally used only in the context of a Range, which then defines
// which source file the position is within.
type Pos struct {
	// Line is the source code line where this position points. Lines are
	// counted starting at 1 and incremented for each newline character
	// encountered.
	Line int

	// Column is the source code column where this position points, in
	// unicode characters, with counting starting at 1.
	//
	// Column counts characters as they appear visually, so for example a
	// latin letter with a combining diacritic mark counts as one character.
	// This is intended for rendering visual markers against source code in
	// contexts where these diacritics would be rendered in a single character
	// cell. Technically speaking, Column is counting grapheme clusters as
	// used in unicode normalization.
	Column int

	// Byte is the byte offset into the file where the indicated character
	// begins. This is a zero-based offset to the first byte of the first
	// UTF-8 codepoint sequence in the character, and thus gives a position
	// that can be resolved _without_ awareness of Unicode characters.
	Byte int
}

var StartPos = Pos{Line: 1, Column: 1}

// Range represents a span of characters between two positions in a source
// file.
//
// This struct is usually used by value in types that represent AST nodes,
// but by pointer in types that refer to the positions of other objects,
// such as in diagnostics.
type Range struct {
	// Filename is the name of the file into which this range's positions
	// point.
	Filename string

	// Start and End represent the bounds of this range. Start is inclusive
	// and End is exclusive.
	Start, End Pos
}

// RangeBetween returns a new range that spans from the beginning of the
// start range to the end of the end range.
//
// The result is meaningless if the two ranges do not belong to the same
// source file or if the end range appears before the start range.
func RangeBetween(start, end Range) Range {
	return Range{
		Filename: start.Filename,
		Start:    start.Start,
		End:      end.End,
	}
}

// ContainsOffset returns true if and only if the given byte offset is within
// the receiving Range.
func (r Range) ContainsOffset(offset int) bool {
	return offset >= r.Start.Byte && offset < r.End.Byte
}

// String returns a compact string representation of the receiver.
// Callers should generally prefer to present a range more visually,
// e.g. via markers directly on the relevant portion of source code.
func (r Range) String() string {
	if r.Start.Line == r.End.Line {
		return fmt.Sprintf(
			"%s:%d,%d-%d",
			r.Filename,
			r.Start.Line, r.Start.Column,
			r.End.Column,
		)
	} else {
		return fmt.Sprintf(
			"%s:%d,%d-%d,%d",
			r.Filename,
			r.Start.Line, r.Start.Column,
			r.End.Line, r.End.Column,
		)
	}
}
<commit_msg>source: List helper for Ranges<commit_after>package source

import "fmt"

// Pos represents a single position in a source file, by addressing the
// start byte of a unicode character encoded in UTF-8.
//
// Pos is generally used only in the context of a Range, which then defines
// which source file the position is within.
type Pos struct {
	// Line is the source code line where this position points. Lines are
	// counted starting at 1 and incremented for each newline character
	// encountered.
	Line int

	// Column is the source code column where this position points, in
	// unicode characters, with counting starting at 1.
	//
	// Column counts characters as they appear visually, so for example a
	// latin letter with a combining diacritic mark counts as one character.
	// This is intended for rendering visual markers against source code in
	// contexts where these diacritics would be rendered in a single character
	// cell. Technically speaking, Column is counting grapheme clusters as
	// used in unicode normalization.
	Column int

	// Byte is the byte offset into the file where the indicated character
	// begins. This is a zero-based offset to the first byte of the first
	// UTF-8 codepoint sequence in the character, and thus gives a position
	// that can be resolved _without_ awareness of Unicode characters.
	Byte int
}

var StartPos = Pos{Line: 1, Column: 1}

// Range represents a span of characters between two positions in a source
// file.
//
// This struct is usually used by value in types that represent AST nodes,
// but by pointer in types that refer to the positions of other objects,
// such as in diagnostics.
type Range struct {
	// Filename is the name of the file into which this range's positions
	// point.
	Filename string

	// Start and End represent the bounds of this range. Start is inclusive
	// and End is exclusive.
	Start, End Pos
}

// RangeBetween returns a new range that spans from the beginning of the
// start range to the end of the end range.
//
// The result is meaningless if the two ranges do not belong to the same
// source file or if the end range appears before the start range.
func RangeBetween(start, end Range) Range {
	return Range{
		Filename: start.Filename,
		Start:    start.Start,
		End:      end.End,
	}
}

// ContainsOffset returns true if and only if the given byte offset is within
// the receiving Range.
func (r Range) ContainsOffset(offset int) bool {
	return offset >= r.Start.Byte && offset < r.End.Byte
}

// String returns a compact string representation of the receiver.
// Callers should generally prefer to present a range more visually,
// e.g. via markers directly on the relevant portion of source code.
func (r Range) String() string {
	if r.Start.Line == r.End.Line {
		return fmt.Sprintf(
			"%s:%d,%d-%d",
			r.Filename,
			r.Start.Line, r.Start.Column,
			r.End.Column,
		)
	} else {
		return fmt.Sprintf(
			"%s:%d,%d-%d,%d",
			r.Filename,
			r.Start.Line, r.Start.Column,
			r.End.Line, r.End.Column,
		)
	}
}

// List returns the receiver wrapped in a single-element slice.
//
// This is provided as a convenience for building Diag structures which
// can have zero or more ranges, but often only one.
func (r Range) List() []Range {
	return []Range{r}
}
<|endoftext|>