<commit_before>/*
 * Copyright (c) 2012 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goon

import (
	"appengine"
	"appengine/datastore"
	"appengine/memcache"
	"bytes"
	"encoding/gob"
	"errors"
	"net/http"
	"reflect"
)

// Goon holds the app engine context and request memory cache.
type Goon struct {
	context       appengine.Context
	cache         map[string]*Entity
	inTransaction bool
	toSet         map[string]*Entity
	toDelete      []string
}

func memkey(k *datastore.Key) string {
	return k.String()
}

func NewGoon(r *http.Request) *Goon {
	return &Goon{
		context: appengine.NewContext(r),
		cache:   make(map[string]*Entity),
	}
}

// RunInTransaction runs f in a transaction. It calls f with a transaction
// context tg that f should use for all App Engine operations. Neither cache nor
// memcache are used or set during a transaction.
//
// Otherwise similar to appengine/datastore.RunInTransaction:
// https://developers.google.com/appengine/docs/go/datastore/reference#RunInTransaction
func (g *Goon) RunInTransaction(f func(tg *Goon) error, opts *datastore.TransactionOptions) error {
	var ng *Goon
	err := datastore.RunInTransaction(g.context, func(tc appengine.Context) error {
		ng = &Goon{
			context:       tc,
			inTransaction: true,
			toSet:         make(map[string]*Entity),
		}
		return f(ng)
	}, opts)

	if err == nil {
		for k, v := range ng.toSet {
			g.cache[k] = v
		}

		for _, k := range ng.toDelete {
			delete(g.cache, k)
		}
	}

	return err
}

// Put stores Entity e.
// If e has an incomplete key, it is updated.
func (g *Goon) Put(e *Entity) error {
	return g.PutMulti([]*Entity{e})
}

// PutMulti stores a sequence of Entities.
// Any entity with an incomplete key will be updated.
func (g *Goon) PutMulti(es []*Entity) error {
	var err error

	var memkeys []string
	keys := make([]*datastore.Key, len(es))
	src := make([]interface{}, len(es))

	for i, e := range es {
		if !e.Key.Incomplete() {
			memkeys = append(memkeys, e.memkey())
		}

		keys[i] = e.Key
		src[i] = e.Src
	}

	memcache.DeleteMulti(g.context, memkeys)

	keys, err = datastore.PutMulti(g.context, keys, src)

	if err != nil {
		return err
	}

	for i, e := range es {
		es[i].setKey(keys[i])

		if g.inTransaction {
			g.toSet[e.memkey()] = e
		}
	}

	if !g.inTransaction {
		g.putMemoryMulti(es)
	}

	return nil
}

func (g *Goon) putMemoryMulti(es []*Entity) {
	for _, e := range es {
		g.putMemory(e)
	}
}

func (g *Goon) putMemory(e *Entity) {
	g.cache[e.memkey()] = e
}

func (g *Goon) putMemcache(es []*Entity) error {
	items := make([]*memcache.Item, len(es))

	for i, e := range es {
		gob, err := e.gob()
		if err != nil {
			return err
		}

		items[i] = &memcache.Item{
			Key:   e.memkey(),
			Value: gob,
		}
	}

	err := memcache.SetMulti(g.context, items)

	if err != nil {
		return err
	}

	g.putMemoryMulti(es)
	return nil
}

// structKind returns the reflect.Kind name of src if it is a struct, else nil.
func structKind(src interface{}) (string, error) {
	v := reflect.ValueOf(src)
	v = reflect.Indirect(v)
	t := v.Type()
	k := t.Kind()

	if k == reflect.Struct {
		return t.Name(), nil
	}
	return "", errors.New("goon: src has invalid type")
}

// Get fetches an entity of kind src by.
// Refer to appengine/datastore.NewKey regarding key specification.
func (g *Goon) Get(src interface{}, stringID string, intID int64, parent *datastore.Key) (*Entity, error) {
	k, err := structKind(src)
	if err != nil {
		return nil, err
	}
	key := datastore.NewKey(g.context, k, stringID, intID, parent)
	return g.KeyGet(src, key)
}

// KeyGet fetches an entity of kind src by key.
func (g *Goon) KeyGet(src interface{}, key *datastore.Key) (*Entity, error) {
	e := NewEntity(key, src)
	es := []*Entity{e}
	err := g.GetMulti(es)
	if err != nil {
		return nil, err
	}
	return es[0], nil
}

// Get fetches a sequency of Entities, whose keys must already be valid.
// Entities with no correspending key have their NotFound field set to true.
func (g *Goon) GetMulti(es []*Entity) error {
	var dskeys []*datastore.Key
	var dst []interface{}
	var dixs []int

	if !g.inTransaction {
		var memkeys []string
		var mixs []int

		for i, e := range es {
			m := e.memkey()
			if s, present := g.cache[m]; present {
				es[i] = s
			} else {
				memkeys = append(memkeys, m)
				mixs = append(mixs, i)
			}
		}

		memvalues, err := memcache.GetMulti(g.context, memkeys)
		if err != nil {
			return err
		}

		for i, m := range memkeys {
			e := es[mixs[i]]
			if s, present := memvalues[m]; present {
				err := fromGob(e, s.Value)
				if err != nil {
					return err
				}

				g.putMemory(e)
			} else {
				dskeys = append(dskeys, e.Key)
				dst = append(dst, e.Src)
				dixs = append(dixs, mixs[i])
			}
		}
	} else {
		dskeys = make([]*datastore.Key, len(es))
		dst = make([]interface{}, len(es))
		dixs = make([]int, len(es))

		for i, e := range es {
			dskeys[i] = e.Key
			dst[i] = e.Src
			dixs[i] = i
		}
	}

	var merr appengine.MultiError
	err := datastore.GetMulti(g.context, dskeys, dst)
	if err != nil {
		merr = err.(appengine.MultiError)
	}
	var mes []*Entity

	for i, idx := range dixs {
		e := es[idx]
		if merr != nil && merr[i] != nil {
			e.NotFound = true
		}
		mes = append(mes, e)
	}

	if !g.inTransaction {
		err = g.putMemcache(mes)
		if err != nil {
			return err
		}
	}

	multiErr, any := make(appengine.MultiError, len(es)), false
	for i, e := range es {
		if e.NotFound {
			multiErr[i] = datastore.ErrNoSuchEntity
			any = true
		}
	}

	if any {
		return multiErr
	}

	return nil
}

func fromGob(e *Entity, b []byte) error {
	var buf bytes.Buffer
	_, _ = buf.Write(b)
	gob.Register(e.Src)
	dec := gob.NewDecoder(&buf)
	return dec.Decode(e)
}

// Delete deletes the entity for the given key.
func (g *Goon) Delete(key *datastore.Key) error {
	keys := []*datastore.Key{key}
	return g.DeleteMulti(keys)
}

// DeleteMulti is a batch version of Delete.
func (g *Goon) DeleteMulti(keys []*datastore.Key) error {
	memkeys := make([]string, len(keys))
	for i, k := range keys {
		mk := memkey(k)
		memkeys[i] = mk

		if g.inTransaction {
			g.toDelete = append(g.toDelete, mk)
		} else {
			delete(g.cache, mk)
		}
	}

	memcache.DeleteMulti(g.context, memkeys)

	return datastore.DeleteMulti(g.context, keys)
}
<commit_msg>Use the more common GetById name<commit_after>/*
 * Copyright (c) 2012 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goon

import (
	"appengine"
	"appengine/datastore"
	"appengine/memcache"
	"bytes"
	"encoding/gob"
	"errors"
	"net/http"
	"reflect"
)

// Goon holds the app engine context and request memory cache.
type Goon struct {
	context       appengine.Context
	cache         map[string]*Entity
	inTransaction bool
	toSet         map[string]*Entity
	toDelete      []string
}

func memkey(k *datastore.Key) string {
	return k.String()
}

func NewGoon(r *http.Request) *Goon {
	return &Goon{
		context: appengine.NewContext(r),
		cache:   make(map[string]*Entity),
	}
}

// RunInTransaction runs f in a transaction. It calls f with a transaction
// context tg that f should use for all App Engine operations. Neither cache nor
// memcache are used or set during a transaction.
//
// Otherwise similar to appengine/datastore.RunInTransaction:
// https://developers.google.com/appengine/docs/go/datastore/reference#RunInTransaction
func (g *Goon) RunInTransaction(f func(tg *Goon) error, opts *datastore.TransactionOptions) error {
	var ng *Goon
	err := datastore.RunInTransaction(g.context, func(tc appengine.Context) error {
		ng = &Goon{
			context:       tc,
			inTransaction: true,
			toSet:         make(map[string]*Entity),
		}
		return f(ng)
	}, opts)

	if err == nil {
		for k, v := range ng.toSet {
			g.cache[k] = v
		}

		for _, k := range ng.toDelete {
			delete(g.cache, k)
		}
	}

	return err
}

// Put stores Entity e.
// If e has an incomplete key, it is updated.
func (g *Goon) Put(e *Entity) error {
	return g.PutMulti([]*Entity{e})
}

// PutMulti stores a sequence of Entities.
// Any entity with an incomplete key will be updated.
func (g *Goon) PutMulti(es []*Entity) error {
	var err error

	var memkeys []string
	keys := make([]*datastore.Key, len(es))
	src := make([]interface{}, len(es))

	for i, e := range es {
		if !e.Key.Incomplete() {
			memkeys = append(memkeys, e.memkey())
		}

		keys[i] = e.Key
		src[i] = e.Src
	}

	memcache.DeleteMulti(g.context, memkeys)

	keys, err = datastore.PutMulti(g.context, keys, src)

	if err != nil {
		return err
	}

	for i, e := range es {
		es[i].setKey(keys[i])

		if g.inTransaction {
			g.toSet[e.memkey()] = e
		}
	}

	if !g.inTransaction {
		g.putMemoryMulti(es)
	}

	return nil
}

func (g *Goon) putMemoryMulti(es []*Entity) {
	for _, e := range es {
		g.putMemory(e)
	}
}

func (g *Goon) putMemory(e *Entity) {
	g.cache[e.memkey()] = e
}

func (g *Goon) putMemcache(es []*Entity) error {
	items := make([]*memcache.Item, len(es))

	for i, e := range es {
		gob, err := e.gob()
		if err != nil {
			return err
		}

		items[i] = &memcache.Item{
			Key:   e.memkey(),
			Value: gob,
		}
	}

	err := memcache.SetMulti(g.context, items)

	if err != nil {
		return err
	}

	g.putMemoryMulti(es)
	return nil
}

// structKind returns the reflect.Kind name of src if it is a struct, else nil.
func structKind(src interface{}) (string, error) {
	v := reflect.ValueOf(src)
	v = reflect.Indirect(v)
	t := v.Type()
	k := t.Kind()

	if k == reflect.Struct {
		return t.Name(), nil
	}
	return "", errors.New("goon: src has invalid type")
}

// GetById fetches an entity of kind src by id.
// Refer to appengine/datastore.NewKey regarding key specification.
func (g *Goon) GetById(src interface{}, stringID string, intID int64, parent *datastore.Key) (*Entity, error) {
	k, err := structKind(src)
	if err != nil {
		return nil, err
	}
	key := datastore.NewKey(g.context, k, stringID, intID, parent)
	return g.Get(src, key)
}

// Get fetches an entity of kind src by key.
func (g *Goon) Get(src interface{}, key *datastore.Key) (*Entity, error) {
	e := NewEntity(key, src)
	es := []*Entity{e}
	err := g.GetMulti(es)
	if err != nil {
		return nil, err
	}
	return es[0], nil
}

// Get fetches a sequency of Entities, whose keys must already be valid.
// Entities with no correspending key have their NotFound field set to true.
func (g *Goon) GetMulti(es []*Entity) error {
	var dskeys []*datastore.Key
	var dst []interface{}
	var dixs []int

	if !g.inTransaction {
		var memkeys []string
		var mixs []int

		for i, e := range es {
			m := e.memkey()
			if s, present := g.cache[m]; present {
				es[i] = s
			} else {
				memkeys = append(memkeys, m)
				mixs = append(mixs, i)
			}
		}

		memvalues, err := memcache.GetMulti(g.context, memkeys)
		if err != nil {
			return err
		}

		for i, m := range memkeys {
			e := es[mixs[i]]
			if s, present := memvalues[m]; present {
				err := fromGob(e, s.Value)
				if err != nil {
					return err
				}

				g.putMemory(e)
			} else {
				dskeys = append(dskeys, e.Key)
				dst = append(dst, e.Src)
				dixs = append(dixs, mixs[i])
			}
		}
	} else {
		dskeys = make([]*datastore.Key, len(es))
		dst = make([]interface{}, len(es))
		dixs = make([]int, len(es))

		for i, e := range es {
			dskeys[i] = e.Key
			dst[i] = e.Src
			dixs[i] = i
		}
	}

	var merr appengine.MultiError
	err := datastore.GetMulti(g.context, dskeys, dst)
	if err != nil {
		merr = err.(appengine.MultiError)
	}
	var mes []*Entity

	for i, idx := range dixs {
		e := es[idx]
		if merr != nil && merr[i] != nil {
			e.NotFound = true
		}
		mes = append(mes, e)
	}

	if !g.inTransaction {
		err = g.putMemcache(mes)
		if err != nil {
			return err
		}
	}

	multiErr, any := make(appengine.MultiError, len(es)), false
	for i, e := range es {
		if e.NotFound {
			multiErr[i] = datastore.ErrNoSuchEntity
			any = true
		}
	}

	if any {
		return multiErr
	}

	return nil
}

func fromGob(e *Entity, b []byte) error {
	var buf bytes.Buffer
	_, _ = buf.Write(b)
	gob.Register(e.Src)
	dec := gob.NewDecoder(&buf)
	return dec.Decode(e)
}

// Delete deletes the entity for the given key.
func (g *Goon) Delete(key *datastore.Key) error {
	keys := []*datastore.Key{key}
	return g.DeleteMulti(keys)
}

// DeleteMulti is a batch version of Delete.
func (g *Goon) DeleteMulti(keys []*datastore.Key) error {
	memkeys := make([]string, len(keys))
	for i, k := range keys {
		mk := memkey(k)
		memkeys[i] = mk

		if g.inTransaction {
			g.toDelete = append(g.toDelete, mk)
		} else {
			delete(g.cache, mk)
		}
	}

	memcache.DeleteMulti(g.context, memkeys)

	return datastore.DeleteMulti(g.context, keys)
}
<|endoftext|>


<commit_before>package greq

import (
	"bytes"
	"log"
	"net/http"
	"net/http/httputil"
	"sync"
)

// Request context object.
type Request struct {
	method  string
	rawurl  string
	header  http.Header
	body    []byte
	client  *http.Client
	cookies []*http.Cookie
	once    sync.Once

	responseHandler ResponseHandler
	requestHandler  RequestHandler

	debug bool
}

type (
	RequestMethod   func(*Request) (*http.Response, error)
	RequestHandler  func(*Request, RequestMethod) (*http.Response, error)
	ResponseHandler func(*http.Response, error) error
)

const (
	contentType = "Content-type"

	defaultPOSTContentType = "application/x-www-form-urlencoded"
)

var (
	Debug = false
)

// Set get method
func Get(rawurl string) *Request {
	return New("GET", rawurl)
}

// Set post method
func Post(rawurl string) *Request {
	return New("POST", rawurl).SetHeader(contentType, defaultPOSTContentType)
}

// Set put method
func Put(rawurl string) *Request {
	return New("PUT", rawurl)
}

// Set delete method
func Delete(rawurl string) *Request {
	return New("DELETE", rawurl)
}

// Create a new request object.
func New(method, rawurl string) *Request {
	req := &Request{}
	req.method = method
	req.rawurl = rawurl
	req.header = make(http.Header)
	req.debug = Debug
	return req
}

// Client returns current *http.Client
func (req *Request) Client() *http.Client {
	return req.client
}

// SetClient sets *http.Client
func (req *Request) SetClient(client http.Client) *Request {
	req.client = &client
	return req
}

// Header returns current http.Header.
func (req *Request) Header() http.Header {
	return req.header
}

// SetHeader sets key-values as request header.
func (req *Request) SetHeader(key string, values ...string) *Request {
	for i, value := range values {
		if i == 0 {
			req.header.Set(key, value)
		} else {
			req.header.Add(key, value)
		}
	}
	return req
}

// SetHeader adds key-values to request header.
func (req *Request) AddHeader(key string, values ...string) *Request {
	for _, value := range values {
		req.header.Add(key, value)
	}
	return req
}

// SetBody sets specified body as request body.
func (req *Request) SetBody(body []byte) *Request {
	req.body = body
	return req
}

// SetUseragent sets a specified string as request useragent.
func (req *Request) SetUseragent(value string) *Request {
	req.SetHeader("User-Agent", value)
	return req
}

// Do HTTP requests using itself parameters.
func (req *Request) Do() (*http.Response, error) {
	req.once.Do(func() {
		if req.client == nil {
			req.client = &(*http.DefaultClient)
		}
	})
	var (
		res *http.Response
		err error
	)
	rh := req.requestHandler
	if rh == nil {
		rh = defaultRequestHandler
	}
	if res, e := rh(req, func(req *Request) (*http.Response, error) {
		res, err = req.doReq(req.method, req.rawurl)
		if req.responseHandler != nil {
			err = req.responseHandler(res, err)
		}
		return res, err
	}); e != nil {
		return res, e
	}
	if err != nil {
		return res, err
	}
	return res, nil
}

// RequestHandler hooks an event which before sending request.
func (req *Request) RequestHandler(handler RequestHandler) *Request {
	req.requestHandler = handler
	return req
}

// ResponseHandler hooks an event which after sending request.
func (req *Request) ResponseHandler(handler ResponseHandler) *Request {
	req.responseHandler = handler
	return req
}

// AddCookie adds a cookie to request headers.
func (req *Request) AddCookie(cookie *http.Cookie) *Request {
	req.cookies = append(req.cookies, cookie)
	return req
}

func (req *Request) doReq(method, rawurl string) (*http.Response, error) {
	r, err := http.NewRequest(method, rawurl, bytes.NewBuffer(req.body))
	if err != nil {
		return nil, err
	}
	r.Header = req.header
	for _, c := range req.cookies {
		r.AddCookie(c)
	}

	if req.debug {
		dump, err := httputil.DumpRequest(r, true)
		if err != nil {
			log.Println(err)
		}
		log.Println(string(dump))
	}

	res, err := req.client.Do(r)
	if err != nil {
		return nil, err
	}
	return res, nil
}

// Type converter for string response body.
func (req *Request) String() (string, error) {
	return String(req.Do())
}

// Type converter for []byte response body.
func (req *Request) Bytes() ([]byte, error) {
	return Bytes(req.Do())
}

// JSON bind a response body to specified object.
func (req *Request) JSON(ptr interface{}) error {
	res, err := req.Do()
	return JSON(res, err, ptr)
}

// Give true argument, print debug log when do request.
func (req *Request) Debug(debug bool) *Request {
	req.debug = debug
	return req
}
<commit_msg>set default http client at the initialization of request.<commit_after>package greq

import (
	"bytes"
	"log"
	"net/http"
	"net/http/httputil"
)

// Request context object.
type Request struct {
	method  string
	rawurl  string
	header  http.Header
	body    []byte
	client  *http.Client
	cookies []*http.Cookie

	responseHandler ResponseHandler
	requestHandler  RequestHandler

	debug bool
}

type (
	RequestMethod   func(*Request) (*http.Response, error)
	RequestHandler  func(*Request, RequestMethod) (*http.Response, error)
	ResponseHandler func(*http.Response, error) error
)

const (
	contentType = "Content-type"

	defaultPOSTContentType = "application/x-www-form-urlencoded"
)

var (
	Debug = false
)

// Set get method
func Get(rawurl string) *Request {
	return New("GET", rawurl)
}

// Set post method
func Post(rawurl string) *Request {
	return New("POST", rawurl).SetHeader(contentType, defaultPOSTContentType)
}

// Set put method
func Put(rawurl string) *Request {
	return New("PUT", rawurl)
}

// Set delete method
func Delete(rawurl string) *Request {
	return New("DELETE", rawurl)
}

// Create a new request object.
func New(method, rawurl string) *Request {
	req := &Request{}
	req.method = method
	req.rawurl = rawurl
	req.header = make(http.Header)
	req.debug = Debug
	req.client = http.DefaultClient
	return req
}

// Client returns current *http.Client
func (req *Request) Client() *http.Client {
	return req.client
}

// SetClient sets *http.Client
func (req *Request) SetClient(client http.Client) *Request {
	req.client = &client
	return req
}

// Header returns current http.Header.
func (req *Request) Header() http.Header {
	return req.header
}

// SetHeader sets key-values as request header.
func (req *Request) SetHeader(key string, values ...string) *Request {
	for i, value := range values {
		if i == 0 {
			req.header.Set(key, value)
		} else {
			req.header.Add(key, value)
		}
	}
	return req
}

// SetHeader adds key-values to request header.
func (req *Request) AddHeader(key string, values ...string) *Request {
	for _, value := range values {
		req.header.Add(key, value)
	}
	return req
}

// SetBody sets specified body as request body.
func (req *Request) SetBody(body []byte) *Request {
	req.body = body
	return req
}

// SetUseragent sets a specified string as request useragent.
func (req *Request) SetUseragent(value string) *Request {
	req.SetHeader("User-Agent", value)
	return req
}

// Do HTTP requests using itself parameters.
func (req *Request) Do() (*http.Response, error) {
	var (
		res *http.Response
		err error
	)
	rh := req.requestHandler
	if rh == nil {
		rh = defaultRequestHandler
	}
	if res, e := rh(req, func(req *Request) (*http.Response, error) {
		res, err = req.doReq(req.method, req.rawurl)
		if req.responseHandler != nil {
			err = req.responseHandler(res, err)
		}
		return res, err
	}); e != nil {
		return res, e
	}
	if err != nil {
		return res, err
	}
	return res, nil
}

// RequestHandler hooks an event which before sending request.
func (req *Request) RequestHandler(handler RequestHandler) *Request {
	req.requestHandler = handler
	return req
}

// ResponseHandler hooks an event which after sending request.
func (req *Request) ResponseHandler(handler ResponseHandler) *Request {
	req.responseHandler = handler
	return req
}

// AddCookie adds a cookie to request headers.
func (req *Request) AddCookie(cookie *http.Cookie) *Request {
	req.cookies = append(req.cookies, cookie)
	return req
}

func (req *Request) doReq(method, rawurl string) (*http.Response, error) {
	r, err := http.NewRequest(method, rawurl, bytes.NewBuffer(req.body))
	if err != nil {
		return nil, err
	}
	r.Header = req.header
	for _, c := range req.cookies {
		r.AddCookie(c)
	}

	if req.debug {
		dump, err := httputil.DumpRequest(r, true)
		if err != nil {
			log.Println(err)
		}
		log.Println(string(dump))
	}

	res, err := req.client.Do(r)
	if err != nil {
		return nil, err
	}
	return res, nil
}

// Type converter for string response body.
func (req *Request) String() (string, error) {
	return String(req.Do())
}

// Type converter for []byte response body.
func (req *Request) Bytes() ([]byte, error) {
	return Bytes(req.Do())
}

// JSON bind a response body to specified object.
func (req *Request) JSON(ptr interface{}) error {
	res, err := req.Do()
	return JSON(res, err, ptr)
}

// Give true argument, print debug log when do request.
func (req *Request) Debug(debug bool) *Request {
	req.debug = debug
	return req
}
<|endoftext|>


<commit_before>package agent

import (
	"fmt"
	"github.com/hashicorp/consul/consul/structs"
	"net/http"
)

/*
* /v1/catalog/register : Registers a new service
* /v1/catalog/deregister : Deregisters a service or node
* /v1/catalog/datacenters : Lists known datacenters
* /v1/catalog/nodes : Lists nodes in a given DC
* /v1/catalog/services : Lists services in a given DC
* /v1/catalog/service/<service>/ : Lists the nodes in a given service
* /v1/catalog/node/<node>/ : Lists the services provided by a node
 */

func (s *HTTPServer) CatalogRegister(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
	var args structs.RegisterRequest
	if err := decodeBody(req, &args); err != nil {
		resp.WriteHeader(400)
		resp.Write([]byte(fmt.Sprintf("Request decode failed: %v", err)))
		return nil, nil
	}

	// Setup the default DC if not provided
	if args.Datacenter == "" {
		args.Datacenter = s.agent.config.Datacenter
	}
	s.logger.Printf("[DEBUG] ARGS: %#v %v %#v", args, args.Datacenter == "", s.agent.config)

	// Forward to the servers
	var out struct{}
	if err := s.agent.RPC("Catalog.Register", &args, &out); err != nil {
		return nil, err
	}
	return true, nil
}

func (s *HTTPServer) CatalogDatacenters(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
	var out []string
	if err := s.agent.RPC("Catalog.ListDatacenters", struct{}{}, &out); err != nil {
		return nil, err
	}
	return out, nil
}

func (s *HTTPServer) CatalogNodes(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
	// Set default DC
	dc := s.agent.config.Datacenter

	// Check for other DC
	if other := req.URL.Query().Get("dc"); other != "" {
		dc = other
	}

	var out structs.Nodes
	if err := s.agent.RPC("Catalog.ListNodes", dc, &out); err != nil {
		return nil, err
	}
	return out, nil
}
<commit_msg>Remove debug line<commit_after>package agent

import (
	"fmt"
	"github.com/hashicorp/consul/consul/structs"
	"net/http"
)

/*
* /v1/catalog/register : Registers a new service
* /v1/catalog/deregister : Deregisters a service or node
* /v1/catalog/datacenters : Lists known datacenters
* /v1/catalog/nodes : Lists nodes in a given DC
* /v1/catalog/services : Lists services in a given DC
* /v1/catalog/service/<service>/ : Lists the nodes in a given service
* /v1/catalog/node/<node>/ : Lists the services provided by a node
 */

func (s *HTTPServer) CatalogRegister(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
	var args structs.RegisterRequest
	if err := decodeBody(req, &args); err != nil {
		resp.WriteHeader(400)
		resp.Write([]byte(fmt.Sprintf("Request decode failed: %v", err)))
		return nil, nil
	}

	// Setup the default DC if not provided
	if args.Datacenter == "" {
		args.Datacenter = s.agent.config.Datacenter
	}

	// Forward to the servers
	var out struct{}
	if err := s.agent.RPC("Catalog.Register", &args, &out); err != nil {
		return nil, err
	}
	return true, nil
}

func (s *HTTPServer) CatalogDatacenters(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
	var out []string
	if err := s.agent.RPC("Catalog.ListDatacenters", struct{}{}, &out); err != nil {
		return nil, err
	}
	return out, nil
}

func (s *HTTPServer) CatalogNodes(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
	// Set default DC
	dc := s.agent.config.Datacenter

	// Check for other DC
	if other := req.URL.Query().Get("dc"); other != "" {
		dc = other
	}

	var out structs.Nodes
	if err := s.agent.RPC("Catalog.ListNodes", dc, &out); err != nil {
		return nil, err
	}
	return out, nil
}
<|endoftext|>


<commit_before>package grim

// Copyright 2015 MediaMath <http://www.mediamath.com>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

import "fmt"

// Instance models the state of a configured Grim instance.
type Instance struct {
	configRoot *string
	queue      *sqsQueue
}

// SetConfigRoot sets the base path of the configuration directory and clears any previously read config values from memory.
func (i *Instance) SetConfigRoot(path string) {
	i.configRoot = &path
	i.queue = nil
}

// PrepareGrimQueue creates or reuses the Amazon SQS queue named in the config.
func (i *Instance) PrepareGrimQueue() error {
	configRoot := getEffectiveConfigRoot(i.configRoot)

	config, err := getEffectiveGlobalConfig(configRoot)
	if err != nil {
		return fatalGrimErrorf("error while reading config: %v", err)
	}

	queue, err := prepareSQSQueue(config.awsKey, config.awsSecret, config.awsRegion, config.grimQueueName)
	if err != nil {
		return fatalGrimErrorf("error preparing queue: %v", err)
	}

	i.queue = queue

	return nil
}

// PrepareRepos discovers all repos that are configured then sets up SNS and GitHub.
// It is an error to call this without calling PrepareGrimQueue first.
func (i *Instance) PrepareRepos() error {
	if err := i.checkGrimQueue(); err != nil {
		return err
	}

	configRoot := getEffectiveConfigRoot(i.configRoot)

	config, err := getEffectiveGlobalConfig(configRoot)
	if err != nil {
		return fatalGrimErrorf("error while reading config: %v", err)
	}

	repos := getAllConfiguredRepos(configRoot)

	var topicARNs []string
	for _, repo := range repos {
		localConfig, err := getEffectiveConfig(configRoot, repo.owner, repo.name)

		snsTopicName := fmt.Sprintf("grim-%v-%v-repo-topic", repo.owner, repo.name)

		snsTopicARN, err := prepareSNSTopic(config.awsKey, config.awsSecret, config.awsRegion, snsTopicName)
		if err != nil {
			return fatalGrimErrorf("error creating SNS topic: %v", err)
		}

		err = prepareSubscription(config.awsKey, config.awsSecret, config.awsRegion, snsTopicARN, i.queue.ARN)
		if err != nil {
			return fatalGrimErrorf("error subscribing Grim queue %q to SNS topic %q: %v", i.queue.ARN, snsTopicARN, err)
		}

		err = prepareAmazonSNSService(localConfig.gitHubToken, repo.owner, repo.name, snsTopicARN, config.awsKey, config.awsSecret, config.awsRegion)
		if err != nil {
			return fatalGrimErrorf("error creating configuring GitHub AmazonSNS service: %v", err)
		}
		topicARNs = append(topicARNs, snsTopicARN)
	}

	err = setPolicy(config.awsKey, config.awsSecret, config.awsRegion, i.queue.ARN, i.queue.URL, topicARNs)
	if err != nil {
		return fatalGrimErrorf("error setting policy for Grim queue: %v", err)
	}

	return nil
}

// BuildNextInGrimQueue creates or reuses an SQS queue as a source of work.
func (i *Instance) BuildNextInGrimQueue() error {
	if err := i.checkGrimQueue(); err != nil {
		return err
	}

	configRoot := getEffectiveConfigRoot(i.configRoot)

	globalConfig, err := getEffectiveGlobalConfig(configRoot)
	if err != nil {
		return grimErrorf("error while reading config: %v", err)
	}

	message, err := getNextMessage(globalConfig.awsKey, globalConfig.awsSecret, globalConfig.awsRegion, i.queue.URL)
	if err != nil {
		return grimErrorf("error retrieving message from Grim queue %q: %v", i.queue.URL, err)
	}

	if message != "" {
		hook, err := extractHookEvent(message)
		if err != nil {
			return grimErrorf("error extracting hook from message: %v", err)
		}

		if !(hook.eventName == "push" || hook.eventName == "pull_request" && (hook.action == "opened" || hook.action == "reopened" || hook.action == "synchronize")) {
			return nil
		}

		if hook.eventName == "pull_request" {
			sha, err := pollForMergeCommitSha(globalConfig.gitHubToken, hook.owner, hook.repo, hook.prNumber)
			if err != nil {
				return grimErrorf("error getting merge commit sha: %v", err)
			} else if sha == "" {
				return grimErrorf("error getting merge commit sha: field empty")
			}
			hook.ref = sha
		}

		localConfig, err := getEffectiveConfig(configRoot, hook.owner, hook.repo)
		if err != nil {
			return grimErrorf("error while reading config: %v", err)
		}

		return buildForHook(configRoot, localConfig, *hook)
	}

	return nil
}

// BuildRef builds a git ref immediately.
func (i *Instance) BuildRef(owner, repo, ref string) error {
	configRoot := getEffectiveConfigRoot(i.configRoot)

	config, err := getEffectiveConfig(configRoot, owner, repo)
	if err != nil {
		return fatalGrimErrorf("error while reading config: %v", err)
	}

	return buildForHook(configRoot, config, hookEvent{
		owner: owner,
		repo:  repo,
		ref:   ref,
	})
}

func buildForHook(configRoot string, config *effectiveConfig, hook hookEvent) error {
	extraEnv := hook.env()

	// TODO: do something with the err
	notifyPending(config, hook)

	result, err := build(configRoot, config.workspaceRoot, config.pathToCloneIn, hook.owner, hook.repo, extraEnv)
	if err != nil {
		notifyError(config, hook)
		return fatalGrimErrorf("error during %v: %v", describeHook(hook), err)
	}

	var notifyError error
	if result.ExitCode == 0 {
		notifyError = notifySuccess(config, hook)
	} else {
		notifyError = notifyFailure(config, hook)
	}

	err = appendResult(config.resultRoot, hook.owner, hook.repo, *result)
	if err != nil {
		return fatalGrimErrorf("error while storing result: %v", err)
	}

	return notifyError
}

func describeHook(hook hookEvent) string {
	return fmt.Sprintf("build of %v/%v initiated by a %q to %q by %q", hook.owner, hook.repo, hook.eventName, hook.target, hook.userName)
}

func notifyPending(config *effectiveConfig, hook hookEvent) error {
	return notify(config, hook, RSPending, fmt.Sprintf("Starting %v", describeHook(hook)), ColorYellow)
}

func notifyError(config *effectiveConfig, hook hookEvent) error {
	return notify(config, hook, RSError, fmt.Sprintf("Error during %v", describeHook(hook)), ColorGray)
}

func notifyFailure(config *effectiveConfig, hook hookEvent) error {
	return notify(config, hook, RSFailure, fmt.Sprintf("Failure during %v", describeHook(hook)), ColorRed)
}

func notifySuccess(config *effectiveConfig, hook hookEvent) error {
	return notify(config, hook, RSSuccess, fmt.Sprintf("Success after %v", describeHook(hook)), ColorGreen)
}

func notify(config *effectiveConfig, hook hookEvent, state refStatus, message string, color messageColor) error {
	if hook.eventName != "push" && hook.eventName != "pull_request" {
		return nil
	}

	//add grimServerID/grimQueueName to hipchat message
	message += "ServerID:" + config.grimServerID

	ghErr := setRefStatus(config.gitHubToken, hook.owner, hook.repo, hook.statusRef, state, "", message)

	if config.hipChatToken != "" && config.hipChatRoom != "" {
		err := sendMessageToRoom(config.hipChatToken, config.hipChatRoom, "Grim", message, color)
		if err != nil {
			return err
		}
	}

	return ghErr
}

func (i *Instance) checkGrimQueue() error {
	if i.queue == nil {
		return fatalGrimErrorf("the Grim queue must be prepared first")
	}

	return nil
}
<commit_msg>grim local test<commit_after>package grim

// Copyright 2015 MediaMath <http://www.mediamath.com>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

import "fmt"

// Instance models the state of a configured Grim instance.
type Instance struct {
	configRoot *string
	queue      *sqsQueue
}

// SetConfigRoot sets the base path of the configuration directory and clears any previously read config values from memory.
func (i *Instance) SetConfigRoot(path string) {
	i.configRoot = &path
	i.queue = nil
}

// PrepareGrimQueue creates or reuses the Amazon SQS queue named in the config.
func (i *Instance) PrepareGrimQueue() error {
	configRoot := getEffectiveConfigRoot(i.configRoot)

	config, err := getEffectiveGlobalConfig(configRoot)
	if err != nil {
		return fatalGrimErrorf("error while reading config: %v", err)
	}

	queue, err := prepareSQSQueue(config.awsKey, config.awsSecret, config.awsRegion, config.grimQueueName)
	if err != nil {
		return fatalGrimErrorf("error preparing queue: %v", err)
	}

	i.queue = queue

	return nil
}

// PrepareRepos discovers all repos that are configured then sets up SNS and GitHub.
// It is an error to call this without calling PrepareGrimQueue first.
func (i *Instance) PrepareRepos() error {
	if err := i.checkGrimQueue(); err != nil {
		return err
	}

	configRoot := getEffectiveConfigRoot(i.configRoot)

	config, err := getEffectiveGlobalConfig(configRoot)
	if err != nil {
		return fatalGrimErrorf("error while reading config: %v", err)
	}

	repos := getAllConfiguredRepos(configRoot)

	var topicARNs []string
	for _, repo := range repos {
		localConfig, err := getEffectiveConfig(configRoot, repo.owner, repo.name)

		snsTopicName := fmt.Sprintf("grim-%v-%v-repo-topic", repo.owner, repo.name)

		snsTopicARN, err := prepareSNSTopic(config.awsKey, config.awsSecret, config.awsRegion, snsTopicName)
		if err != nil {
			return fatalGrimErrorf("error creating SNS topic: %v", err)
		}

		err = prepareSubscription(config.awsKey, config.awsSecret, config.awsRegion, snsTopicARN, i.queue.ARN)
		if err != nil {
			return fatalGrimErrorf("error subscribing Grim queue %q to SNS topic %q: %v", i.queue.ARN, snsTopicARN, err)
		}

		err = prepareAmazonSNSService(localConfig.gitHubToken, repo.owner, repo.name, snsTopicARN, config.awsKey, config.awsSecret, config.awsRegion)
		if err != nil {
			return fatalGrimErrorf("error creating configuring GitHub AmazonSNS service: %v", err)
		}
		topicARNs = append(topicARNs, snsTopicARN)
	}

	err = setPolicy(config.awsKey, config.awsSecret, config.awsRegion, i.queue.ARN, i.queue.URL, topicARNs)
	if err != nil {
		return fatalGrimErrorf("error setting policy for Grim queue: %v", err)
	}

	return nil
}

// BuildNextInGrimQueue creates or reuses an SQS queue as a source of work.
func (i *Instance) BuildNextInGrimQueue() error {
	if err := i.checkGrimQueue(); err != nil {
		return err
	}

	configRoot := getEffectiveConfigRoot(i.configRoot)

	globalConfig, err := getEffectiveGlobalConfig(configRoot)
	if err != nil {
		return grimErrorf("error while reading config: %v", err)
	}

	message, err := getNextMessage(globalConfig.awsKey, globalConfig.awsSecret, globalConfig.awsRegion, i.queue.URL)
	if err != nil {
		return grimErrorf("error retrieving message from Grim queue %q: %v", i.queue.URL, err)
	}

	if message != "" {
		hook, err := extractHookEvent(message)
		if err != nil {
			return grimErrorf("error extracting hook from message: %v", err)
		}

		if !(hook.eventName == "push" || hook.eventName == "pull_request" && (hook.action == "opened" || hook.action == "reopened" || hook.action == "synchronize")) {
			return nil
		}

		if hook.eventName == "pull_request" {
			sha, err := pollForMergeCommitSha(globalConfig.gitHubToken, hook.owner, hook.repo, hook.prNumber)
			if err != nil {
				return grimErrorf("error getting merge commit sha: %v", err)
			} else if sha == "" {
				return grimErrorf("error getting merge commit sha: field empty")
			}
			hook.ref = sha
		}

		localConfig, err := getEffectiveConfig(configRoot, hook.owner, hook.repo)
		if err != nil {
			return grimErrorf("error while reading config: %v", err)
		}

		return buildForHook(configRoot, localConfig, *hook)
	}

	return nil
}

// BuildRef builds a git ref immediately.
func (i *Instance) BuildRef(owner, repo, ref string) error {
	configRoot := getEffectiveConfigRoot(i.configRoot)

	config, err := getEffectiveConfig(configRoot, owner, repo)
	if err != nil {
		return fatalGrimErrorf("error while reading config: %v", err)
	}

	return buildForHook(configRoot, config, hookEvent{
		owner: owner,
		repo:  repo,
		ref:   ref,
	})
}

func buildForHook(configRoot string, config *effectiveConfig, hook hookEvent) error {
	extraEnv := hook.env()

	// TODO: do something with the err
	notifyPending(config, hook)

	result, err := build(configRoot, config.workspaceRoot, config.pathToCloneIn, hook.owner, hook.repo, extraEnv)
	if err != nil {
		notifyError(config, hook)
		return fatalGrimErrorf("error during %v: %v", describeHook(hook), err)
	}

	var notifyError error
	if result.ExitCode == 0 {
		notifyError = notifySuccess(config, hook)
	} else {
		notifyError = notifyFailure(config, hook)
	}

	err = appendResult(config.resultRoot, hook.owner, hook.repo, *result)
	if err != nil {
		return fatalGrimErrorf("error while storing result: %v", err)
	}

	return notifyError
}

func describeHook(hook hookEvent) string {
	return fmt.Sprintf("build of %v/%v initiated by a %q to %q by %q", hook.owner, hook.repo, hook.eventName, hook.target, hook.userName)
}

func notifyPending(config *effectiveConfig, hook hookEvent) error {
	return notify(config, hook, RSPending, fmt.Sprintf("Starting %v", describeHook(hook)), ColorYellow)
}

func notifyError(config *effectiveConfig, hook hookEvent) error {
	return notify(config, hook, RSError, fmt.Sprintf("Error during %v", describeHook(hook)), ColorGray)
}

func notifyFailure(config *effectiveConfig, hook hookEvent) error {
	return notify(config, hook, RSFailure, fmt.Sprintf("Failure during %v", describeHook(hook)), ColorRed)
}

func notifySuccess(config *effectiveConfig, hook hookEvent) error {
	return notify(config, hook, RSSuccess, fmt.Sprintf("Success after %v", describeHook(hook)), ColorGreen)
}

func notify(config *effectiveConfig, hook hookEvent, state refStatus, message string, color messageColor) error {
	if hook.eventName != "push" && hook.eventName != "pull_request" {
		return nil
	}

	//add grimServerID/grimQueueName to hipchat message test
	message += "ServerID:" + config.grimServerID

	ghErr := setRefStatus(config.gitHubToken, hook.owner, hook.repo, hook.statusRef, state, "", message)

	if config.hipChatToken != "" && config.hipChatRoom != "" {
		err := sendMessageToRoom(config.hipChatToken, config.hipChatRoom, "Grim", message, color)
		if err != nil {
			return err
		}
	}

	return ghErr
}

func (i *Instance) checkGrimQueue() error {
	if i.queue == nil {
		return fatalGrimErrorf("the Grim queue must be prepared first")
	}

	return nil
}
<|endoftext|>


<commit_before>package grok

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
)

var (
	valid    = regexp.MustCompile(`^\w+([-.]\w+)*(:([-.\w]+)(:(string|float|int))?)?$`)
	normal   = regexp.MustCompile(`%{([\w-.]+(?::[\w-.]+(?::[\w-.]+)?)?)}`)
	symbolic = regexp.MustCompile(`\W`)
)

// A Config structure is used to configure a Grok parser.
type Config struct {
	NamedCapturesOnly   bool
	SkipDefaultPatterns bool
	RemoveEmptyValues   bool
	PatternsDir         []string
	Patterns            map[string]string
}

// Grok object us used to load patterns and deconstruct strings using those
// patterns.
type Grok struct {
	rawPattern       map[string]string
	config           *Config
	aliases          map[string]string
	compiledPatterns map[string]*gRegexp
	patterns         map[string]*gPattern
	patternsGuard    *sync.RWMutex
	compiledGuard    *sync.RWMutex
}

type gPattern struct {
	expression string
	typeInfo   semanticTypes
}

type gRegexp struct {
	regexp   *regexp.Regexp
	typeInfo semanticTypes
}

type semanticTypes map[string]string

// New returns a Grok object.
func New() (*Grok, error) {
	return NewWithConfig(&Config{})
}

// NewWithConfig returns a Grok object that is configured to behave according
// to the supplied Config structure.
func NewWithConfig(config *Config) (*Grok, error) {
	g := &Grok{
		config:           config,
		aliases:          map[string]string{},
		compiledPatterns: map[string]*gRegexp{},
		patterns:         map[string]*gPattern{},
		rawPattern:       map[string]string{},
		patternsGuard:    new(sync.RWMutex),
		compiledGuard:    new(sync.RWMutex),
	}

	if !config.SkipDefaultPatterns {
		err := g.AddPatternsFromMap(patterns)
		if err != nil {
			return nil, err
		}
	}

	if len(config.PatternsDir) > 0 {
		for _, path := range config.PatternsDir {
			err := g.AddPatternsFromPath(path)
			if err != nil {
				return nil, err
			}
		}

	}

	if err := g.AddPatternsFromMap(config.Patterns); err != nil {
		return nil, err
	}

	return g, nil
}

// AddPattern adds a new pattern to the list of loaded patterns.
func (g *Grok) addPattern(name, pattern string) error {
	dnPattern, ti, err := g.denormalizePattern(pattern, g.patterns)
	if err != nil {
		return err
	}

	g.patterns[name] = &gPattern{expression: dnPattern, typeInfo: ti}
	return nil
}

// AddPattern adds a named pattern to grok
func (g *Grok) AddPattern(name, pattern string) error {
	g.patternsGuard.Lock()
	defer g.patternsGuard.Unlock()

	g.rawPattern[name] = pattern
	return g.buildPatterns()
}

// AddPatternsFromMap loads a map of named patterns
func (g *Grok) AddPatternsFromMap(m map[string]string) error {
	g.patternsGuard.Lock()
	defer g.patternsGuard.Unlock()

	for name, pattern := range m {
		g.rawPattern[name] = pattern
	}
	return g.buildPatterns()
}

// AddPatternsFromMap adds new patterns from the specified map to the list of
// loaded patterns.
func (g *Grok) addPatternsFromMap(m map[string]string) error {
	patternDeps := graph{}
	for k, v := range m {
		keys := []string{}
		for _, key := range normal.FindAllStringSubmatch(v, -1) {
			if !valid.MatchString(key[1]) {
				return fmt.Errorf("invalid pattern %%{%s}", key[1])
			}
			names := strings.Split(key[1], ":")
			syntax := names[0]
			if g.patterns[syntax] == nil {
				if _, ok := m[syntax]; !ok {
					return fmt.Errorf("no pattern found for %%{%s}", syntax)
				}
			}
			keys = append(keys, syntax)
		}
		patternDeps[k] = keys
	}
	order, _ := sortGraph(patternDeps)
	for _, key := range reverseList(order) {
		err := g.addPattern(key, m[key])
		if err != nil {
			return fmt.Errorf("cannot add pattern %q: %v", key, err)
		}
	}

	return nil
}

// AddPatternsFromPath adds new patterns from the files in the specified
// directory to the list of loaded patterns.
func (g *Grok) AddPatternsFromPath(path string) error {
	if fi, err := os.Stat(path); err == nil {
		if fi.IsDir() {
			path = path + "/*"
		}
	} else {
		return fmt.Errorf("invalid path : %s", path)
	}

	// only one error can be raised, when pattern is malformed
	// pattern is hard-coded "/*" so we ignore err
	files, _ := filepath.Glob(path)

	var filePatterns = map[string]string{}
	for _, fileName := range files {
		file, err := os.Open(fileName)
		if err != nil {
			return err
		}

		scanner := bufio.NewScanner(bufio.NewReader(file))

		for scanner.Scan() {
			l := scanner.Text()
			if len(l) > 0 && l[0] != '#' {
				names := strings.SplitN(l, " ", 2)
				filePatterns[names[0]] = names[1]
			}
		}

		file.Close()
	}

	return g.AddPatternsFromMap(filePatterns)
}

// Match returns true if the specified text matches the pattern.
func (g *Grok) Match(pattern, text string) (bool, error) {
	gr, err := g.compile(pattern)
	if err != nil {
		return false, err
	}

	if ok := gr.regexp.MatchString(text); !ok {
		return false, nil
	}

	return true, nil
}

// compiledParse parses the specified text and returns a map with the results.
func (g *Grok) compiledParse(gr *gRegexp, text string) (map[string]string, error) {
	captures := make(map[string]string)
	if match := gr.regexp.FindStringSubmatch(text); len(match) > 0 {
		for i, name := range gr.regexp.SubexpNames() {
			if name != "" {
				if g.config.RemoveEmptyValues && match[i] == "" {
					continue
				}
				name = g.nameToAlias(name)
				captures[name] = match[i]
			}
		}
	}

	return captures, nil
}

// Parse the specified text and return a map with the results.
func (g *Grok) Parse(pattern, text string) (map[string]string, error) {
	gr, err := g.compile(pattern)
	if err != nil {
		return nil, err
	}

	return g.compiledParse(gr, text)
}

// ParseTyped returns a interface{} map with typed captured fields based on provided pattern over the text
func (g *Grok) ParseTyped(pattern string, text string) (map[string]interface{}, error) {
	gr, err := g.compile(pattern)
	if err != nil {
		return nil, err
	}
	match := gr.regexp.FindStringSubmatch(text)
	captures := make(map[string]interface{})
	if len(match) > 0 {
		for i, segmentName := range gr.regexp.SubexpNames() {
			if len(segmentName) != 0 {
				if g.config.RemoveEmptyValues == true && match[i] == "" {
					continue
				}
				name := g.nameToAlias(segmentName)
				if segmentType, ok := gr.typeInfo[name]; ok {
					switch segmentType {
					case "int":
						captures[name], _ = strconv.Atoi(match[i])
					case "float":
						captures[name], _ = strconv.ParseFloat(match[i], 64)
					default:
						return nil, fmt.Errorf("ERROR the value %s cannot be converted to %s", match[i], segmentType)
					}
				} else {
					captures[name] = match[i]
				}
			}

		}
	}

	return captures, nil
}

// ParseToMultiMap parses the specified text and returns a map with the
// results. Values are stored in an string slice, so values from captures with
// the same name don't get overridden.
func (g *Grok) ParseToMultiMap(pattern, text string) (map[string][]string, error) {
	gr, err := g.compile(pattern)
	if err != nil {
		return nil, err
	}

	captures := make(map[string][]string)
	if match := gr.regexp.FindStringSubmatch(text); len(match) > 0 {
		for i, name := range gr.regexp.SubexpNames() {
			if name != "" {
				if g.config.RemoveEmptyValues == true && match[i] == "" {
					continue
				}
				name = g.nameToAlias(name)
				captures[name] = append(captures[name], match[i])
			}
		}
	}

	return captures, nil
}

func (g *Grok) buildPatterns() error {
	g.patterns = map[string]*gPattern{}
	return g.addPatternsFromMap(g.rawPattern)
}

func (g *Grok) compile(pattern string) (*gRegexp, error) {
	g.compiledGuard.RLock()
	gr, ok := g.compiledPatterns[pattern]
	g.compiledGuard.RUnlock()

	if ok {
		return gr, nil
	}

	g.patternsGuard.RLock()
	newPattern, ti, err := g.denormalizePattern(pattern, g.patterns)
	g.patternsGuard.RUnlock()
	if err != nil {
		return nil, err
	}

	compiledRegex, err := regexp.Compile(newPattern)
	if err != nil {
		return nil, err
	}
	gr = &gRegexp{regexp: compiledRegex, typeInfo: ti}

	g.compiledGuard.Lock()
	g.compiledPatterns[pattern] = gr
	g.compiledGuard.Unlock()

	return gr, nil
}

func (g *Grok) denormalizePattern(pattern string, storedPatterns map[string]*gPattern) (string, semanticTypes, error) {
	ti := semanticTypes{}
	for _, values := range normal.FindAllStringSubmatch(pattern, -1) {
		if !valid.MatchString(values[1]) {
			return "", ti, fmt.Errorf("invalid pattern %%{%s}", values[1])
		}
		names := strings.Split(values[1], ":")

		syntax, semantic, alias := names[0], names[0], names[0]
		if len(names) > 1 {
			semantic = names[1]
			alias = g.aliasizePatternName(semantic)
		}

		// Add type cast information only if type set, and not string
		if len(names) == 3 {
			if names[2] != "string" {
				ti[semantic] = names[2]
			}
		}

		storedPattern, ok := storedPatterns[syntax]
		if !ok {
			return "", ti, fmt.Errorf("no pattern found for %%{%s}", syntax)
		}

		var buffer bytes.Buffer
		if !g.config.NamedCapturesOnly || (g.config.NamedCapturesOnly && len(names) > 1) {
			buffer.WriteString("(?P<")
			buffer.WriteString(alias)
			buffer.WriteString(">")
			buffer.WriteString(storedPattern.expression)
			buffer.WriteString(")")
		} else {
			buffer.WriteString("(")
			buffer.WriteString(storedPattern.expression)
			buffer.WriteString(")")
		}

		//Merge type Informations
		for k, v := range storedPattern.typeInfo {
			//Lastest type information is the one to keep in memory
			if _, ok := ti[k]; !ok {
				ti[k] = v
			}
		}

		pattern = strings.Replace(pattern, values[0], buffer.String(), -1)
	}

	return pattern, ti, nil

}

func (g *Grok) aliasizePatternName(name string) string {
	alias := symbolic.ReplaceAllString(name, "_")
	g.aliases[alias] = name
	return alias
}

func (g *Grok) nameToAlias(name string) string {
	alias, ok := g.aliases[name]
	if ok {
		return alias
	}
	return name
}

// ParseStream will match the given pattern on a line by line basis from the reader
// and apply the results to the process function
func (g *Grok) ParseStream(reader *bufio.Reader, pattern string, process func(map[string]string) error) error {
	gr, err := g.compile(pattern)
	if err != nil {
		return err
	}
	for {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
		values, err := g.compiledParse(gr, line)
		if err != nil {
			return err
		}
		if err = process(values); err != nil {
			return err
		}
	}
}
<commit_msg>minor type fixes<commit_after>package grok

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
)

var (
	valid    = regexp.MustCompile(`^\w+([-.]\w+)*(:([-.\w]+)(:(string|float|int))?)?$`)
	normal   = regexp.MustCompile(`%{([\w-.]+(?::[\w-.]+(?::[\w-.]+)?)?)}`)
	symbolic = regexp.MustCompile(`\W`)
)

// A Config structure is used to configure a Grok parser.
type Config struct {
	NamedCapturesOnly   bool
	SkipDefaultPatterns bool
	RemoveEmptyValues   bool
	PatternsDir         []string
	Patterns            map[string]string
}

// Grok object us used to load patterns and deconstruct strings using those
// patterns.
type Grok struct {
	rawPattern       map[string]string
	config           *Config
	aliases          map[string]string
	compiledPatterns map[string]*gRegexp
	patterns         map[string]*gPattern
	patternsGuard    *sync.RWMutex
	compiledGuard    *sync.RWMutex
}

type gPattern struct {
	expression string
	typeInfo   semanticTypes
}

type gRegexp struct {
	regexp   *regexp.Regexp
	typeInfo semanticTypes
}

type semanticTypes map[string]string

// New returns a Grok object.
func New() (*Grok, error) {
	return NewWithConfig(&Config{})
}

// NewWithConfig returns a Grok object that is configured to behave according
// to the supplied Config structure.
func NewWithConfig(config *Config) (*Grok, error) {
	g := &Grok{
		config:           config,
		aliases:          map[string]string{},
		compiledPatterns: map[string]*gRegexp{},
		patterns:         map[string]*gPattern{},
		rawPattern:       map[string]string{},
		patternsGuard:    new(sync.RWMutex),
		compiledGuard:    new(sync.RWMutex),
	}

	if !config.SkipDefaultPatterns {
		err := g.AddPatternsFromMap(patterns)
		if err != nil {
			return nil, err
		}
	}

	if len(config.PatternsDir) > 0 {
		for _, path := range config.PatternsDir {
			err := g.AddPatternsFromPath(path)
			if err != nil {
				return nil, err
			}
		}

	}

	if err := g.AddPatternsFromMap(config.Patterns); err != nil {
		return nil, err
	}

	return g, nil
}

// AddPattern adds a new pattern to the list of loaded patterns.
func (g *Grok) addPattern(name, pattern string) error {
	dnPattern, ti, err := g.denormalizePattern(pattern, g.patterns)
	if err != nil {
		return err
	}

	g.patterns[name] = &gPattern{expression: dnPattern, typeInfo: ti}
	return nil
}

// AddPattern adds a named pattern to grok
func (g *Grok) AddPattern(name, pattern string) error {
	g.patternsGuard.Lock()
	defer g.patternsGuard.Unlock()

	g.rawPattern[name] = pattern
	return g.buildPatterns()
}

// AddPatternsFromMap loads a map of named patterns
func (g *Grok) AddPatternsFromMap(m map[string]string) error {
	g.patternsGuard.Lock()
	defer g.patternsGuard.Unlock()

	for name, pattern := range m {
		g.rawPattern[name] = pattern
	}
	return g.buildPatterns()
}

// AddPatternsFromMap adds new patterns from the specified map to the list of
// loaded patterns.
func (g *Grok) addPatternsFromMap(m map[string]string) error {
	patternDeps := graph{}
	for k, v := range m {
		var keys []string
		for _, key := range normal.FindAllStringSubmatch(v, -1) {
			if !valid.MatchString(key[1]) {
				return fmt.Errorf("invalid pattern %%{%s}", key[1])
			}
			names := strings.Split(key[1], ":")
			syntax := names[0]
			if g.patterns[syntax] == nil {
				if _, ok := m[syntax]; !ok {
					return fmt.Errorf("no pattern found for %%{%s}", syntax)
				}
			}
			keys = append(keys, syntax)
		}
		patternDeps[k] = keys
	}
	order, _ := sortGraph(patternDeps)
	for _, key := range reverseList(order) {
		err := g.addPattern(key, m[key])
		if err != nil {
			return fmt.Errorf("cannot add pattern %q: %v", key, err)
		}
	}

	return nil
}

// AddPatternsFromPath adds new patterns from the files in the specified
// directory to the list of loaded patterns.
func (g *Grok) AddPatternsFromPath(path string) error {
	if fi, err := os.Stat(path); err == nil {
		if fi.IsDir() {
			path = path + "/*"
		}
	} else {
		return fmt.Errorf("invalid path : %s", path)
	}

	// only one error can be raised, when pattern is malformed
	// pattern is hard-coded "/*" so we ignore err
	files, _ := filepath.Glob(path)

	var filePatterns = map[string]string{}
	for _, fileName := range files {
		file, err := os.Open(fileName)
		if err != nil {
			return err
		}

		scanner := bufio.NewScanner(bufio.NewReader(file))

		for scanner.Scan() {
			l := scanner.Text()
			if len(l) > 0 && l[0] != '#' {
				names := strings.SplitN(l, " ", 2)
				filePatterns[names[0]] = names[1]
			}
		}

		_ = file.Close()
	}

	return g.AddPatternsFromMap(filePatterns)
}

// Match returns true if the specified text matches the pattern.
func (g *Grok) Match(pattern, text string) (bool, error) {
	gr, err := g.compile(pattern)
	if err != nil {
		return false, err
	}

	if ok := gr.regexp.MatchString(text); !ok {
		return false, nil
	}

	return true, nil
}

// compiledParse parses the specified text and returns a map with the results.
func (g *Grok) compiledParse(gr *gRegexp, text string) (map[string]string, error) {
	captures := make(map[string]string)
	if match := gr.regexp.FindStringSubmatch(text); len(match) > 0 {
		for i, name := range gr.regexp.SubexpNames() {
			if name != "" {
				if g.config.RemoveEmptyValues && match[i] == "" {
					continue
				}
				name = g.nameToAlias(name)
				captures[name] = match[i]
			}
		}
	}

	return captures, nil
}

// Parse the specified text and return a map with the results.
func (g *Grok) Parse(pattern, text string) (map[string]string, error) {
	gr, err := g.compile(pattern)
	if err != nil {
		return nil, err
	}

	return g.compiledParse(gr, text)
}

// ParseTyped returns a interface{} map with typed captured fields based on provided pattern over the text
func (g *Grok) ParseTyped(pattern string, text string) (map[string]interface{}, error) {
	gr, err := g.compile(pattern)
	if err != nil {
		return nil, err
	}
	match := gr.regexp.FindStringSubmatch(text)
	captures := make(map[string]interface{})
	if len(match) > 0 {
		for i, segmentName := range gr.regexp.SubexpNames() {
			if len(segmentName) != 0 {
				if g.config.RemoveEmptyValues == true && match[i] == "" {
					continue
				}
				name := g.nameToAlias(segmentName)
				if segmentType, ok := gr.typeInfo[name]; ok {
					switch segmentType {
					case "int":
						captures[name], _ = strconv.Atoi(match[i])
					case "float":
						captures[name], _ = strconv.ParseFloat(match[i], 64)
					default:
						return nil, fmt.Errorf("ERROR the value %s cannot be converted to %s", match[i], segmentType)
					}
				} else {
					captures[name] = match[i]
				}
			}

		}
	}

	return captures, nil
}

// ParseToMultiMap parses the specified text and returns a map with the
// results. Values are stored in an string slice, so values from captures with
// the same name don't get overridden.
func (g *Grok) ParseToMultiMap(pattern, text string) (map[string][]string, error) {
	gr, err := g.compile(pattern)
	if err != nil {
		return nil, err
	}

	captures := make(map[string][]string)
	if match := gr.regexp.FindStringSubmatch(text); len(match) > 0 {
		for i, name := range gr.regexp.SubexpNames() {
			if name != "" {
				if g.config.RemoveEmptyValues == true && match[i] == "" {
					continue
				}
				name = g.nameToAlias(name)
				captures[name] = append(captures[name], match[i])
			}
		}
	}

	return captures, nil
}

func (g *Grok) buildPatterns() error {
	g.patterns = map[string]*gPattern{}
	return g.addPatternsFromMap(g.rawPattern)
}

func (g *Grok) compile(pattern string) (*gRegexp, error) {
	g.compiledGuard.RLock()
	gr, ok := g.compiledPatterns[pattern]
	g.compiledGuard.RUnlock()

	if ok {
		return gr, nil
	}

	g.patternsGuard.RLock()
	newPattern, ti, err := g.denormalizePattern(pattern, g.patterns)
	g.patternsGuard.RUnlock()
	if err != nil {
		return nil, err
	}

	compiledRegex, err := regexp.Compile(newPattern)
	if err != nil {
		return nil, err
	}
	gr = &gRegexp{regexp: compiledRegex, typeInfo: ti}

	g.compiledGuard.Lock()
	g.compiledPatterns[pattern] = gr
	g.compiledGuard.Unlock()

	return gr, nil
}

func (g *Grok) denormalizePattern(pattern string, storedPatterns map[string]*gPattern) (string, semanticTypes, error) {
	ti := semanticTypes{}
	for _, values := range normal.FindAllStringSubmatch(pattern, -1) {
		if !valid.MatchString(values[1]) {
			return "", ti, fmt.Errorf("invalid pattern %%{%s}", values[1])
		}
		names := strings.Split(values[1], ":")

		syntax, semantic, alias := names[0], names[0], names[0]
		if len(names) > 1 {
			semantic = names[1]
			alias = g.aliasizePatternName(semantic)
		}

		// Add type cast information only if type set, and not string
		if len(names) == 3 {
			if names[2] != "string" {
				ti[semantic] = names[2]
			}
		}

		storedPattern, ok := storedPatterns[syntax]
		if !ok {
			return "", ti, fmt.Errorf("no pattern found for %%{%s}", syntax)
		}

		var buffer bytes.Buffer
		if !g.config.NamedCapturesOnly || (g.config.NamedCapturesOnly && len(names) > 1) {
			buffer.WriteString("(?P<")
			buffer.WriteString(alias)
			buffer.WriteString(">")
			buffer.WriteString(storedPattern.expression)
			buffer.WriteString(")")
		} else {
			buffer.WriteString("(")
			buffer.WriteString(storedPattern.expression)
			buffer.WriteString(")")
		}

		//Merge type Informations
		for k, v := range storedPattern.typeInfo {
			//Latest type information is the one to keep in memory
			if _, ok := ti[k]; !ok {
				ti[k] = v
			}
		}

		pattern = strings.Replace(pattern, values[0], buffer.String(), -1)
	}

	return pattern, ti, nil

}

func (g *Grok) aliasizePatternName(name string) string {
	alias := symbolic.ReplaceAllString(name, "_")
	g.aliases[alias] = name
	return alias
}

func (g *Grok) nameToAlias(name string) string {
	alias, ok := g.aliases[name]
	if ok {
		return alias
	}
	return name
}

// ParseStream will match the given pattern on a line by line basis from the reader
// and apply the results to the process function
func (g *Grok) ParseStream(reader *bufio.Reader, pattern string, process func(map[string]string) error) error {
	gr, err := g.compile(pattern)
	if err != nil {
		return err
	}
	for {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
		values, err := g.compiledParse(gr, line)
		if err != nil {
			return err
		}
		if err = process(values); err != nil {
			return err
		}
	}
}
<|endoftext|>


<commit_before>package boleto

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"html/template"

	"github.com/boombuler/barcode"
	"github.com/boombuler/barcode/twooffive"

	"image/jpeg"

	"bitbucket.org/mundipagg/boletoapi/models"
	"bitbucket.org/mundipagg/boletoapi/tmpl"
)

const templateBoleto = `

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">

    {{if eq .Format "html"}}

            <button class="no-print btnDefault print" onclick="window.print()">

                &nbspImprimir
            </button>
            <button class="no-print btnDefault print" onclick="window.location='./boleto?fmt=pdf&id={{.ID}}'">

                &nbspGerar PDF
            </button>

    {{end}}
    {{template "boletoForm" .}}

	{{template "boletoForm" .}}

`

const boletoForm = `
{{define "boletoForm"}}

                    {{.BankLogo}}

                {{.BankNumber}}
                {{fmtDigitableLine .DigitableLine}}

                    Local de Pagamento

                    ATÉ O VENCIMENTO EM QUALQUER BANCO OU CORRESPONDENTE NÃO BANCÁRIO, APÓS O VENCIMENTO, PAGUE EM QUALQUER BANCO OU CORRESPONDENTE NÃO BANCÁRIO

                    Data de Vencimento

{{.Boleto.Title.ExpireDateTime | brdate}}

                    Nome do Beneficiário / CNPJ / CPF / Endereço:

                            {{.Boleto.Recipient.Name}}
                            {{.Boleto.Recipient.Document.Type}} {{fmtDoc .Boleto.Recipient.Document}}

                    {{.Boleto.Recipient.Address.Street}},
                    {{.Boleto.Recipient.Address.Number}} -
                    {{.Boleto.Recipient.Address.District}},
                    {{.Boleto.Recipient.Address.StateCode}} -
                    {{.Boleto.Recipient.Address.ZipCode}}

                    Agência/Código Beneficiário

{{.Boleto.Agreement.Agency}}/{{.Boleto.Agreement.Account}}-{{.Boleto.Agreement.AccountDigit}}

                    Data do Documento

{{today | brdate}}

                    Num. do Documento

{{.Boleto.Title.DocumentNumber}}

                    Espécie doc

DM

                    Aceite

N

                    Data Processamento

{{today | brdate}}

                    Carteira/Nosso Número

17/{{.Boleto.Title.OurNumber}}

                    Uso do Banco

                    Carteira

17

                    Espécie

R$

                    Quantidade

N

                    Valor

{{fmtNumber .Boleto.Title.AmountInCents}}

                    (=) Valor do Documento

{{fmtNumber .Boleto.Title.AmountInCents}}

                    Instruções de responsabilidade do BENEFICIÁRIO. Qualquer dúvida sobre este boleto contate o beneficiário.

{{.Boleto.Title.Instructions}}

                    (-) Descontos/Abatimento

                    (+) Juros/Multa

                    (=) Valor Pago

                            Nome do Pagador:  {{.Boleto.Buyer.Name}}
                            CNPJ/CPF:  {{fmtDoc .Boleto.Buyer.Document}}

                            Endereço:  {{.Boleto.Buyer.Address.Street}} {{.Boleto.Buyer.Address.Number}}, {{.Boleto.Buyer.Address.District}} - {{.Boleto.Buyer.Address.City}}, {{.Boleto.Buyer.Address.StateCode}} - {{.Boleto.Buyer.Address.ZipCode}}

                            Sacador/Avalista:
                            CNPJ/CPF:

	{{end}}
`

//HTML renderiza HTML do boleto
func HTML(boleto models.BoletoView, format string) string {
	b := tmpl.New()
	boleto.BankLogo = template.HTML(logoBB)
	boleto.Format = format
	bcode, _ := twooffive.Encode(boleto.Barcode, true)
	orgBounds := bcode.Bounds()
	orgWidth := orgBounds.Max.X - orgBounds.Min.X
	img, _ := barcode.Scale(bcode, orgWidth, 50)
	buf := new(bytes.Buffer)
	err := jpeg.Encode(buf, img, nil)
	boleto.Barcode64 = base64.StdEncoding.EncodeToString(buf.Bytes())
	s, err := b.From(boleto).To(templateBoleto).Transform(boletoForm)
	if err != nil {
		fmt.Println(err)
	}
	return s
}
<commit_msg>:art: Coloca css como https<commit_after>package boleto

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"html/template"

	"github.com/boombuler/barcode"
	"github.com/boombuler/barcode/twooffive"

	"image/jpeg"

	"bitbucket.org/mundipagg/boletoapi/models"
	"bitbucket.org/mundipagg/boletoapi/tmpl"
)

const templateBoleto = `

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">

    {{if eq .Format "html"}}

            <button class="no-print btnDefault print" onclick="window.print()">

                &nbspImprimir
            </button>
            <button class="no-print btnDefault print" onclick="window.location='./boleto?fmt=pdf&id={{.ID}}'">

                &nbspGerar PDF
            </button>

    {{end}}
    {{template "boletoForm" .}}

	{{template "boletoForm" .}}

`

const boletoForm = `
{{define "boletoForm"}}

                    {{.BankLogo}}

                {{.BankNumber}}
                {{fmtDigitableLine .DigitableLine}}

                    Local de Pagamento

                    ATÉ O VENCIMENTO EM QUALQUER BANCO OU CORRESPONDENTE NÃO BANCÁRIO, APÓS O VENCIMENTO, PAGUE EM QUALQUER BANCO OU CORRESPONDENTE NÃO BANCÁRIO

                    Data de Vencimento

{{.Boleto.Title.ExpireDateTime | brdate}}

                    Nome do Beneficiário / CNPJ / CPF / Endereço:

                            {{.Boleto.Recipient.Name}}
                            {{.Boleto.Recipient.Document.Type}} {{fmtDoc .Boleto.Recipient.Document}}

                    {{.Boleto.Recipient.Address.Street}},
                    {{.Boleto.Recipient.Address.Number}} -
                    {{.Boleto.Recipient.Address.District}},
                    {{.Boleto.Recipient.Address.StateCode}} -
                    {{.Boleto.Recipient.Address.ZipCode}}

                    Agência/Código Beneficiário

{{.Boleto.Agreement.Agency}}/{{.Boleto.Agreement.Account}}-{{.Boleto.Agreement.AccountDigit}}

                    Data do Documento

{{today | brdate}}

                    Num. do Documento

{{.Boleto.Title.DocumentNumber}}

                    Espécie doc

DM

                    Aceite

N

                    Data Processamento

{{today | brdate}}

                    Carteira/Nosso Número

17/{{.Boleto.Title.OurNumber}}

                    Uso do Banco

                    Carteira

17

                    Espécie

R$

                    Quantidade

N

                    Valor

{{fmtNumber .Boleto.Title.AmountInCents}}

                    (=) Valor do Documento

{{fmtNumber .Boleto.Title.AmountInCents}}

                    Instruções de responsabilidade do BENEFICIÁRIO. Qualquer dúvida sobre este boleto contate o beneficiário.

{{.Boleto.Title.Instructions}}

                    (-) Descontos/Abatimento

                    (+) Juros/Multa

                    (=) Valor Pago

                            Nome do Pagador:  {{.Boleto.Buyer.Name}}
                            CNPJ/CPF:  {{fmtDoc .Boleto.Buyer.Document}}

                            Endereço:  {{.Boleto.Buyer.Address.Street}} {{.Boleto.Buyer.Address.Number}}, {{.Boleto.Buyer.Address.District}} - {{.Boleto.Buyer.Address.City}}, {{.Boleto.Buyer.Address.StateCode}} - {{.Boleto.Buyer.Address.ZipCode}}

                            Sacador/Avalista:
                            CNPJ/CPF:

	{{end}}
`

//HTML renderiza HTML do boleto
func HTML(boleto models.BoletoView, format string) string {
	b := tmpl.New()
	boleto.BankLogo = template.HTML(logoBB)
	boleto.Format = format
	bcode, _ := twooffive.Encode(boleto.Barcode, true)
	orgBounds := bcode.Bounds()
	orgWidth := orgBounds.Max.X - orgBounds.Min.X
	img, _ := barcode.Scale(bcode, orgWidth, 50)
	buf := new(bytes.Buffer)
	err := jpeg.Encode(buf, img, nil)
	boleto.Barcode64 = base64.StdEncoding.EncodeToString(buf.Bytes())
	s, err := b.From(boleto).To(templateBoleto).Transform(boletoForm)
	if err != nil {
		fmt.Println(err)
	}
	return s
}
<|endoftext|>


<commit_before>package parser_test

import (
	"testing"

	"github.com/TailorDev/msw/parser"
)

func TestParse(t *testing.T) {
	issue, err := parser.Parse("../fixtures/2016-10-13.yml")
	if err != nil {
		t.Fatalf("TestParse: %s", err)
	}

	if issue.Number != 123 {
		t.Fatalf("Expected 123, got %d", issue.Number)
	}

	if issue.WelcomeText != "Hello, World!\n" {
		t.Fatalf("Expected 'Hello, World!\\n', got %s", issue.WelcomeText)
	}

	if len(issue.Categories) != 1 {
		t.Fatalf("Expected 3 categories, got: %d", len(issue.Categories))
	}

	if title := issue.Categories[0].Title; title != "Cat. 1" {
		t.Fatalf("Expected 'Cat. 1', got: %s", title)
	}

	if nbLinks := len(issue.Categories[0].Links); nbLinks != 1 {
		t.Fatalf("Expected no links, got: %d", nbLinks)
	}

	link := issue.Categories[0].Links[0]

	if link.Name != "Link #1" {
		t.Fatalf("Expected 'Link #1', got: %s", link.Name)
	}

	if link.URL != "http://example.org" {
		t.Fatalf("Expected 'http://example.org', got: %s", link.URL)
	}

	if link.Abstract != "This is the abstract of the first link.\n" {
		t.Fatalf("Expected 'This is the abstract of the first link.\\n', got: %s", link.Abstract)
	}
}
<commit_msg>Add a test to check date parsing<commit_after>package parser_test

import (
	"testing"

	"github.com/TailorDev/msw/parser"
)

func TestParse(t *testing.T) {
	issue, err := parser.Parse("../fixtures/2016-10-13.yml")
	if err != nil {
		t.Fatalf("TestParse: %s", err)
	}

	if issue.Number != 123 {
		t.Fatalf("Expected 123, got %d", issue.Number)
	}

	if issue.Date.Format("2006-01-02") != "2016-10-13" {
		t.Fatalf("Expected 2016-10-13, got %s", issue.Date)
	}

	if issue.WelcomeText != "Hello, World!\n" {
		t.Fatalf("Expected 'Hello, World!\\n', got %s", issue.WelcomeText)
	}

	if len(issue.Categories) != 1 {
		t.Fatalf("Expected 3 categories, got: %d", len(issue.Categories))
	}

	if title := issue.Categories[0].Title; title != "Cat. 1" {
		t.Fatalf("Expected 'Cat. 1', got: %s", title)
	}

	if nbLinks := len(issue.Categories[0].Links); nbLinks != 1 {
		t.Fatalf("Expected no links, got: %d", nbLinks)
	}

	link := issue.Categories[0].Links[0]

	if link.Name != "Link #1" {
		t.Fatalf("Expected 'Link #1', got: %s", link.Name)
	}

	if link.URL != "http://example.org" {
		t.Fatalf("Expected 'http://example.org', got: %s", link.URL)
	}

	if link.Abstract != "This is the abstract of the first link.\n" {
		t.Fatalf("Expected 'This is the abstract of the first link.\\n', got: %s", link.Abstract)
	}
}
<|endoftext|>


<commit_before>package adngo

import (
	"bytes"
	"encoding/base64"
	"net/http"
	"net/url"
	"strings"
)

const (
	baseURI = "https://alpha-api.app.net/"
	authURI = "https://account.app.net/oauth/"
)

type Scopes []string

func (s *Scopes) Spaced() string {
	return strings.Join(s, " ")
}

func (s *Scopes) String() string {
	return strings.Join(s, ",")
}

type App struct {
	clientId     string
	clientSecret string
	accessToken  string
	RedirectURI  string
	Scopes       Scopes
}

var httpClient = &http.Client{}

func (a *App) Do(method, url, bodyType string, data Values) (resp *Response, err error) {
	req := http.NewRequest(method, url, bytes.NewBufferString(data.Encode()))

	if a.accessToken != "" {
		req.Header.Add("Authorization", "Bearer "+a.accessToken)
	}
	if bodyType != "" {
		req.Header.Add("Content-Type", bodyType)
	}

	return httpClient.Do(req)
}

func (a *App) Get(url, bodyType string) (resp *Response, err error) {
	return a.Do("GET", url, bodyType, url.Values{})
}

func (a *App) Post(url string, bodyType string, data Values) (resp *Response, err error) {
	return a.Do("POST", url, bodyType, data)
}

func (a *App) Put(url string, bodyType string, data Values) (resp *Response, err error) {
	return a.Do("PUT", url, bodyType, data)
}

func (a *App) Patch(url string, bodyType string, data Values) (resp *Response, err error) {
	return a.Do("PATCH", url, bodyType, data)
}

func (a *App) Delete(url string) (resp *Response, err error) {
	return a.Do("DELETE", url, bodyType, url.Values{})
}

func (a *App) VerifyToken(delegate bool) {
	if delegate {
		auth := []byte(a.clientId + ":" + a.clientSecret)
		req := http.NewRequest("GET", baseURI+"stream/0/token", nil)
		req.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString(auth))
		req.Header.Add("Identity-Delegate-Token", "True")

		resp, err := httpClient.Do(req)
	} else {
		resp, err := a.Get(baseURI+"stream/0/token", "application/json")
	}
}

func (a *App) AuthURI(clientSide, appStore bool) {
	data := url.Values{}
	data.Add("client_id", a.clientId)
	data.Add("redirect_uri", a.RedirectURI)
	data.Add("scope", a.Scopes.String())

	if clientSide {
		data.Add("response_type", "token")
	} else {
		data.Add("response_type", "code")
	}
	if appStore {
		data.Add("adnview", "appstore")
	}

	return authURI + "authenticate?" + data.Encode()
}

func (a *App) GetAccessToken(code string, app bool) {
	if app {
		data := url.Values{}
		data.Add("client_id", a.clientId)
		data.Add("client_secret", a.clientSecret)
		data.Add("grant_type", "client_credentials")

		resp, err := a.Post(authURI+"access_token", "", data)
	}
}

func (a *App) ProcessText(text string) {
	data := url.Values{}
	data.Add("text", text)

	resp, err := a.Post(baseURI+"stream/0/text/process", "", data)
}
<commit_msg>Just enough to test that the basic pieces work. Can pull a Config Object from App.Net.<commit_after>package adngo

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"log"
	"net/http"
	"net/url"
	"strings"
)

// Our API Urls
const (
	baseURI = "https://alpha-api.app.net/"
	authURI = "https://account.app.net/oauth/"
)

// This is our scopes struct to check for that.
type Scopes []string

func (s *Scopes) Spaced() string {
	return strings.Join(s, " ")
}

func (s *Scopes) String() string {
	return strings.Join(s, ",")
}

type App struct {
	clientId     string
	clientSecret string
	accessToken  string
	RedirectURI  string
	Scopes       Scopes
}

var httpClient = &http.Client{}

func (a *App) do(method, url, bodyType string, data Values) (resp *Response, err error) {
	if data == nil {
		req := http.NewRequest(method, url, nil)
	} else {
		req := http.NewRequest(method, url, bytes.NewBufferString(data.Encode()))
	}

	if a.accessToken != "" {
		req.Header.Add("Authorization", "Bearer "+a.accessToken)
	}
	if bodyType != "" {
		req.Header.Add("Content-Type", bodyType)
	}

	return httpClient.do(req)
}

func (a *App) get(url, bodyType string) (resp *Response, err error) {
	return a.do("GET", url, bodyType, nil)
}

func (a *App) post(url string, bodyType string, data Values) (resp *Response, err error) {
	return a.do("POST", url, bodyType, data)
}

func (a *App) put(url string, bodyType string, data Values) (resp *Response, err error) {
	return a.do("PUT", url, bodyType, data)
}

func (a *App) patch(url string, bodyType string, data Values) (resp *Response, err error) {
	return a.do("PATCH", url, bodyType, data)
}

func (a *App) delete(url string) (resp *Response, err error) {
	return a.do("DELETE", url, bodyType, nil)
}

// Do we even need this??
func (a *App) VerifyToken(delegate bool) {
	if delegate {
		auth := []byte(a.clientId + ":" + a.clientSecret)
		req := http.NewRequest("GET", baseURI+"stream/0/token", nil)
		req.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString(auth))
		req.Header.Add("Identity-Delegate-Token", "True")

		resp, err := httpClient.Do(req)
	} else {
		resp, err := a.get(baseURI+"stream/0/token", "application/json")
	}
}

func (a *App) AuthURI(clientSide, appStore bool) {
	data := url.Values{}
	data.Add("client_id", a.clientId)
	data.Add("redirect_uri", a.RedirectURI)
	data.Add("scope", a.Scopes.String())

	if clientSide {
		data.Add("response_type", "token")
	} else {
		data.Add("response_type", "code")
	}
	if appStore {
		data.Add("adnview", "appstore")
	}

	return authURI + "authenticate?" + data.Encode()
}

func (a *App) GetAccessToken(code string, app bool) {
	if app {
		data := url.Values{}
		data.Add("client_id", a.clientId)
		data.Add("client_secret", a.clientSecret)
		data.Add("grant_type", "client_credentials")

		resp, err := a.post(authURI+"access_token", "", data)
	}
}

func (a *App) ProcessText(text string) {
	data := url.Values{}
	data.Add("text", text)

	resp, err := a.post(baseURI+"stream/0/text/process", "", data)
}

// Retrieves the App.Net Configuration Object
func (a *App) GetConfig() {
	resp, err := a.get(baseURI+"stream/0/config", "application/json")
	if err != nil {
		log.Fatal(err)
	}

	var config interface{}
	err = json.Unmarshal(resp, &config)
	if err != nil {
		log.Fatal(err)
	}
	log.Print(config["meta"]["code"])
	return config
}
<|endoftext|>


<commit_before>package drivers

import (
	"bytes"
	"context"
	"encoding/binary"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/sys/unix"
	log "gopkg.in/inconshreveable/log15.v2"
)

var fanotifyLoaded bool

type fanotify struct {
	common

	fd int
}

type fanotifyEventInfoHeader struct {
	InfoType uint8
	Pad      uint8
	Len      uint16
}

type fanotifyEventInfoFid struct {
	fanotifyEventInfoHeader
	FSID uint64
}

func (d *fanotify) load(ctx context.Context) error {
	if fanotifyLoaded {
		return nil
	}

	var err error

	d.fd, err = unix.FanotifyInit(unix.FAN_CLOEXEC|unix.FAN_REPORT_DFID_NAME, unix.O_CLOEXEC)
	if err != nil {
		return fmt.Errorf("Failed to initialize fanotify: %w", err)
	}

	err = unix.FanotifyMark(d.fd, unix.FAN_MARK_ADD|unix.FAN_MARK_FILESYSTEM, unix.FAN_CREATE|unix.FAN_DELETE|unix.FAN_ONDIR, unix.AT_FDCWD, d.prefixPath)
	if err != nil {
		unix.Close(d.fd)
		return fmt.Errorf("Failed to watch directory %q: %w", d.prefixPath, err)
	}

	fd, err := unix.Open(d.prefixPath, unix.O_DIRECTORY|unix.O_RDONLY|unix.O_CLOEXEC, 0)
	if err != nil {
		unix.Close(d.fd)
		return fmt.Errorf("Failed to open directory %q: %w", d.prefixPath, err)
	}

	go func() {
		for {
			select {
			case <-ctx.Done():
				unix.Close(d.fd)
				fanotifyLoaded = false
				return
			}
		}
	}()

	go d.getEvents(fd)

	fanotifyLoaded = true

	return nil
}

func (d *fanotify) getEvents(mountFd int) {
	for {
		buf := make([]byte, 256)

		// Although the event is less than 256 bytes, we read as much to ensure the entire event
		// is captured and following events are readable. Using only binary.Read() would require
		// more manual cleanup as otherwise bytes from a previous event would still be present and
		// make everything unreadable.
		_, err := unix.Read(d.fd, buf)
		if err != nil {
			// Stop listening for events as the fanotify fd has been closed due to cleanup.
			if errors.Is(err, unix.EBADF) {
				unix.Close(mountFd)
				return
			}

			d.logger.Error("Failed to read event", log.Ctx{"err": err})
			continue
		}

		rd := bytes.NewReader(buf)

		event := unix.FanotifyEventMetadata{}

		err = binary.Read(rd, binary.LittleEndian, &event)
		if err != nil {
			d.logger.Error("Failed to read event metadata", log.Ctx{"err": err})
			continue
		}

		// Read event info fid
		fid := fanotifyEventInfoFid{}

		err = binary.Read(rd, binary.LittleEndian, &fid)
		if err != nil {
			d.logger.Error("Failed to read event fid", log.Ctx{"err": err})
			continue
		}

		// Although unix.FileHandle exists, it cannot be used with binary.Read() as the
		// variables inside are not exported.
		type fileHandleInfo struct {
			Bytes uint32
			Type  int32
		}

		// Read file handle information
		fhInfo := fileHandleInfo{}

		err = binary.Read(rd, binary.LittleEndian, &fhInfo)
		if err != nil {
			d.logger.Error("Failed to read file handle info", log.Ctx{"err": err})
			continue
		}

		// Read file handle
		fileHandle := make([]byte, fhInfo.Bytes)

		err = binary.Read(rd, binary.LittleEndian, fileHandle)
		if err != nil {
			d.logger.Error("Failed to read file handle", log.Ctx{"err": err})
			continue
		}

		fh := unix.NewFileHandle(fhInfo.Type, fileHandle)

		fd, err := unix.OpenByHandleAt(mountFd, fh, 0)
		if err != nil {
			d.logger.Error("Failed to open file", log.Ctx{"err": err})
			continue
		}
		unix.CloseOnExec(fd)

		// Determine the directory of the created or deleted file.
		target, err := os.Readlink(fmt.Sprintf("/proc/self/fd/%d", fd))
		if err != nil {
			d.logger.Error("Failed to read symlink", log.Ctx{"err": err})
			continue
		}
		unix.Close(fd)

		// If the target file has been deleted, the returned value might contain a " (deleted)" suffix.
		// This needs to be removed.
		target = strings.TrimSuffix(target, " (deleted)")

		// The file handle is followed by a null terminated string that identifies the
		// created/deleted directory entry name.
		sb := strings.Builder{}
		sb.WriteString(target + "/")

		for {
			b, err := rd.ReadByte()
			if err != nil || b == 0 {
				break
			}

			err = sb.WriteByte(b)
			if err != nil {
				break
			}
		}

		eventPath := filepath.Clean(sb.String())

		// Check whether there's a watch on a specific file or directory.
		d.mu.Lock()
		for path := range d.watches {
			if eventPath != path {
				continue
			}

			var action Event

			if event.Mask&unix.FAN_CREATE != 0 {
				action = Add
			} else if event.Mask&unix.FAN_DELETE != 0 || event.Mask&unix.FAN_DELETE_SELF != 0 {
				action = Remove
			}

			for identifier, f := range d.watches[path] {
				ret := f(path, action.String())
				if !ret {
					delete(d.watches[path], identifier)

					if len(d.watches[path]) == 0 {
						delete(d.watches, path)
					}
				}
			}

			break
		}
		d.mu.Unlock()
	}
}
<commit_msg>lxd/fsmonitor/drivers: Ignore stale file handle errors.<commit_after>package drivers

import (
	"bytes"
	"context"
	"encoding/binary"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/sys/unix"
	log "gopkg.in/inconshreveable/log15.v2"
)

var fanotifyLoaded bool

type fanotify struct {
	common

	fd int
}

type fanotifyEventInfoHeader struct {
	InfoType uint8
	Pad      uint8
	Len      uint16
}

type fanotifyEventInfoFid struct {
	fanotifyEventInfoHeader
	FSID uint64
}

func (d *fanotify) load(ctx context.Context) error {
	if fanotifyLoaded {
		return nil
	}

	var err error

	d.fd, err = unix.FanotifyInit(unix.FAN_CLOEXEC|unix.FAN_REPORT_DFID_NAME, unix.O_CLOEXEC)
	if err != nil {
		return fmt.Errorf("Failed to initialize fanotify: %w", err)
	}

	err = unix.FanotifyMark(d.fd, unix.FAN_MARK_ADD|unix.FAN_MARK_FILESYSTEM, unix.FAN_CREATE|unix.FAN_DELETE|unix.FAN_ONDIR, unix.AT_FDCWD, d.prefixPath)
	if err != nil {
		unix.Close(d.fd)
		return fmt.Errorf("Failed to watch directory %q: %w", d.prefixPath, err)
	}

	fd, err := unix.Open(d.prefixPath, unix.O_DIRECTORY|unix.O_RDONLY|unix.O_CLOEXEC, 0)
	if err != nil {
		unix.Close(d.fd)
		return fmt.Errorf("Failed to open directory %q: %w", d.prefixPath, err)
	}

	go func() {
		for {
			select {
			case <-ctx.Done():
				unix.Close(d.fd)
				fanotifyLoaded = false
				return
			}
		}
	}()

	go d.getEvents(fd)

	fanotifyLoaded = true

	return nil
}

func (d *fanotify) getEvents(mountFd int) {
	for {
		buf := make([]byte, 256)

		// Although the event is less than 256 bytes, we read as much to ensure the entire event
		// is captured and following events are readable. Using only binary.Read() would require
		// more manual cleanup as otherwise bytes from a previous event would still be present and
		// make everything unreadable.
		_, err := unix.Read(d.fd, buf)
		if err != nil {
			// Stop listening for events as the fanotify fd has been closed due to cleanup.
			if errors.Is(err, unix.EBADF) {
				unix.Close(mountFd)
				return
			}

			d.logger.Error("Failed to read event", log.Ctx{"err": err})
			continue
		}

		rd := bytes.NewReader(buf)

		event := unix.FanotifyEventMetadata{}

		err = binary.Read(rd, binary.LittleEndian, &event)
		if err != nil {
			d.logger.Error("Failed to read event metadata", log.Ctx{"err": err})
			continue
		}

		// Read event info fid
		fid := fanotifyEventInfoFid{}

		err = binary.Read(rd, binary.LittleEndian, &fid)
		if err != nil {
			d.logger.Error("Failed to read event fid", log.Ctx{"err": err})
			continue
		}

		// Although unix.FileHandle exists, it cannot be used with binary.Read() as the
		// variables inside are not exported.
		type fileHandleInfo struct {
			Bytes uint32
			Type  int32
		}

		// Read file handle information
		fhInfo := fileHandleInfo{}

		err = binary.Read(rd, binary.LittleEndian, &fhInfo)
		if err != nil {
			d.logger.Error("Failed to read file handle info", log.Ctx{"err": err})
			continue
		}

		// Read file handle
		fileHandle := make([]byte, fhInfo.Bytes)

		err = binary.Read(rd, binary.LittleEndian, fileHandle)
		if err != nil {
			d.logger.Error("Failed to read file handle", log.Ctx{"err": err})
			continue
		}

		fh := unix.NewFileHandle(fhInfo.Type, fileHandle)

		fd, err := unix.OpenByHandleAt(mountFd, fh, 0)
		if err != nil {
			errno := err.(unix.Errno)
			if errno != unix.ESTALE {
				d.logger.Error("Failed to open file", log.Ctx{"err": err})
			}
			continue
		}
		unix.CloseOnExec(fd)

		// Determine the directory of the created or deleted file.
		target, err := os.Readlink(fmt.Sprintf("/proc/self/fd/%d", fd))
		if err != nil {
			d.logger.Error("Failed to read symlink", log.Ctx{"err": err})
			continue
		}
		unix.Close(fd)

		// If the target file has been deleted, the returned value might contain a " (deleted)" suffix.
		// This needs to be removed.
		target = strings.TrimSuffix(target, " (deleted)")

		// The file handle is followed by a null terminated string that identifies the
		// created/deleted directory entry name.
		sb := strings.Builder{}
		sb.WriteString(target + "/")

		for {
			b, err := rd.ReadByte()
			if err != nil || b == 0 {
				break
			}

			err = sb.WriteByte(b)
			if err != nil {
				break
			}
		}

		eventPath := filepath.Clean(sb.String())

		// Check whether there's a watch on a specific file or directory.
		d.mu.Lock()
		for path := range d.watches {
			if eventPath != path {
				continue
			}

			var action Event

			if event.Mask&unix.FAN_CREATE != 0 {
				action = Add
			} else if event.Mask&unix.FAN_DELETE != 0 || event.Mask&unix.FAN_DELETE_SELF != 0 {
				action = Remove
			}

			for identifier, f := range d.watches[path] {
				ret := f(path, action.String())
				if !ret {
					delete(d.watches[path], identifier)

					if len(d.watches[path]) == 0 {
						delete(d.watches, path)
					}
				}
			}

			break
		}
		d.mu.Unlock()
	}
}
<|endoftext|>


<commit_before>package windows

import (
  "time"
  "strconv"
  "github.com/mattn/go-gtk/gtk"
  "ghighlighter/models"
)

type GhMainWindow struct {
  *gtk.GtkWindow
  highlights *models.GhHighlights
}

func (window *GhMainWindow) build() {
  window.SetTitle("ghighlights")
  window.Connect("destroy", gtk.MainQuit)

  mainVBox := gtk.VBox(false, 1)

  menubar := window.buildMenuBar()
  mainVBox.PackStart(menubar, false, false, 0)

  scrolledTextViewWindow := gtk.ScrolledWindow(nil, nil)
  scrolledTextViewWindow.SetPolicy(gtk.GTK_POLICY_AUTOMATIC, gtk.GTK_POLICY_AUTOMATIC)

  textView := gtk.TextView()
  textView.SetSizeRequest(600, 100)
  scrolledTextViewWindow.Add(textView)

  scrolledTextViewWindow.SetSizeRequest(600, 100)
  mainVBox.Add(scrolledTextViewWindow)

  readingHBox := gtk.HBox(false, 10)
  pageNumberEntry := gtk.Entry()
  pageTotalEntry := gtk.Entry()

  readingsComboBox := gtk.ComboBoxText()
  readings := models.Readings()
  for _, reading := range readings.Items {
    readingsComboBox.AppendText(reading.Title)
  }
  readingsComboBox.SetActive(0)
  readingsComboBox.Connect("changed", func() {
    reading:= readings.FindByTitle(readingsComboBox.GetActiveText())
    pageNumberEntry.SetText("0")
    pageTotalEntry.SetText(strconv.Itoa(reading.TotalPages))
  })
  align := gtk.Alignment(1, 1, 1, 0)
  align.Add(readingsComboBox)
  readingHBox.Add(align)

  pageHBox := gtk.HBox(false, 1)
  pageHBox.Add(gtk.Label("Page"))

  pageNumberEntry.SetAlignment(1)
  pageNumberEntry.SetWidthChars(4)
  pageNumberEntry.SetText("0")
  pageHBox.Add(pageNumberEntry)

  pageHBox.Add(gtk.Label("of"))

  pageTotalEntry.SetAlignment(1)
  pageTotalEntry.SetWidthChars(4)
  if len(readings.Items) > 0 {
    pageTotalEntry.SetText(strconv.Itoa(readings.Items[0].TotalPages))
  }
  pageHBox.Add(pageTotalEntry)

  pageBoxAlignment := gtk.Alignment(0, 0, 0, 0)
  pageBoxAlignment.Add(pageHBox)
  readingHBox.Add(pageBoxAlignment)
  mainVBox.Add(readingHBox)

  addHighlightButton := gtk.ButtonWithLabel("Add highlight")
  window.highlights = models.Highlights()
  addHighlightButton.Clicked(func() {
    readingId := readings.FindByTitle(readingsComboBox.GetActiveText()).ReadmillId

    buffer := textView.GetBuffer()
    var startIter, endIter gtk.GtkTextIter
    buffer.GetStartIter(&startIter)
    buffer.GetEndIter(&endIter)
    content := buffer.GetText(&startIter, &endIter, true)

    highlight := models.GhHighlight{content, readingId, 0, time.Now()}
    window.highlights.Add(highlight)

    buffer.Delete(&startIter, &endIter)
  })
  readingHBox.PackEnd(addHighlightButton, false, false, 0)

  window.Add(mainVBox)
  return
}

func (w *GhMainWindow) buildMenuBar() *gtk.GtkMenuBar {
  menubar := gtk.MenuBar()

  fileMenuItem := gtk.MenuItemWithMnemonic("_File")
  menubar.Append(fileMenuItem)

  fileMenu := gtk.Menu()
  fileMenuItem.SetSubmenu(fileMenu)

  syncMenuItem := gtk.MenuItemWithMnemonic("_Sync")
  syncMenuItem.Connect("activate", func() {
    window := SyncWindow()
    window.Connect("destroy", func() {
      if w.highlights != nil {
        w.highlights.Read() // Reload highlights since there should be none left after a sync
      }
    })
    window.ShowAll()
  })
  fileMenu.Append(syncMenuItem)

  separatorMenuItem := gtk.SeparatorMenuItem()
  fileMenu.Append(separatorMenuItem)

  quitMenuItem := gtk.MenuItemWithMnemonic("_Quit")
  quitMenuItem.Connect("activate", func() {
    gtk.MainQuit()
  })
  fileMenu.Append(quitMenuItem)

  viewMenuItem := gtk.MenuItemWithMnemonic("_View")
  menubar.Append(viewMenuItem)

  viewMenu := gtk.Menu()
  viewMenuItem.SetSubmenu(viewMenu)

  queuedHighlightsMenuItem := gtk.MenuItemWithMnemonic("Queued _Highlights")
  queuedHighlightsMenuItem.Connect("activate", func() {
    window := QueuedHighlightsWindow()
    window.ShowAll()
  })
  viewMenu.Append(queuedHighlightsMenuItem)

  helpMenuItem := gtk.MenuItemWithMnemonic("_Help")
  menubar.Append(helpMenuItem)

  helpMenu := gtk.Menu()
  helpMenuItem.SetSubmenu(helpMenu)

  aboutMenuItem := gtk.MenuItemWithMnemonic("About")
  aboutMenuItem.Connect("activate", func() {
    aboutDialog := AboutDialog()
    dialog := aboutDialog.GtkAboutDialog
    dialog.Run()
    dialog.Destroy()
  })
  helpMenu.Append(aboutMenuItem)

  return menubar
}

func MainWindow() *GhMainWindow {
  mainWindow := &GhMainWindow{gtk.Window(gtk.GTK_WINDOW_TOPLEVEL), nil}
  mainWindow.build()
  return mainWindow
}

<commit_msg>Store reading position and use correct position for highlight<commit_after>package windows

import (
  "time"
  "strconv"
  "github.com/mattn/go-gtk/gtk"
  "ghighlighter/models"
)

type GhMainWindow struct {
  *gtk.GtkWindow
  highlights *models.GhHighlights
}

func (window *GhMainWindow) build() {
  window.SetTitle("ghighlights")
  window.Connect("destroy", gtk.MainQuit)

  mainVBox := gtk.VBox(false, 1)

  menubar := window.buildMenuBar()
  mainVBox.PackStart(menubar, false, false, 0)

  scrolledTextViewWindow := gtk.ScrolledWindow(nil, nil)
  scrolledTextViewWindow.SetPolicy(gtk.GTK_POLICY_AUTOMATIC, gtk.GTK_POLICY_AUTOMATIC)

  textView := gtk.TextView()
  textView.SetSizeRequest(600, 100)
  scrolledTextViewWindow.Add(textView)

  scrolledTextViewWindow.SetSizeRequest(600, 100)
  mainVBox.Add(scrolledTextViewWindow)

  readingHBox := gtk.HBox(false, 10)
  pageNumberEntry := gtk.Entry()
  pageTotalEntry := gtk.Entry()

  readingsComboBox := gtk.ComboBoxText()
  readings := models.Readings()
  for _, reading := range readings.Items {
    readingsComboBox.AppendText(reading.Title)
  }
  readingsComboBox.SetActive(0)
  readingsComboBox.Connect("changed", func() {
    reading:= readings.FindByTitle(readingsComboBox.GetActiveText())
    pageNumberEntry.SetText("0")
    pageTotalEntry.SetText(strconv.Itoa(reading.TotalPages))
  })
  align := gtk.Alignment(1, 1, 1, 0)
  align.Add(readingsComboBox)
  readingHBox.Add(align)

  pageHBox := gtk.HBox(false, 1)
  pageHBox.Add(gtk.Label("Page"))

  pageNumberEntry.SetAlignment(1)
  pageNumberEntry.SetWidthChars(4)
  pageNumberEntry.SetText("0")
  pageHBox.Add(pageNumberEntry)

  pageHBox.Add(gtk.Label("of"))

  pageTotalEntry.SetAlignment(1)
  pageTotalEntry.SetWidthChars(4)
  if len(readings.Items) > 0 {
    pageTotalEntry.SetText(strconv.Itoa(readings.Items[0].TotalPages))
  }
  pageHBox.Add(pageTotalEntry)

  pageBoxAlignment := gtk.Alignment(0, 0, 0, 0)
  pageBoxAlignment.Add(pageHBox)
  readingHBox.Add(pageBoxAlignment)
  mainVBox.Add(readingHBox)

  addHighlightButton := gtk.ButtonWithLabel("Add highlight")
  window.highlights = models.Highlights()
  addHighlightButton.Clicked(func() {
    reading := readings.FindByTitle(readingsComboBox.GetActiveText())
    readingId := reading.ReadmillId

    buffer := textView.GetBuffer()
    var startIter, endIter gtk.GtkTextIter
    buffer.GetStartIter(&startIter)
    buffer.GetEndIter(&endIter)
    content := buffer.GetText(&startIter, &endIter, true)

    pageNumber, _ := strconv.Atoi(pageNumberEntry.GetText())
    pageTotal, _ := strconv.Atoi(pageTotalEntry.GetText())
    position := float32(pageNumber) / float32(pageTotal)

    highlight := models.GhHighlight{content, readingId, position, time.Now()}
    window.highlights.Add(highlight)

    readings.UpdateTotalPages(pageTotal, reading)

    buffer.Delete(&startIter, &endIter)
  })
  readingHBox.PackEnd(addHighlightButton, false, false, 0)

  window.Add(mainVBox)
  return
}

func (w *GhMainWindow) buildMenuBar() *gtk.GtkMenuBar {
  menubar := gtk.MenuBar()

  fileMenuItem := gtk.MenuItemWithMnemonic("_File")
  menubar.Append(fileMenuItem)

  fileMenu := gtk.Menu()
  fileMenuItem.SetSubmenu(fileMenu)

  syncMenuItem := gtk.MenuItemWithMnemonic("_Sync")
  syncMenuItem.Connect("activate", func() {
    window := SyncWindow()
    window.Connect("destroy", func() {
      if w.highlights != nil {
        w.highlights.Read() // Reload highlights since there should be none left after a sync
      }
    })
    window.ShowAll()
  })
  fileMenu.Append(syncMenuItem)

  separatorMenuItem := gtk.SeparatorMenuItem()
  fileMenu.Append(separatorMenuItem)

  quitMenuItem := gtk.MenuItemWithMnemonic("_Quit")
  quitMenuItem.Connect("activate", func() {
    gtk.MainQuit()
  })
  fileMenu.Append(quitMenuItem)

  viewMenuItem := gtk.MenuItemWithMnemonic("_View")
  menubar.Append(viewMenuItem)

  viewMenu := gtk.Menu()
  viewMenuItem.SetSubmenu(viewMenu)

  queuedHighlightsMenuItem := gtk.MenuItemWithMnemonic("Queued _Highlights")
  queuedHighlightsMenuItem.Connect("activate", func() {
    window := QueuedHighlightsWindow()
    window.ShowAll()
  })
  viewMenu.Append(queuedHighlightsMenuItem)

  helpMenuItem := gtk.MenuItemWithMnemonic("_Help")
  menubar.Append(helpMenuItem)

  helpMenu := gtk.Menu()
  helpMenuItem.SetSubmenu(helpMenu)

  aboutMenuItem := gtk.MenuItemWithMnemonic("About")
  aboutMenuItem.Connect("activate", func() {
    aboutDialog := AboutDialog()
    dialog := aboutDialog.GtkAboutDialog
    dialog.Run()
    dialog.Destroy()
  })
  helpMenu.Append(aboutMenuItem)

  return menubar
}

func MainWindow() *GhMainWindow {
  mainWindow := &GhMainWindow{gtk.Window(gtk.GTK_WINDOW_TOPLEVEL), nil}
  mainWindow.build()
  return mainWindow
}

<|endoftext|>


<commit_before>package permissionsql

import (
	"testing"

	"github.com/xyproto/pinterface"
)

func TestInterface(t *testing.T) {
	// Check that the value qualifies for the interface
	var _ pinterface.IPermissions = New()
}
<commit_msg>Made test work for Travis-CI<commit_after>package permissionsql

import (
	"testing"

	"github.com/xyproto/pinterface"
)

func TestInterface(t *testing.T) {
	// Check that the value qualifies for the interface
	var _ pinterface.IPermissions = NewWithConf(connectionString)
}
<|endoftext|>