<commit_before>package ekanite

import (
	"expvar"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/ekanite/ekanite/input"
)

const (
	DefaultNumShards       = 16
	DefaultIndexDuration   = 24 * time.Hour
	DefaultRetentionPeriod = 24 * time.Hour

	RetentionCheckInterval = time.Hour
)

var (
	stats = expvar.NewMap("engine")
)

type EventIndexer interface {
	Index(events []*Event) error
}

// Batcher accepts "input events", and once it has a certain number, or a certain amount
// of time has passed, sends those as indexable Events to an Indexer. It also supports a
// maximum number of unprocessed Events it will keep pending. Once this limit is reached,
// it will not accept anymore until outstanding Events are processed.
type Batcher struct {
	indexer  EventIndexer
	size     int
	duration time.Duration

	c chan *input.Event
}

// NewBatcher returns a Batcher for EventIndexer e, a batching size of sz, a maximum duration
// of dur, and a maximum outstanding count of max.
func NewBatcher(e EventIndexer, sz int, dur time.Duration, max int) *Batcher {
	return &Batcher{
		indexer:  e,
		size:     sz,
		duration: dur,
		c:        make(chan *input.Event, max),
	}
}

// Start starts the batching process.
// XXX handle shutdown.
func (b *Batcher) Start(errChan chan<- error) error {
	go func() {
		batch := make([]*Event, 0, b.size)
		timer := time.NewTimer(b.duration)
		timer.Stop() // Stop any first firing.

		send := func() {
			err := b.indexer.Index(batch)
			if err != nil {
				stats.Add("batchIndexedError", 1)
				// handle error XXX
			}
			stats.Add("batchIndexed", 1)
			stats.Add("eventsIndexed", int64(len(batch)))
			if errChan != nil {
				errChan <- err
			}
			batch = make([]*Event, 0, b.size)

		}

		for {
			select {
			case event := <-b.c:
				idxEvent := &Event{
					event,
				}
				batch = append(batch, idxEvent)
				if len(batch) == 1 {
					timer.Reset(b.duration)
				}
				if len(batch) == b.size {
					timer.Stop()
					send()
				}
			case <-timer.C:
				stats.Add("batchTimeout", 1)
				send()
			}
		}
	}()

	return nil
}

// C returns the channel on the batcher to which events should be sent.
func (b *Batcher) C() chan<- *input.Event {
	return b.c
}

// Engine is the component that performs all indexing.
type Engine struct {
	path            string        // Path to all indexed data
	NumShards       int           // Number of shards to use when creating an index.
	IndexDuration   time.Duration // Duration of created indexes.
	RetentionPeriod time.Duration // How long after Index end-time to hang onto data.

	mu      sync.RWMutex
	indexes Indexes

	open bool
	done chan struct{}
	wg   sync.WaitGroup

	Logger *log.Logger
}

// NewEngine returns a new indexing engine, which will use any data located at path.
func NewEngine(path string) *Engine {
	return &Engine{
		path:            path,
		NumShards:       DefaultNumShards,
		IndexDuration:   DefaultIndexDuration,
		RetentionPeriod: DefaultRetentionPeriod,
		done:            make(chan struct{}),
		Logger:          log.New(os.Stderr, "[engine] ", log.LstdFlags),
	}
}

// Open opens the engine.
func (e *Engine) Open() error {
	if err := os.MkdirAll(e.path, 0755); err != nil {
		return err
	}
	d, err := os.Open(e.path)
	if err != nil {
		return fmt.Errorf("failed to open engine: %s", err.Error())
	}

	fis, err := d.Readdir(0)
	if err != nil {
		return err
	}

	// Open all indexes.
	for _, fi := range fis {
		if !fi.IsDir() || strings.HasPrefix(fi.Name(), ".") {
			continue
		}
		indexPath := filepath.Join(e.path, fi.Name())
		i, err := OpenIndex(indexPath)
		if err != nil {
			log.Printf("engine failed to open at index %s: %s", indexPath, err.Error())
			return err
		}
		log.Printf("engine opened index with %d shard(s) at %s", len(i.Shards), indexPath)
		e.indexes = append(e.indexes, i)
	}

	e.wg.Add(1)
	go e.runRetentionEnforcement()

	e.open = true
	return nil
}

// Close closes the engine.
func (e *Engine) Close() error {
	if !e.open {
		return nil
	}

	for _, i := range e.indexes {
		if err := i.Close(); err != nil {
			return err
		}
	}

	close(e.done)
	e.wg.Wait()

	e.open = false
	return nil
}

// Total returns the total number of documents indexed.
func (e *Engine) Total() (uint64, error) {
	e.mu.RLock()
	defer e.mu.RUnlock()

	var total uint64
	for _, i := range e.indexes {
		t, err := i.Total()
		if err != nil {
			return 0, err
		}
		total += t
	}
	return total, nil
}

// runRetentionEnforcement periodically run retention enforcement.
func (e *Engine) runRetentionEnforcement() {
	defer e.wg.Done()
	for {
		select {
		case <-e.done:
			return

		case <-time.After(RetentionCheckInterval):
			e.Logger.Print("retention enforcement commencing")
			stats.Add("retentionEnforcementRun", 1)
			e.enforceRetention()
		}
	}
}

// enforceRetention removes indexes which have aged out.
func (e *Engine) enforceRetention() {
	e.mu.Lock()
	defer e.mu.Unlock()

	filtered := e.indexes[:0]
	for _, i := range e.indexes {
		if i.Expired(time.Now().UTC(), e.RetentionPeriod) {
			if err := DeleteIndex(i); err != nil {
				e.Logger.Printf("retention enforcement failed to delete index %s: %s", i.path, err.Error())
			} else {
				e.Logger.Printf("retention enforcement deleted index %s", i.path)
				stats.Add("retentionEnforcementDeletions", 1)
			}
		} else {
			filtered = append(filtered, i)
		}
	}
	e.indexes = filtered
	return
}

// indexForReferenceTime returns an index suitable for indexing an event
// for the given reference time. Must be called under RLock.
func (e *Engine) indexForReferenceTime(t time.Time) *Index {
	for _, i := range e.indexes {
		if i.Contains(t) {
			return i
		}
	}
	return nil
}

// createIndex creates an index with a given start and end time and adds the
// created index to the Engine's store. It must be called under lock.
func (e *Engine) createIndex(startTime, endTime time.Time) (*Index, error) {
	// There cannot be two indexes with the same start time, since this would mean
	// two indexes with the same path. So if an index already exists with the requested
	// start time, use that index's end time as the start time.
	var idx *Index
	for _, i := range e.indexes {
		if i.startTime == startTime {
			idx = i
			break
		}
	}
	if idx != nil {
		startTime = idx.endTime // XXX This could still align with another start time! Needs some sort of loop.
		assert(!startTime.After(endTime), "new start time after end time")
	}

	i, err := NewIndex(e.path, startTime, endTime, e.NumShards)
	if err != nil {
		return nil, err
	}
	e.indexes = append(e.indexes, i)
	sort.Sort(e.indexes)

	e.Logger.Printf("index %s created with %d shards, start time: %s, end time: %s",
		i.Path(), e.NumShards, i.StartTime(), i.EndTime())
	return i, nil
}

// createIndexForReferenceTime creates an index suitable for indexing an event at the given
// reference time.
func (e *Engine) createIndexForReferenceTime(rt time.Time) (*Index, error) {
	start := rt.Truncate(e.IndexDuration).UTC()
	end := start.Add(e.IndexDuration).UTC()
	return e.createIndex(start, end)
}

// Index indexes a batch of Events. It blocks until all processing has completed.
func (e *Engine) Index(events []*Event) error {
	e.mu.RLock()
	defer e.mu.RUnlock()

	var wg sync.WaitGroup

	// De-multiplex the batch into sub-batches, one sub-batch for each Index.
	subBatches := make(map[*Index][]Document, 0)

	for _, ev := range events {
		index := e.indexForReferenceTime(ev.ReferenceTime())
		if index == nil {
			func() {
				// Take a RWLock, check again, and create a new index if necessary.
				// Doing this in a function makes lock management foolproof.
				e.mu.RUnlock()
				defer e.mu.RLock()
				e.mu.Lock()
				defer e.mu.Unlock()

				index = e.indexForReferenceTime(ev.ReferenceTime())
				if index == nil {
					var err error
					index, err = e.createIndexForReferenceTime(ev.ReferenceTime())
					if err != nil || index == nil {
						panic(fmt.Sprintf("failed to create index for %s", ev.ReferenceTime()))
					}
				}
			}()
		}

		if _, ok := subBatches[index]; !ok {
			subBatches[index] = make([]Document, 0)
		}
		subBatches[index] = append(subBatches[index], ev)
	}

	// Index each batch in parallel.
	for index, subBatch := range subBatches {
		wg.Add(1)
		go func(i *Index, b []Document) {
			defer wg.Done()
			i.Index(b)
		}(index, subBatch)
	}
	wg.Wait()
	return nil
}

// Search performs a search.
func (e *Engine) Search(query string) (<-chan string, error) {
	e.mu.RLock()
	defer e.mu.RUnlock()
	stats.Add("queriesRx", 1)

	// Buffer channel to control how many docs are sent back. XXX Will this allow
	// the client to control? Possibly.
	c := make(chan string, 1)

	go func() {
		// Sequentially search each index.
		for _, i := range e.indexes {
			ids, err := i.Search(query)
			if err != nil {
				e.Logger.Println("error performing search:", err.Error())
				break
			}
			for _, id := range ids {
				b, err := i.Document(id)
				if err != nil {
					e.Logger.Println("error getting document:", err.Error())
					break
				}
				stats.Add("docsIDsRetrived", 1)
				c <- string(b) // There is excessive byte-slice-to-strings here.
			}
		}
		close(c)
	}()

	return c, nil
}

// Path returns the path to the indexed data directory.
func (e *Engine) Path() string {
	return e.path
}

// assert will panic with a given formatted message if the given condition is false.
func assert(condition bool, msg string, v ...interface{}) {
	if !condition {
		panic(fmt.Sprintf("assert failed: "+msg, v...))
	}
}
<commit_msg>Don't send on batching error<commit_after>package ekanite

import (
	"expvar"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/ekanite/ekanite/input"
)

const (
	DefaultNumShards       = 16
	DefaultIndexDuration   = 24 * time.Hour
	DefaultRetentionPeriod = 24 * time.Hour

	RetentionCheckInterval = time.Hour
)

var (
	stats = expvar.NewMap("engine")
)

type EventIndexer interface {
	Index(events []*Event) error
}

// Batcher accepts "input events", and once it has a certain number, or a certain amount
// of time has passed, sends those as indexable Events to an Indexer. It also supports a
// maximum number of unprocessed Events it will keep pending. Once this limit is reached,
// it will not accept anymore until outstanding Events are processed.
type Batcher struct {
	indexer  EventIndexer
	size     int
	duration time.Duration

	c chan *input.Event
}

// NewBatcher returns a Batcher for EventIndexer e, a batching size of sz, a maximum duration
// of dur, and a maximum outstanding count of max.
func NewBatcher(e EventIndexer, sz int, dur time.Duration, max int) *Batcher {
	return &Batcher{
		indexer:  e,
		size:     sz,
		duration: dur,
		c:        make(chan *input.Event, max),
	}
}

// Start starts the batching process.
func (b *Batcher) Start(errChan chan<- error) error {
	go func() {
		batch := make([]*Event, 0, b.size)
		timer := time.NewTimer(b.duration)
		timer.Stop() // Stop any first firing.

		send := func() {
			err := b.indexer.Index(batch)
			if err != nil {
				stats.Add("batchIndexedError", 1)
				return
			}
			stats.Add("batchIndexed", 1)
			stats.Add("eventsIndexed", int64(len(batch)))
			if errChan != nil {
				errChan <- err
			}
			batch = make([]*Event, 0, b.size)
		}

		for {
			select {
			case event := <-b.c:
				idxEvent := &Event{
					event,
				}
				batch = append(batch, idxEvent)
				if len(batch) == 1 {
					timer.Reset(b.duration)
				}
				if len(batch) == b.size {
					timer.Stop()
					send()
				}
			case <-timer.C:
				stats.Add("batchTimeout", 1)
				send()
			}
		}
	}()

	return nil
}

// C returns the channel on the batcher to which events should be sent.
func (b *Batcher) C() chan<- *input.Event {
	return b.c
}

// Engine is the component that performs all indexing.
type Engine struct {
	path            string        // Path to all indexed data
	NumShards       int           // Number of shards to use when creating an index.
	IndexDuration   time.Duration // Duration of created indexes.
	RetentionPeriod time.Duration // How long after Index end-time to hang onto data.

	mu      sync.RWMutex
	indexes Indexes

	open bool
	done chan struct{}
	wg   sync.WaitGroup

	Logger *log.Logger
}

// NewEngine returns a new indexing engine, which will use any data located at path.
func NewEngine(path string) *Engine {
	return &Engine{
		path:            path,
		NumShards:       DefaultNumShards,
		IndexDuration:   DefaultIndexDuration,
		RetentionPeriod: DefaultRetentionPeriod,
		done:            make(chan struct{}),
		Logger:          log.New(os.Stderr, "[engine] ", log.LstdFlags),
	}
}

// Open opens the engine.
func (e *Engine) Open() error {
	if err := os.MkdirAll(e.path, 0755); err != nil {
		return err
	}
	d, err := os.Open(e.path)
	if err != nil {
		return fmt.Errorf("failed to open engine: %s", err.Error())
	}

	fis, err := d.Readdir(0)
	if err != nil {
		return err
	}

	// Open all indexes.
	for _, fi := range fis {
		if !fi.IsDir() || strings.HasPrefix(fi.Name(), ".") {
			continue
		}
		indexPath := filepath.Join(e.path, fi.Name())
		i, err := OpenIndex(indexPath)
		if err != nil {
			log.Printf("engine failed to open at index %s: %s", indexPath, err.Error())
			return err
		}
		log.Printf("engine opened index with %d shard(s) at %s", len(i.Shards), indexPath)
		e.indexes = append(e.indexes, i)
	}

	e.wg.Add(1)
	go e.runRetentionEnforcement()

	e.open = true
	return nil
}

// Close closes the engine.
func (e *Engine) Close() error {
	if !e.open {
		return nil
	}

	for _, i := range e.indexes {
		if err := i.Close(); err != nil {
			return err
		}
	}

	close(e.done)
	e.wg.Wait()

	e.open = false
	return nil
}

// Total returns the total number of documents indexed.
func (e *Engine) Total() (uint64, error) {
	e.mu.RLock()
	defer e.mu.RUnlock()

	var total uint64
	for _, i := range e.indexes {
		t, err := i.Total()
		if err != nil {
			return 0, err
		}
		total += t
	}
	return total, nil
}

// runRetentionEnforcement periodically run retention enforcement.
func (e *Engine) runRetentionEnforcement() {
	defer e.wg.Done()
	for {
		select {
		case <-e.done:
			return

		case <-time.After(RetentionCheckInterval):
			e.Logger.Print("retention enforcement commencing")
			stats.Add("retentionEnforcementRun", 1)
			e.enforceRetention()
		}
	}
}

// enforceRetention removes indexes which have aged out.
func (e *Engine) enforceRetention() {
	e.mu.Lock()
	defer e.mu.Unlock()

	filtered := e.indexes[:0]
	for _, i := range e.indexes {
		if i.Expired(time.Now().UTC(), e.RetentionPeriod) {
			if err := DeleteIndex(i); err != nil {
				e.Logger.Printf("retention enforcement failed to delete index %s: %s", i.path, err.Error())
			} else {
				e.Logger.Printf("retention enforcement deleted index %s", i.path)
				stats.Add("retentionEnforcementDeletions", 1)
			}
		} else {
			filtered = append(filtered, i)
		}
	}
	e.indexes = filtered
	return
}

// indexForReferenceTime returns an index suitable for indexing an event
// for the given reference time. Must be called under RLock.
func (e *Engine) indexForReferenceTime(t time.Time) *Index {
	for _, i := range e.indexes {
		if i.Contains(t) {
			return i
		}
	}
	return nil
}

// createIndex creates an index with a given start and end time and adds the
// created index to the Engine's store. It must be called under lock.
func (e *Engine) createIndex(startTime, endTime time.Time) (*Index, error) {
	// There cannot be two indexes with the same start time, since this would mean
	// two indexes with the same path. So if an index already exists with the requested
	// start time, use that index's end time as the start time.
	var idx *Index
	for _, i := range e.indexes {
		if i.startTime == startTime {
			idx = i
			break
		}
	}
	if idx != nil {
		startTime = idx.endTime // XXX This could still align with another start time! Needs some sort of loop.
		assert(!startTime.After(endTime), "new start time after end time")
	}

	i, err := NewIndex(e.path, startTime, endTime, e.NumShards)
	if err != nil {
		return nil, err
	}
	e.indexes = append(e.indexes, i)
	sort.Sort(e.indexes)

	e.Logger.Printf("index %s created with %d shards, start time: %s, end time: %s",
		i.Path(), e.NumShards, i.StartTime(), i.EndTime())
	return i, nil
}

// createIndexForReferenceTime creates an index suitable for indexing an event at the given
// reference time.
func (e *Engine) createIndexForReferenceTime(rt time.Time) (*Index, error) {
	start := rt.Truncate(e.IndexDuration).UTC()
	end := start.Add(e.IndexDuration).UTC()
	return e.createIndex(start, end)
}

// Index indexes a batch of Events. It blocks until all processing has completed.
func (e *Engine) Index(events []*Event) error {
	e.mu.RLock()
	defer e.mu.RUnlock()

	var wg sync.WaitGroup

	// De-multiplex the batch into sub-batches, one sub-batch for each Index.
	subBatches := make(map[*Index][]Document, 0)

	for _, ev := range events {
		index := e.indexForReferenceTime(ev.ReferenceTime())
		if index == nil {
			func() {
				// Take a RWLock, check again, and create a new index if necessary.
				// Doing this in a function makes lock management foolproof.
				e.mu.RUnlock()
				defer e.mu.RLock()
				e.mu.Lock()
				defer e.mu.Unlock()

				index = e.indexForReferenceTime(ev.ReferenceTime())
				if index == nil {
					var err error
					index, err = e.createIndexForReferenceTime(ev.ReferenceTime())
					if err != nil || index == nil {
						panic(fmt.Sprintf("failed to create index for %s", ev.ReferenceTime()))
					}
				}
			}()
		}

		if _, ok := subBatches[index]; !ok {
			subBatches[index] = make([]Document, 0)
		}
		subBatches[index] = append(subBatches[index], ev)
	}

	// Index each batch in parallel.
	for index, subBatch := range subBatches {
		wg.Add(1)
		go func(i *Index, b []Document) {
			defer wg.Done()
			i.Index(b)
		}(index, subBatch)
	}
	wg.Wait()
	return nil
}

// Search performs a search.
func (e *Engine) Search(query string) (<-chan string, error) {
	e.mu.RLock()
	defer e.mu.RUnlock()
	stats.Add("queriesRx", 1)

	// Buffer channel to control how many docs are sent back. XXX Will this allow
	// the client to control? Possibly.
	c := make(chan string, 1)

	go func() {
		// Sequentially search each index.
		for _, i := range e.indexes {
			ids, err := i.Search(query)
			if err != nil {
				e.Logger.Println("error performing search:", err.Error())
				break
			}
			for _, id := range ids {
				b, err := i.Document(id)
				if err != nil {
					e.Logger.Println("error getting document:", err.Error())
					break
				}
				stats.Add("docsIDsRetrived", 1)
				c <- string(b) // There is excessive byte-slice-to-strings here.
			}
		}
		close(c)
	}()

	return c, nil
}

// Path returns the path to the indexed data directory.
func (e *Engine) Path() string {
	return e.path
}

// assert will panic with a given formatted message if the given condition is false.
func assert(condition bool, msg string, v ...interface{}) {
	if !condition {
		panic(fmt.Sprintf("assert failed: "+msg, v...))
	}
}
<|endoftext|>


<commit_before>package qb

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"
)

// NewEngine generates a new engine and returns it as an engine pointer
func NewEngine(driver string, dsn string) (*Engine, error) {

	conn, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}

	return &Engine{
		driver: driver,
		dsn:    dsn,
		db:     conn,
	}, err
}

// Engine is the generic struct for handling db connections
type Engine struct {
	driver string
	dsn    string
	db     *sql.DB
}

// Exec executes insert & update type queries and returns sql.Result and error
func (e *Engine) Exec(query *Query) (sql.Result, error) {

	stmt, err := e.db.Prepare(query.SQL())
	if err != nil {
		return nil, err
	}

	res, err := stmt.Exec(query.Bindings()...)
	if err != nil {
		return nil, err
	}

	return res, nil
}

// QueryRow wraps *sql.DB.QueryRow()
func (e *Engine) QueryRow(query *Query) *sql.Row {
	return e.db.QueryRow(query.SQL(), query.Bindings()...)
}

// DB returns sql.DB of wrapped engine connection
func (e *Engine) DB() *sql.DB {
	return e.db
}

// Ping pings the db using connection and returns error if connectivity is not present
func (e *Engine) Ping() error {
	return e.db.Ping()
}

// Driver returns the driver as string
func (e *Engine) Driver() string {
	return e.driver
}

// Dsn returns the connection dsn
func (e *Engine) Dsn() string {
	return e.dsn
}
<commit_msg>add Query function to engine<commit_after>package qb

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"
)

// NewEngine generates a new engine and returns it as an engine pointer
func NewEngine(driver string, dsn string) (*Engine, error) {

	conn, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}

	return &Engine{
		driver: driver,
		dsn:    dsn,
		db:     conn,
	}, err
}

// Engine is the generic struct for handling db connections
type Engine struct {
	driver string
	dsn    string
	db     *sql.DB
}

// Exec executes insert & update type queries and returns sql.Result and error
func (e *Engine) Exec(query *Query) (sql.Result, error) {

	stmt, err := e.db.Prepare(query.SQL())
	if err != nil {
		return nil, err
	}

	res, err := stmt.Exec(query.Bindings()...)
	if err != nil {
		return nil, err
	}

	return res, nil
}

// QueryRow wraps *sql.DB.QueryRow()
func (e *Engine) QueryRow(query *Query) *sql.Row {
	return e.db.QueryRow(query.SQL(), query.Bindings()...)
}

// Query wraps *sql.DB.Query()
func (e *Engine) Query(query *Query) (*sql.Rows, error) {
	return e.db.Query(query.SQL(), query.Bindings()...)
}

// DB returns sql.DB of wrapped engine connection
func (e *Engine) DB() *sql.DB {
	return e.db
}

// Ping pings the db using connection and returns error if connectivity is not present
func (e *Engine) Ping() error {
	return e.db.Ping()
}

// Driver returns the driver as string
func (e *Engine) Driver() string {
	return e.driver
}

// Dsn returns the connection dsn
func (e *Engine) Dsn() string {
	return e.dsn
}
<|endoftext|>


<commit_before>package citadel

import (
	"crypto/tls"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/samalba/dockerclient"
)

type Engine struct {
	ID     string   `json:"id,omitempty"`
	Addr   string   `json:"addr,omitempty"`
	Cpus   float64  `json:"cpus,omitempty"`
	Memory float64  `json:"memory,omitempty"`
	Labels []string `json:"labels,omitempty"`

	client       *dockerclient.DockerClient
	eventHandler EventHandler
}

func (e *Engine) Connect(config *tls.Config) error {
	c, err := dockerclient.NewDockerClient(e.Addr, config)
	if err != nil {
		return err
	}

	e.client = c

	return nil
}

func (e *Engine) SetClient(c *dockerclient.DockerClient) {
	e.client = c
}

// IsConnected returns true if the engine is connected to a remote docker API
func (e *Engine) IsConnected() bool {
	return e.client != nil
}

func (e *Engine) Pull(image string) error {
	imageInfo := ParseImageName(image)
	if err := e.client.PullImage(imageInfo.Name, imageInfo.Tag); err != nil {
		return err
	}
	return nil
}

func (e *Engine) Start(c *Container, pullImage bool) error {
	var (
		err    error
		env    = []string{}
		client = e.client
		i      = c.Image
	)
	c.Engine = e

	for k, v := range i.Environment {
		env = append(env, fmt.Sprintf("%s=%s", k, v))
	}

	env = append(env,
		fmt.Sprintf("_citadel_type=%s", i.Type),
		fmt.Sprintf("_citadel_labels=%s", strings.Join(i.Labels, ",")),
	)

	vols := make(map[string]struct{})
	binds := []string{}
	for _, v := range i.Volumes {
		if strings.Index(v, ":") > -1 {
			cv := strings.Split(v, ":")
			binds = append(binds, v)
			v = cv[1]
		}
		vols[v] = struct{}{}
	}
	config := &dockerclient.ContainerConfig{
		Hostname:     i.Hostname,
		Domainname:   i.Domainname,
		Image:        i.Name,
		Cmd:          i.Args,
		Memory:       int(i.Memory) * 1024 * 1024,
		Env:          env,
		CpuShares:    int(i.Cpus * 100.0 / e.Cpus),
		ExposedPorts: make(map[string]struct{}),
		Volumes:      vols,
	}

	links := []string{}
	for k, v := range i.Links {
		links = append(links, fmt.Sprintf("%s:%s", k, v))
	}
	hostConfig := &dockerclient.HostConfig{
		PublishAllPorts: i.Publish,
		PortBindings:    make(map[string][]dockerclient.PortBinding),
		Links:           links,
		Binds:           binds,
		RestartPolicy: dockerclient.RestartPolicy{
			Name:              i.RestartPolicy.Name,
			MaximumRetryCount: i.RestartPolicy.MaximumRetryCount,
		},
		NetworkMode: i.NetworkMode,
	}

	for _, b := range i.BindPorts {
		key := fmt.Sprintf("%d/%s", b.ContainerPort, b.Proto)
		config.ExposedPorts[key] = struct{}{}

		hostConfig.PortBindings[key] = []dockerclient.PortBinding{
			{
				HostIp:   b.HostIp,
				HostPort: fmt.Sprint(b.Port),
			},
		}
	}

	if pullImage {
		if err := e.Pull(i.Name); err != nil {
			return err
		}
	}

	if c.ID, err = client.CreateContainer(config, c.Name); err != nil {
		return err
	}

	if err := client.StartContainer(c.ID, hostConfig); err != nil {
		return err
	}

	return e.updatePortInformation(c)
}

func (e *Engine) ListImages() ([]string, error) {
	images, err := e.client.ListImages()
	if err != nil {
		return nil, err
	}

	out := []string{}

	for _, i := range images {
		for _, t := range i.RepoTags {
			out = append(out, t)
		}
	}

	return out, nil
}

func (e *Engine) updatePortInformation(c *Container) error {
	info, err := e.client.InspectContainer(c.ID)
	if err != nil {
		return err
	}

	return parsePortInformation(info, c)
}

func (e *Engine) ListContainers(all bool) ([]*Container, error) {
	out := []*Container{}

	c, err := e.client.ListContainers(all, true, "")
	if err != nil {
		return nil, err
	}

	for _, ci := range c {
		cc, err := FromDockerContainer(ci.Id, ci.Image, e)
		if err != nil {
			return nil, err
		}

		out = append(out, cc)
	}

	return out, nil
}

func (e *Engine) Logs(container *Container, stdout bool, stderr bool) (io.ReadCloser, error) {
	logopts := &dockerclient.LogOptions{
		Stdout:     stdout,
		Stderr:     stderr,
		Timestamps: false,
		Follow:     false,
		Tail:       0,
	}
	return e.client.ContainerLogs(container.ID, logopts)
}

func (e *Engine) Kill(container *Container, sig int) error {
	return e.client.KillContainer(container.ID)
}

func (e *Engine) Stop(container *Container) error {
	return e.client.StopContainer(container.ID, 8)
}

func (e *Engine) Restart(container *Container, timeout int) error {
	return e.client.RestartContainer(container.ID, timeout)
}

func (e *Engine) Remove(container *Container) error {
	return e.client.RemoveContainer(container.ID, true)
}

func (e *Engine) Events(h EventHandler) error {
	if e.eventHandler != nil {
		return fmt.Errorf("event handler already set")
	}
	e.eventHandler = h

	e.client.StartMonitorEvents(e.handler)

	return nil
}

func (e *Engine) String() string {
	return fmt.Sprintf("engine %s addr %s", e.ID, e.Addr)
}

func (e *Engine) handler(ev *dockerclient.Event, args ...interface{}) {
	event := &Event{
		Engine: e,
		Type:   ev.Status,
		Time:   time.Unix(int64(ev.Time), 0),
	}

	container, err := FromDockerContainer(ev.Id, ev.From, e)
	if err != nil {
		// TODO: un fuck this shit, fuckin handler
		return
	}

	event.Container = container

	e.eventHandler.Handle(event)
}
<commit_msg>Since 1.13/1.14 the image:tag format for image names is supported<commit_after>package citadel

import (
	"crypto/tls"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/samalba/dockerclient"
)

type Engine struct {
	ID     string   `json:"id,omitempty"`
	Addr   string   `json:"addr,omitempty"`
	Cpus   float64  `json:"cpus,omitempty"`
	Memory float64  `json:"memory,omitempty"`
	Labels []string `json:"labels,omitempty"`

	client       *dockerclient.DockerClient
	eventHandler EventHandler
}

func (e *Engine) Connect(config *tls.Config) error {
	c, err := dockerclient.NewDockerClient(e.Addr, config)
	if err != nil {
		return err
	}

	e.client = c

	return nil
}

func (e *Engine) SetClient(c *dockerclient.DockerClient) {
	e.client = c
}

// IsConnected returns true if the engine is connected to a remote docker API
func (e *Engine) IsConnected() bool {
	return e.client != nil
}

func (e *Engine) Pull(image string) error {
	if err := e.client.PullImage(image); err != nil {
		return err
	}
	return nil
}

func (e *Engine) Start(c *Container, pullImage bool) error {
	var (
		err    error
		env    = []string{}
		client = e.client
		i      = c.Image
	)
	c.Engine = e

	for k, v := range i.Environment {
		env = append(env, fmt.Sprintf("%s=%s", k, v))
	}

	env = append(env,
		fmt.Sprintf("_citadel_type=%s", i.Type),
		fmt.Sprintf("_citadel_labels=%s", strings.Join(i.Labels, ",")),
	)

	vols := make(map[string]struct{})
	binds := []string{}
	for _, v := range i.Volumes {
		if strings.Index(v, ":") > -1 {
			cv := strings.Split(v, ":")
			binds = append(binds, v)
			v = cv[1]
		}
		vols[v] = struct{}{}
	}
	config := &dockerclient.ContainerConfig{
		Hostname:     i.Hostname,
		Domainname:   i.Domainname,
		Image:        i.Name,
		Cmd:          i.Args,
		Memory:       int(i.Memory) * 1024 * 1024,
		Env:          env,
		CpuShares:    int(i.Cpus * 100.0 / e.Cpus),
		ExposedPorts: make(map[string]struct{}),
		Volumes:      vols,
	}

	links := []string{}
	for k, v := range i.Links {
		links = append(links, fmt.Sprintf("%s:%s", k, v))
	}
	hostConfig := &dockerclient.HostConfig{
		PublishAllPorts: i.Publish,
		PortBindings:    make(map[string][]dockerclient.PortBinding),
		Links:           links,
		Binds:           binds,
		RestartPolicy: dockerclient.RestartPolicy{
			Name:              i.RestartPolicy.Name,
			MaximumRetryCount: i.RestartPolicy.MaximumRetryCount,
		},
		NetworkMode: i.NetworkMode,
	}

	for _, b := range i.BindPorts {
		key := fmt.Sprintf("%d/%s", b.ContainerPort, b.Proto)
		config.ExposedPorts[key] = struct{}{}

		hostConfig.PortBindings[key] = []dockerclient.PortBinding{
			{
				HostIp:   b.HostIp,
				HostPort: fmt.Sprint(b.Port),
			},
		}
	}

	if pullImage {
		if err := e.Pull(i.Name); err != nil {
			return err
		}
	}

	if c.ID, err = client.CreateContainer(config, c.Name); err != nil {
		return err
	}

	if err := client.StartContainer(c.ID, hostConfig); err != nil {
		return err
	}

	return e.updatePortInformation(c)
}

func (e *Engine) ListImages() ([]string, error) {
	images, err := e.client.ListImages()
	if err != nil {
		return nil, err
	}

	out := []string{}

	for _, i := range images {
		for _, t := range i.RepoTags {
			out = append(out, t)
		}
	}

	return out, nil
}

func (e *Engine) updatePortInformation(c *Container) error {
	info, err := e.client.InspectContainer(c.ID)
	if err != nil {
		return err
	}

	return parsePortInformation(info, c)
}

func (e *Engine) ListContainers(all bool) ([]*Container, error) {
	out := []*Container{}

	c, err := e.client.ListContainers(all, true, "")
	if err != nil {
		return nil, err
	}

	for _, ci := range c {
		cc, err := FromDockerContainer(ci.Id, ci.Image, e)
		if err != nil {
			return nil, err
		}

		out = append(out, cc)
	}

	return out, nil
}

func (e *Engine) Logs(container *Container, stdout bool, stderr bool) (io.ReadCloser, error) {
	logopts := &dockerclient.LogOptions{
		Stdout:     stdout,
		Stderr:     stderr,
		Timestamps: false,
		Follow:     false,
		Tail:       0,
	}
	return e.client.ContainerLogs(container.ID, logopts)
}

func (e *Engine) Kill(container *Container, sig int) error {
	return e.client.KillContainer(container.ID)
}

func (e *Engine) Stop(container *Container) error {
	return e.client.StopContainer(container.ID, 8)
}

func (e *Engine) Restart(container *Container, timeout int) error {
	return e.client.RestartContainer(container.ID, timeout)
}

func (e *Engine) Remove(container *Container) error {
	return e.client.RemoveContainer(container.ID, true)
}

func (e *Engine) Events(h EventHandler) error {
	if e.eventHandler != nil {
		return fmt.Errorf("event handler already set")
	}
	e.eventHandler = h

	e.client.StartMonitorEvents(e.handler)

	return nil
}

func (e *Engine) String() string {
	return fmt.Sprintf("engine %s addr %s", e.ID, e.Addr)
}

func (e *Engine) handler(ev *dockerclient.Event, args ...interface{}) {
	event := &Event{
		Engine: e,
		Type:   ev.Status,
		Time:   time.Unix(int64(ev.Time), 0),
	}

	container, err := FromDockerContainer(ev.Id, ev.From, e)
	if err != nil {
		// TODO: un fuck this shit, fuckin handler
		return
	}

	event.Container = container

	e.eventHandler.Handle(event)
}
<|endoftext|>


<commit_before>package redishappy

import (
	"github.com/mdevilliers/redishappy/api"
	"github.com/mdevilliers/redishappy/configuration"
	"github.com/mdevilliers/redishappy/sentinel"
	"github.com/mdevilliers/redishappy/services/logger"
	"github.com/mdevilliers/redishappy/types"
	"github.com/zenazn/goji"
)

func NewRedisHappyEngine(flipper types.FlipperClient, cm *configuration.ConfigurationManager, logPath string) {

	logger.InitLogging(logPath)

	masterEvents := make(chan types.MasterSwitchedEvent)
	sentinelManager := sentinel.NewManager(masterEvents, cm)

	go loopSentinelEvents(flipper, masterEvents)
	go intiliseTopology(flipper, sentinelManager)

	initApiServer(sentinelManager, cm)
}

func loopSentinelEvents(flipper types.FlipperClient, masterEvents chan types.MasterSwitchedEvent) {

	for event := range masterEvents {
		flipper.Orchestrate(event)
	}
}

func intiliseTopology(flipper types.FlipperClient, sentinelManager *sentinel.SentinelManager) {

	stateChannel := make(chan types.MasterDetailsCollection)

	go sentinelManager.GetTopology(stateChannel)

	topology := <-stateChannel

	flipper.InitialiseRunningState(&topology)
}

func initApiServer(manager *sentinel.SentinelManager, cm *configuration.ConfigurationManager) {

	logger.Info.Print("hosting json endpoint.")

	pongApi := api.PingApi{}
	sentinelApi := api.SentinelApi{Manager: manager}
	configurationApi := api.ConfigurationApi{ConfigurationManager: cm}

	goji.Get("/api/ping", pongApi.Get)
	goji.Get("/api/sentinel", sentinelApi.Get)
	goji.Get("/api/configuration", configurationApi.Get)

	goji.Serve()
}
<commit_msg>changed url for the sentinel api endpoint<commit_after>package redishappy

import (
	"github.com/mdevilliers/redishappy/api"
	"github.com/mdevilliers/redishappy/configuration"
	"github.com/mdevilliers/redishappy/sentinel"
	"github.com/mdevilliers/redishappy/services/logger"
	"github.com/mdevilliers/redishappy/types"
	"github.com/zenazn/goji"
)

func NewRedisHappyEngine(flipper types.FlipperClient, cm *configuration.ConfigurationManager, logPath string) {

	logger.InitLogging(logPath)

	masterEvents := make(chan types.MasterSwitchedEvent)
	sentinelManager := sentinel.NewManager(masterEvents, cm)

	go loopSentinelEvents(flipper, masterEvents)
	go intiliseTopology(flipper, sentinelManager)

	initApiServer(sentinelManager, cm)
}

func loopSentinelEvents(flipper types.FlipperClient, masterEvents chan types.MasterSwitchedEvent) {

	for event := range masterEvents {
		flipper.Orchestrate(event)
	}
}

func intiliseTopology(flipper types.FlipperClient, sentinelManager *sentinel.SentinelManager) {

	stateChannel := make(chan types.MasterDetailsCollection)

	go sentinelManager.GetTopology(stateChannel)

	topology := <-stateChannel

	flipper.InitialiseRunningState(&topology)
}

func initApiServer(manager *sentinel.SentinelManager, cm *configuration.ConfigurationManager) {

	logger.Info.Print("hosting json endpoint.")

	pongApi := api.PingApi{}
	sentinelApi := api.SentinelApi{Manager: manager}
	configurationApi := api.ConfigurationApi{ConfigurationManager: cm}

	goji.Get("/api/ping", pongApi.Get)
	goji.Get("/api/sentinels", sentinelApi.Get)
	goji.Get("/api/configuration", configurationApi.Get)

	goji.Serve()
}
<|endoftext|>


<commit_before>package hdf5

// #include "hdf5.h"
// #include <stdlib.h>
// #include <string.h>
// #include "cgo_hdf5.h"
import "C"

import (
	"fmt"
)

// DisplayErrors enables/disables HDF5's automatic error printing
func DisplayErrors(b bool) error {
	switch b {
	case true:
		if err := togo_err(C._go_hdf5_unsilence_errors()); err != nil {
			return fmt.Errorf("hdf5: could not call H5E_set_auto(): %v", err)
		}
	default:
		if err := togo_err(C._go_hdf5_silence_errors()); err != nil {
			return fmt.Errorf("hdf5: could not call H5E_set_auto(): %v", err)
		}
	}
	return nil
}

func init() {
	err := DisplayErrors(false)
	if err != nil {
		panic(err.Error())
	}
}

// EOF
<commit_msg>togo_err -> h5err in errors.go<commit_after>package hdf5

// #include "hdf5.h"
// #include <stdlib.h>
// #include <string.h>
// #include "cgo_hdf5.h"
import "C"

import (
	"fmt"
)

// DisplayErrors enables/disables HDF5's automatic error printing
func DisplayErrors(b bool) error {
	switch b {
	case true:
		if err := h5err(C._go_hdf5_unsilence_errors()); err != nil {
			return fmt.Errorf("hdf5: could not call H5E_set_auto(): %v", err)
		}
	default:
		if err := h5err(C._go_hdf5_silence_errors()); err != nil {
			return fmt.Errorf("hdf5: could not call H5E_set_auto(): %v", err)
		}
	}
	return nil
}

func init() {
	err := DisplayErrors(false)
	if err != nil {
		panic(err.Error())
	}
}

// EOF
<|endoftext|>


<commit_before>package gorethink

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"

	p "github.com/dancannon/gorethink/ql2"
)

var (
	// ErrNoHosts is returned when no hosts to the Connect method.
	ErrNoHosts = errors.New("no hosts provided")
	// ErrNoConnectionsStarted is returned when the driver couldn't to any of
	// the provided hosts.
	ErrNoConnectionsStarted = errors.New("no connections were made when creating the session")
	// ErrInvalidNode is returned when attempting to connect to a node which
	// returns an invalid response.
	ErrInvalidNode = errors.New("invalid node")
	// ErrNoConnections is returned when there are no active connections in the
	// clusters connection pool.
	ErrNoConnections = errors.New("gorethink: no connections were available")
	// ErrConnectionClosed is returned when trying to send a query with a closed
	// connection.
	ErrConnectionClosed = errors.New("gorethink: the connection is closed")
)

func printCarrots(t Term, frames []*p.Frame) string {
	var frame *p.Frame
	if len(frames) > 1 {
		frame, frames = frames[0], frames[1:]
	} else if len(frames) == 1 {
		frame, frames = frames[0], []*p.Frame{}
	}

	for i, arg := range t.args {
		if frame.GetPos() == int64(i) {
			t.args[i] = Term{
				termType: p.Term_DATUM,
				data:     printCarrots(arg, frames),
			}
		}
	}

	for k, arg := range t.optArgs {
		if frame.GetOpt() == k {
			t.optArgs[k] = Term{
				termType: p.Term_DATUM,
				data:     printCarrots(arg, frames),
			}
		}
	}

	b := &bytes.Buffer{}
	for _, c := range t.String() {
		if c != '^' {
			b.WriteString(" ")
		} else {
			b.WriteString("^")
		}
	}

	return b.String()
}

// Error constants
var ErrEmptyResult = errors.New("The result does not contain any more rows")

// Connection/Response errors

// rqlResponseError is the base type for all errors, it formats both
// for the response and query if set.
type rqlServerError struct {
	response *Response
	term     *Term
}

func (e rqlServerError) Error() string {
	var err = "An error occurred"
	if e.response != nil {
		json.Unmarshal(e.response.Responses[0], &err)
	}

	if e.term == nil {
		return fmt.Sprintf("gorethink: %s", err)
	}

	return fmt.Sprintf("gorethink: %s in: \n%s", err, e.term.String())

}

func (e rqlServerError) String() string {
	return e.Error()
}

type rqlError string

func (e rqlError) Error() string {
	return fmt.Sprintf("gorethink: %s", e)
}

func (e rqlError) String() string {
	return e.Error()
}

// Exported Error "Implementations"

type RQLClientError struct{ rqlServerError }
type RQLCompileError struct{ rqlServerError }
type RQLDriverCompileError struct{ RQLCompileError }
type RQLServerCompileError struct{ RQLCompileError }
type RQLAuthError struct{ RQLDriverError }
type RQLRuntimeError struct{ rqlServerError }

type RQLQueryLogicError struct{ RQLRuntimeError }
type RQLNonExistenceError struct{ RQLQueryLogicError }
type RQLResourceLimitError struct{ RQLRuntimeError }
type RQLUserError struct{ RQLRuntimeError }
type RQLInternalError struct{ RQLRuntimeError }
type RQLTimeoutError struct{ rqlServerError }
type RQLAvailabilityError struct{ RQLRuntimeError }
type RQLOpFailedError struct{ RQLAvailabilityError }
type RQLOpIndeterminateError struct{ RQLAvailabilityError }

// RQLDriverError represents an unexpected error with the driver, if this error
// persists please create an issue.
type RQLDriverError struct {
	rqlError
}

// RQLConnectionError represents an error when communicating with the database
// server.
type RQLConnectionError struct {
	rqlError
}

func createRuntimeError(errorType p.Response_ErrorType, response *Response, term *Term) error {
	serverErr := rqlServerError{response, term}

	switch errorType {
	case p.Response_QUERY_LOGIC:
		return RQLQueryLogicError{RQLRuntimeError{serverErr}}
	case p.Response_NON_EXISTENCE:
		return RQLNonExistenceError{RQLQueryLogicError{RQLRuntimeError{serverErr}}}
	case p.Response_RESOURCE_LIMIT:
		return RQLResourceLimitError{RQLRuntimeError{serverErr}}
	case p.Response_USER:
		return RQLUserError{RQLRuntimeError{serverErr}}
	case p.Response_INTERNAL:
		return RQLInternalError{RQLRuntimeError{serverErr}}
	case p.Response_OP_FAILED:
		return RQLOpFailedError{RQLAvailabilityError{RQLRuntimeError{serverErr}}}
	case p.Response_OP_INDETERMINATE:
		return RQLOpIndeterminateError{RQLAvailabilityError{RQLRuntimeError{serverErr}}}
	default:
		return RQLRuntimeError{serverErr}
	}
}
<commit_msg>errors.go: fix infinite recursion in rqlError.Error()<commit_after>package gorethink

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"

	p "github.com/dancannon/gorethink/ql2"
)

var (
	// ErrNoHosts is returned when no hosts to the Connect method.
	ErrNoHosts = errors.New("no hosts provided")
	// ErrNoConnectionsStarted is returned when the driver couldn't to any of
	// the provided hosts.
	ErrNoConnectionsStarted = errors.New("no connections were made when creating the session")
	// ErrInvalidNode is returned when attempting to connect to a node which
	// returns an invalid response.
	ErrInvalidNode = errors.New("invalid node")
	// ErrNoConnections is returned when there are no active connections in the
	// clusters connection pool.
	ErrNoConnections = errors.New("gorethink: no connections were available")
	// ErrConnectionClosed is returned when trying to send a query with a closed
	// connection.
	ErrConnectionClosed = errors.New("gorethink: the connection is closed")
)

func printCarrots(t Term, frames []*p.Frame) string {
	var frame *p.Frame
	if len(frames) > 1 {
		frame, frames = frames[0], frames[1:]
	} else if len(frames) == 1 {
		frame, frames = frames[0], []*p.Frame{}
	}

	for i, arg := range t.args {
		if frame.GetPos() == int64(i) {
			t.args[i] = Term{
				termType: p.Term_DATUM,
				data:     printCarrots(arg, frames),
			}
		}
	}

	for k, arg := range t.optArgs {
		if frame.GetOpt() == k {
			t.optArgs[k] = Term{
				termType: p.Term_DATUM,
				data:     printCarrots(arg, frames),
			}
		}
	}

	b := &bytes.Buffer{}
	for _, c := range t.String() {
		if c != '^' {
			b.WriteString(" ")
		} else {
			b.WriteString("^")
		}
	}

	return b.String()
}

// Error constants
var ErrEmptyResult = errors.New("The result does not contain any more rows")

// Connection/Response errors

// rqlResponseError is the base type for all errors, it formats both
// for the response and query if set.
type rqlServerError struct {
	response *Response
	term     *Term
}

func (e rqlServerError) Error() string {
	var err = "An error occurred"
	if e.response != nil {
		json.Unmarshal(e.response.Responses[0], &err)
	}

	if e.term == nil {
		return fmt.Sprintf("gorethink: %s", err)
	}

	return fmt.Sprintf("gorethink: %s in: \n%s", err, e.term.String())

}

func (e rqlServerError) String() string {
	return e.Error()
}

type rqlError string

func (e rqlError) Error() string {
	return fmt.Sprintf("gorethink: %s", string(e))
}

func (e rqlError) String() string {
	return e.Error()
}

// Exported Error "Implementations"

type RQLClientError struct{ rqlServerError }
type RQLCompileError struct{ rqlServerError }
type RQLDriverCompileError struct{ RQLCompileError }
type RQLServerCompileError struct{ RQLCompileError }
type RQLAuthError struct{ RQLDriverError }
type RQLRuntimeError struct{ rqlServerError }

type RQLQueryLogicError struct{ RQLRuntimeError }
type RQLNonExistenceError struct{ RQLQueryLogicError }
type RQLResourceLimitError struct{ RQLRuntimeError }
type RQLUserError struct{ RQLRuntimeError }
type RQLInternalError struct{ RQLRuntimeError }
type RQLTimeoutError struct{ rqlServerError }
type RQLAvailabilityError struct{ RQLRuntimeError }
type RQLOpFailedError struct{ RQLAvailabilityError }
type RQLOpIndeterminateError struct{ RQLAvailabilityError }

// RQLDriverError represents an unexpected error with the driver, if this error
// persists please create an issue.
type RQLDriverError struct {
	rqlError
}

// RQLConnectionError represents an error when communicating with the database
// server.
type RQLConnectionError struct {
	rqlError
}

func createRuntimeError(errorType p.Response_ErrorType, response *Response, term *Term) error {
	serverErr := rqlServerError{response, term}

	switch errorType {
	case p.Response_QUERY_LOGIC:
		return RQLQueryLogicError{RQLRuntimeError{serverErr}}
	case p.Response_NON_EXISTENCE:
		return RQLNonExistenceError{RQLQueryLogicError{RQLRuntimeError{serverErr}}}
	case p.Response_RESOURCE_LIMIT:
		return RQLResourceLimitError{RQLRuntimeError{serverErr}}
	case p.Response_USER:
		return RQLUserError{RQLRuntimeError{serverErr}}
	case p.Response_INTERNAL:
		return RQLInternalError{RQLRuntimeError{serverErr}}
	case p.Response_OP_FAILED:
		return RQLOpFailedError{RQLAvailabilityError{RQLRuntimeError{serverErr}}}
	case p.Response_OP_INDETERMINATE:
		return RQLOpIndeterminateError{RQLAvailabilityError{RQLRuntimeError{serverErr}}}
	default:
		return RQLRuntimeError{serverErr}
	}
}
<|endoftext|>


<commit_before>package errors

import (
	"bytes"
	"encoding/json"
	"fmt"
	"hash/crc32"
	"io/ioutil"
	"strconv"
	"strings"
	"text/template"

	"github.com/facebookgo/stack"
	uuid "github.com/nu7hatch/gouuid"
)

const (
	no_VALUE = "<no value>"
)

const (
	ERRCODE_PARSE_TPL_ERROR = 100
	ERRCODE_EXEC_TPL_ERROR  = 101
)

var (
	UsingLoadedTemplate = true
)

var (
	errorTemplate  map[uint64]errCodeTemplate
	errCodeDefined map[uint64]bool
)

func init() {
	errorTemplate = make(map[uint64]errCodeTemplate)
	errCodeDefined = make(map[uint64]bool)
}

type Params map[string]interface{}

type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}

func New(text string) error {
	return &errorString{text}
}

func Errorf(format string, a ...interface{}) error {
	return fmt.Errorf(format, a...)
}

func T(code uint64, template string) errCodeTemplate {
	if _, exist := errCodeDefined[code]; exist {
		strErr := fmt.Sprintf("error code %d already exist", code)
		panic(strErr)
	} else {
		errCodeDefined[code] = true
	}
	return errCodeTemplate{code: code, template: template}
}

type ErrorContext map[string]interface{}

func (p ErrorContext) String() string {
	if bJson, e := json.Marshal(p); e == nil {
		return string(bJson)
	}
	return ""
}

type ErrCode interface {
	Id() string
	Code() uint64
	Error() string
	StackTrace() string
	Context() ErrorContext
	FullError() error
}

type errCodeTemplate struct {
	code     uint64
	template string
}

func (p *errCodeTemplate) New(v ...Params) (err ErrCode) {
	params := Params{}
	if v != nil {
		for _, param := range v {
			for pn, pv := range param {
				params[pn] = pv
			}
		}
	}

	var tpl *errCodeTemplate = p
	if UsingLoadedTemplate {
		if t, exist := errorTemplate[p.code]; exist {
			tpl = &t
		}
	}

	strCode := fmt.Sprintf("ERRCODE:%d", tpl.code)

	stack := stack.CallersMulti(1)

	errId := "<NO-UUID>"
	if errUUID, e := uuid.NewV4(); e == nil {
		errId = errUUID.String()
	}

	crcErrId := crc32.ChecksumIEEE([]byte(errId))

	if t, e := template.New(strCode).Parse(tpl.template); e != nil {
		strErr := fmt.Sprintf("parser error template failed, code: %d, error: %s", tpl.code, e)
		err = &errorCode{id: errId, id_crc: crcErrId, code: ERRCODE_PARSE_TPL_ERROR, message: strErr, stackTrace: stack.String(), context: params}
		return
	} else {
		var buf bytes.Buffer
		if e := t.Execute(&buf, params); e != nil {
			strErr := fmt.Sprintf("execute template failed, code: %d, error: %s", tpl.code, e)
			return &errorCode{id: errId, id_crc: crcErrId, code: ERRCODE_EXEC_TPL_ERROR, message: strErr, stackTrace: stack.String(), context: params}
		} else {
			bufstr := strings.Replace(buf.String(), no_VALUE, "[NO_VALUE]", -1)
			return &errorCode{id: errId, id_crc: crcErrId, code: tpl.code, message: bufstr, stackTrace: stack.String(), context: params}
		}
	}
}

func (p *errCodeTemplate) IsEqual(err error) bool {
	if e, ok := err.(ErrCode); ok {
		if e.Code() == p.code {
			return true
		}
	}
	return false
}

type errorCode struct {
	id         string
	id_crc     uint32
	code       uint64
	message    string
	stackTrace string
	context    map[string]interface{}
}

func (p *errorCode) Id() string {
	return p.id
}

func (p *errorCode) Code() uint64 {
	return p.code
}

func (p *errorCode) Error() string {
	return fmt.Sprintf("[ERR-%d-%0xd]: %s", p.code, p.id_crc, p.message)
}

func (p *errorCode) FullError() error {
	errLines := make([]string, 1)
	errLines[0] = fmt.Sprintf("ERR_ID: %s\nCODE: %d-%0xd", p.id, p.code, p.id_crc)
	errLines = append(errLines, "MESSAGE:")
	errLines = append(errLines, p.message)
	errLines = append(errLines, "CONTEXT:")
	errLines = append(errLines, p.Context().String())
	errLines = append(errLines, "ORIGINAL_STACK_TRACE:")
	errLines = append(errLines, p.stackTrace)
	return New(strings.Join(errLines, "\n"))
}

func (p *errorCode) Context() ErrorContext {
	return p.context
}

func (p *errorCode) StackTrace() string {
	return p.stackTrace
}

func LoadMessageTemplate(fileName string) error {
	var fileLines []string
	if bFile, e := ioutil.ReadFile(fileName); e != nil {
		return e
	} else {
		fileLines = strings.Split(string(bFile), "\n")
	}

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

	for i, line := range fileLines {

		line = strings.TrimSpace(line)
		line = strings.TrimRight(line, "\r\n")
		if line == "" {
			continue
		}

		datas := strings.Split(line, "=")

		if len(datas) != 2 {
			return Errorf("the error code template column count is not equal 2, line: %d", i+1)
		}

		strCode := strings.TrimSpace(datas[0])
		tmpl := strings.TrimSpace(datas[1])

		if code, e := strconv.ParseUint(strCode, 10, 32); e != nil {
			return e
		} else if code > 0 {
			if _, exist := errorTemplate[code]; exist {
				return Errorf("error code of %d already exist, line %d", code, i+1)
			}
			errorTemplate[code] = errCodeTemplate{code: code, template: tmpl}
		} else {
			return Errorf("error code should greater than 0, line %d", i+1)
		}
	}
	return nil
}

func IsErrCode(err error) bool {
	_, ok := err.(ErrCode)
	return ok
}
<commit_msg>move stack.CallersMulti to stack.CallersDeepth<commit_after>package errors

import (
	"bytes"
	"encoding/json"
	"fmt"
	"hash/crc32"
	"io/ioutil"
	"strconv"
	"strings"
	"text/template"

	"github.com/gogap/stack"
	uuid "github.com/nu7hatch/gouuid"
)

const (
	no_VALUE = "<no value>"
)

const (
	ERRCODE_PARSE_TPL_ERROR = 100
	ERRCODE_EXEC_TPL_ERROR  = 101
)

var (
	UsingLoadedTemplate = true
)

var (
	errorTemplate  map[uint64]errCodeTemplate
	errCodeDefined map[uint64]bool
)

func init() {
	errorTemplate = make(map[uint64]errCodeTemplate)
	errCodeDefined = make(map[uint64]bool)
}

type Params map[string]interface{}

type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}

func New(text string) error {
	return &errorString{text}
}

func Errorf(format string, a ...interface{}) error {
	return fmt.Errorf(format, a...)
}

func T(code uint64, template string) errCodeTemplate {
	if _, exist := errCodeDefined[code]; exist {
		strErr := fmt.Sprintf("error code %d already exist", code)
		panic(strErr)
	} else {
		errCodeDefined[code] = true
	}
	return errCodeTemplate{code: code, template: template}
}

type ErrorContext map[string]interface{}

func (p ErrorContext) String() string {
	if bJson, e := json.Marshal(p); e == nil {
		return string(bJson)
	}
	return ""
}

type ErrCode interface {
	Id() string
	Code() uint64
	Error() string
	StackTrace() string
	Context() ErrorContext
	FullError() error
}

type errCodeTemplate struct {
	code     uint64
	template string
}

func (p *errCodeTemplate) New(v ...Params) (err ErrCode) {
	params := Params{}
	if v != nil {
		for _, param := range v {
			for pn, pv := range param {
				params[pn] = pv
			}
		}
	}

	var tpl *errCodeTemplate = p
	if UsingLoadedTemplate {
		if t, exist := errorTemplate[p.code]; exist {
			tpl = &t
		}
	}

	strCode := fmt.Sprintf("ERRCODE:%d", tpl.code)

	stack := stack.CallersDeepth(1, 5)

	errId := "<NO-UUID>"
	if errUUID, e := uuid.NewV4(); e == nil {
		errId = errUUID.String()
	}

	crcErrId := crc32.ChecksumIEEE([]byte(errId))

	if t, e := template.New(strCode).Parse(tpl.template); e != nil {
		strErr := fmt.Sprintf("parser error template failed, code: %d, error: %s", tpl.code, e)
		err = &errorCode{id: errId, id_crc: crcErrId, code: ERRCODE_PARSE_TPL_ERROR, message: strErr, stackTrace: stack.String(), context: params}
		return
	} else {
		var buf bytes.Buffer
		if e := t.Execute(&buf, params); e != nil {
			strErr := fmt.Sprintf("execute template failed, code: %d, error: %s", tpl.code, e)
			return &errorCode{id: errId, id_crc: crcErrId, code: ERRCODE_EXEC_TPL_ERROR, message: strErr, stackTrace: stack.String(), context: params}
		} else {
			bufstr := strings.Replace(buf.String(), no_VALUE, "[NO_VALUE]", -1)
			return &errorCode{id: errId, id_crc: crcErrId, code: tpl.code, message: bufstr, stackTrace: stack.String(), context: params}
		}
	}
}

func (p *errCodeTemplate) IsEqual(err error) bool {
	if e, ok := err.(ErrCode); ok {
		if e.Code() == p.code {
			return true
		}
	}
	return false
}

type errorCode struct {
	id         string
	id_crc     uint32
	code       uint64
	message    string
	stackTrace string
	context    map[string]interface{}
}

func (p *errorCode) Id() string {
	return p.id
}

func (p *errorCode) Code() uint64 {
	return p.code
}

func (p *errorCode) Error() string {
	return fmt.Sprintf("[ERR-%d-%0xd]: %s", p.code, p.id_crc, p.message)
}

func (p *errorCode) FullError() error {
	errLines := make([]string, 1)
	errLines[0] = fmt.Sprintf("ERR_ID: %s\nCODE: %d-%0xd", p.id, p.code, p.id_crc)
	errLines = append(errLines, "MESSAGE:")
	errLines = append(errLines, p.message)
	errLines = append(errLines, "CONTEXT:")
	errLines = append(errLines, p.Context().String())
	errLines = append(errLines, "ORIGINAL_STACK_TRACE:")
	errLines = append(errLines, p.stackTrace)
	return New(strings.Join(errLines, "\n"))
}

func (p *errorCode) Context() ErrorContext {
	return p.context
}

func (p *errorCode) StackTrace() string {
	return p.stackTrace
}

func LoadMessageTemplate(fileName string) error {
	var fileLines []string
	if bFile, e := ioutil.ReadFile(fileName); e != nil {
		return e
	} else {
		fileLines = strings.Split(string(bFile), "\n")
	}

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

	for i, line := range fileLines {

		line = strings.TrimSpace(line)
		line = strings.TrimRight(line, "\r\n")
		if line == "" {
			continue
		}

		datas := strings.Split(line, "=")

		if len(datas) != 2 {
			return Errorf("the error code template column count is not equal 2, line: %d", i+1)
		}

		strCode := strings.TrimSpace(datas[0])
		tmpl := strings.TrimSpace(datas[1])

		if code, e := strconv.ParseUint(strCode, 10, 32); e != nil {
			return e
		} else if code > 0 {
			if _, exist := errorTemplate[code]; exist {
				return Errorf("error code of %d already exist, line %d", code, i+1)
			}
			errorTemplate[code] = errCodeTemplate{code: code, template: tmpl}
		} else {
			return Errorf("error code should greater than 0, line %d", i+1)
		}
	}
	return nil
}

func IsErrCode(err error) bool {
	_, ok := err.(ErrCode)
	return ok
}
<|endoftext|>


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

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/danryan/hal"
)

var eventHandler = hal.Hear(listenName+` events`, func(res *hal.Response) error {
	events, err := getCalendarEvents()
	if err != nil {
		hal.Logger.Error("failed to call Calendar API: %v", err)
		return res.Send("Could not fetch data from Google Calendar API, please try again later")
	}

	return res.Send(events)
})

var (
	baseURL     = "https://www.googleapis.com/calendar/v3/calendars"
	accessToken AccessToken
)

// AccessToken contains the current oauth2 token and its expiry time.
type AccessToken struct {
	Token string
	Valid time.Time
}

func (a *AccessToken) getExpireTime(o int) {
	n := time.Now()
	d := time.Duration(o) * time.Second

	a.Valid = n.Add(d)
}

func (a *AccessToken) expiredToken() bool {
	n := time.Now()
	if a.Valid.After(n) {
		return true
	}

	return false
}

// Event is the top-level of the JSON return from the calendar API.
type Event struct {
	// Kind is the type of collection ("calendar#events")
	Kind string `json:"kind"`
	// Etag is the etag of the collection
	Etag string `json:"etag"`
	// Summary is the name of the calendar
	Summary string `json:"summary"`
	// Description is the description of the calendar
	Description string `json:"descritpion"`
	// Updated is the last modified time for the calendar
	Updated string `json:"updated"`
	// TimeZone is the timezone for the calendar
	TimeZone string `json:"timeZone"`
	// AccessRole is the role of the current user.
	// possible values include: "none", "freeBuzyReader", "reader", "writer", "owner"
	AccessRole string `json:"accessRole"`
	// NextPageToken is used to access the next page of this result. Omitted if no
	// further results are available, in which case nextSyncToken is provided.
	NextPageToken string `json:"nextPageToken,omitempty"`
	// Items is the list of events on the calendar.
	Items []EventItem `json:"items"`
	// NextSyncToken is used at a later point in time to retrieve only the entries
	// that have changed since this result was returned. Omitted if further results
	// are available, in which case nextPageToken is provided.
	NextSyncToken string `json:"nextSyncToken"`
}

// EventItem contains items with-in the "items" list of the JSON.
type EventItem struct {
	// Kind is the type of collection ("calendar#event")
	Kind string `json:"kind"`
	// Etag string `json:"etag"`
	Etag string `json:"etag"`
	// ID is the ID of the event
	ID string `json:"id"`
	// Status is the status of the event
	Status string `json:"status"`
	// HTMLLink is the link to the event on the calendar
	HTMLLink string `json:"htmlLink"`
	// Created is the datetime stamp that the event was created
	Created string `json:"created"`
	// Updated is the datetame stamp that the event was last modified
	Updated string `json:"updated"`
	// Summary is the name of the event
	Summary string `json:"summary"`
	// Description is the body of the event
	Description string `json:"description"`
	// Location is the address for the event
	Location string `json:"location"`
	// Creator is the user that created the event
	Creator EventCreator `json:"creator"`
	// Organizer is the organizer information
	organizer EventOrganizer `json:"organizer"`
	// Start is the start date and time
	Start EventDateTime `json:"start"`
	// End is the end date and time
	End EventDateTime `json:"end"`
	// ICalUID is the iCal ID for the event
	ICalUID string `json:"uCalUID"`
	// Sequence denotes if this is a repeating event
	Sequence int `json:"sequence"`
	// Reminders are the event reminders
	Reminders EventReminder `json:"reminders"`
}

// EventCreator contains the fields for the creator object.
type EventCreator struct {
	// Email address for the event creator
	Email string `json:"email"`
	// DisplayName is the real name of the creator
	DisplayName string `json:"displayName"`
}

// EventOrganizer contains the fields for the organizer object.
type EventOrganizer struct {
	// Email address for the event organizer
	Email string `json:"email"`
	// DisplayName is the name of the event organizer
	DisplayName string `json:"displayName"`
	// Self denotes if the organizer is the current user
	Self bool `json:self"`
}

// EventDateTime contains the fields for the "start" and "end" objects.
type EventDateTime struct {
	// DateTime is the start/end datetime in  RFC 3339 format
	DateTime string `json:"dateTime"`
	// TimeZone is the Timezone for the event
	TimeZone string `json:"timeZone,omitempty"`
}

//EventReminder contains the fields for the reminders object.
type EventReminder struct {
	// UseDefault denotes if Google Calendar default reminders are used
	UseDefault bool `json:"useDefault"`
}

func getCalendarEvents() (string, error) {
	var err error

	if accessToken.Token == "" ||
		accessToken.expiredToken() {
		accessToken, err = getOauth2Token()
		if err != nil {
			return "", err
		}
	}

	URL := fmt.Sprintf("%s/4qc3thgj9ocunpfist563utr6g@group.calendar.google.com/events?access_token=%s&singleEvents=true&orderBy=startTime&timeMin=%s&maxResults=7",
		baseURL, url.QueryEscape(accessToken.Token),
		url.QueryEscape(time.Now().Format("2006-01-02T15:04:05Z")))
	resp, err := http.Get(URL)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var Events Event

	err = json.Unmarshal(body, &Events)
	if err != nil {
		return "", err
	}

	eventList := getEventList(Events)

	return eventList, nil
}

func getOauth2Token() (AccessToken, error) {
	type Responce struct {
		Token   string `json:"access_token"`
		Expires int    `json:"expires_in"`
	}

	clientID := os.Getenv("CHADEV_ID")
	clientSecret := os.Getenv("CHADEV_SECRET")
	refreshToken := os.Getenv("CHADEV_TOKEN")

	var r Responce

	body := fmt.Sprintf("client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token",
		clientID, clientSecret, refreshToken)
	b := strings.NewReader(body)

	resp, err := http.Post("https://accounts.google.com/o/oauth2/token", "application/x-www-form-urlencoded", b)
	if err != nil {
		return accessToken, err
	}
	defer resp.Body.Close()

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return accessToken, err
	}

	err = json.Unmarshal(respBody, &r)
	if err != nil {
		return accessToken, err
	}

	accessToken.Token = r.Token
	accessToken.getExpireTime(r.Expires)

	return accessToken, nil
}

func getEventList(events Event) string {
	var output string

	output = "Next 7 events: "
	for key, event := range events.Items {
		if key == 0 {
			output += event.Summary
		} else {
			output += ", " + event.Summary
		}
		output += " (" + formatDate(event.Start.DateTime) + ")"
	}

	return output
}

func formatDate(s string) string {
	date, err := time.Parse(time.RFC3339, s)
	if err != nil {
		return ""
	}

	return date.Format("01/02")
}
<commit_msg>Add time to events output<commit_after>// Copyright 2014 Chadev. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/danryan/hal"
)

var eventHandler = hal.Hear(listenName+` events`, func(res *hal.Response) error {
	events, err := getCalendarEvents()
	if err != nil {
		hal.Logger.Error("failed to call Calendar API: %v", err)
		return res.Send("Could not fetch data from Google Calendar API, please try again later")
	}

	return res.Send(events)
})

var (
	baseURL     = "https://www.googleapis.com/calendar/v3/calendars"
	accessToken AccessToken
)

// AccessToken contains the current oauth2 token and its expiry time.
type AccessToken struct {
	Token string
	Valid time.Time
}

func (a *AccessToken) getExpireTime(o int) {
	n := time.Now()
	d := time.Duration(o) * time.Second

	a.Valid = n.Add(d)
}

func (a *AccessToken) expiredToken() bool {
	n := time.Now()
	if a.Valid.After(n) {
		return true
	}

	return false
}

// Event is the top-level of the JSON return from the calendar API.
type Event struct {
	// Kind is the type of collection ("calendar#events")
	Kind string `json:"kind"`
	// Etag is the etag of the collection
	Etag string `json:"etag"`
	// Summary is the name of the calendar
	Summary string `json:"summary"`
	// Description is the description of the calendar
	Description string `json:"descritpion"`
	// Updated is the last modified time for the calendar
	Updated string `json:"updated"`
	// TimeZone is the timezone for the calendar
	TimeZone string `json:"timeZone"`
	// AccessRole is the role of the current user.
	// possible values include: "none", "freeBuzyReader", "reader", "writer", "owner"
	AccessRole string `json:"accessRole"`
	// NextPageToken is used to access the next page of this result. Omitted if no
	// further results are available, in which case nextSyncToken is provided.
	NextPageToken string `json:"nextPageToken,omitempty"`
	// Items is the list of events on the calendar.
	Items []EventItem `json:"items"`
	// NextSyncToken is used at a later point in time to retrieve only the entries
	// that have changed since this result was returned. Omitted if further results
	// are available, in which case nextPageToken is provided.
	NextSyncToken string `json:"nextSyncToken"`
}

// EventItem contains items with-in the "items" list of the JSON.
type EventItem struct {
	// Kind is the type of collection ("calendar#event")
	Kind string `json:"kind"`
	// Etag string `json:"etag"`
	Etag string `json:"etag"`
	// ID is the ID of the event
	ID string `json:"id"`
	// Status is the status of the event
	Status string `json:"status"`
	// HTMLLink is the link to the event on the calendar
	HTMLLink string `json:"htmlLink"`
	// Created is the datetime stamp that the event was created
	Created string `json:"created"`
	// Updated is the datetame stamp that the event was last modified
	Updated string `json:"updated"`
	// Summary is the name of the event
	Summary string `json:"summary"`
	// Description is the body of the event
	Description string `json:"description"`
	// Location is the address for the event
	Location string `json:"location"`
	// Creator is the user that created the event
	Creator EventCreator `json:"creator"`
	// Organizer is the organizer information
	organizer EventOrganizer `json:"organizer"`
	// Start is the start date and time
	Start EventDateTime `json:"start"`
	// End is the end date and time
	End EventDateTime `json:"end"`
	// ICalUID is the iCal ID for the event
	ICalUID string `json:"uCalUID"`
	// Sequence denotes if this is a repeating event
	Sequence int `json:"sequence"`
	// Reminders are the event reminders
	Reminders EventReminder `json:"reminders"`
}

// EventCreator contains the fields for the creator object.
type EventCreator struct {
	// Email address for the event creator
	Email string `json:"email"`
	// DisplayName is the real name of the creator
	DisplayName string `json:"displayName"`
}

// EventOrganizer contains the fields for the organizer object.
type EventOrganizer struct {
	// Email address for the event organizer
	Email string `json:"email"`
	// DisplayName is the name of the event organizer
	DisplayName string `json:"displayName"`
	// Self denotes if the organizer is the current user
	Self bool `json:self"`
}

// EventDateTime contains the fields for the "start" and "end" objects.
type EventDateTime struct {
	// DateTime is the start/end datetime in  RFC 3339 format
	DateTime string `json:"dateTime"`
	// TimeZone is the Timezone for the event
	TimeZone string `json:"timeZone,omitempty"`
}

//EventReminder contains the fields for the reminders object.
type EventReminder struct {
	// UseDefault denotes if Google Calendar default reminders are used
	UseDefault bool `json:"useDefault"`
}

func getCalendarEvents() (string, error) {
	var err error

	if accessToken.Token == "" ||
		accessToken.expiredToken() {
		accessToken, err = getOauth2Token()
		if err != nil {
			return "", err
		}
	}

	URL := fmt.Sprintf("%s/4qc3thgj9ocunpfist563utr6g@group.calendar.google.com/events?access_token=%s&singleEvents=true&orderBy=startTime&timeMin=%s&maxResults=7",
		baseURL, url.QueryEscape(accessToken.Token),
		url.QueryEscape(time.Now().Format("2006-01-02T15:04:05Z")))
	resp, err := http.Get(URL)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var Events Event

	err = json.Unmarshal(body, &Events)
	if err != nil {
		return "", err
	}

	eventList := getEventList(Events)

	return eventList, nil
}

func getOauth2Token() (AccessToken, error) {
	type Responce struct {
		Token   string `json:"access_token"`
		Expires int    `json:"expires_in"`
	}

	clientID := os.Getenv("CHADEV_ID")
	clientSecret := os.Getenv("CHADEV_SECRET")
	refreshToken := os.Getenv("CHADEV_TOKEN")

	var r Responce

	body := fmt.Sprintf("client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token",
		clientID, clientSecret, refreshToken)
	b := strings.NewReader(body)

	resp, err := http.Post("https://accounts.google.com/o/oauth2/token", "application/x-www-form-urlencoded", b)
	if err != nil {
		return accessToken, err
	}
	defer resp.Body.Close()

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return accessToken, err
	}

	err = json.Unmarshal(respBody, &r)
	if err != nil {
		return accessToken, err
	}

	accessToken.Token = r.Token
	accessToken.getExpireTime(r.Expires)

	return accessToken, nil
}

func getEventList(events Event) string {
	var output string

	output = "Next 7 events: "
	for key, event := range events.Items {
		if key == 0 {
			output += event.Summary
		} else {
			output += ", " + event.Summary
		}
		output += " (" + formatDate(event.Start.DateTime) + ")"
	}

	return output
}

func formatDate(s string) string {
	date, err := time.Parse(time.RFC3339, s)
	if err != nil {
		return ""
	}

	return date.Format("01/02 3:04 pm")
}
<|endoftext|>


<commit_before>package exif44

import (
	"bytes"
	"errors"
	tiff "github.com/garyhouston/tiff66"
)

// Tags in the Exif IFD.
const (
	ExposureTime              = 0x829A
	FNumber                   = 0x829D
	ExposureProgram           = 0x8822
	SpectralSensitivity       = 0x8824
	PhotographicSensitivity   = 0x8827
	OECF                      = 0x8828
	SensitivityType           = 0x8830
	StandardOutputSensitivity = 0x8831
	RecommendedExposureIndex  = 0x8832
	ISOSpeed                  = 0x8833
	ISOSpeedLatitudeyyy       = 0x8834
	ISOSpeedLatitudezzz       = 0x8835
	ExifVersion               = 0x9000
	DateTimeOriginal          = 0x9003
	DateTimeDigitized         = 0x9004
	ComponentsConfiguration   = 0x9101
	CompressedBitsPerPixel    = 0x9102
	ShutterSpeedValue         = 0x9201
	ApertureValue             = 0x9202
	BrightnessValue           = 0x9203
	ExposureBiasValue         = 0x9204
	MaxApertureValue          = 0x9205
	SubjectDistance           = 0x9206
	MeteringMode              = 0x9207
	LightSource               = 0x9208
	Flash                     = 0x9209
	FocalLength               = 0x920A
	SubjectArea               = 0x9214
	MakerNote                 = 0x927C
	UserComment               = 0x9286
	SubSecTime                = 0x9290
	SubSecTimeOriginal        = 0x9291
	SubSecTimeDigitized       = 0x9292
	FlashpixVersion           = 0xA000
	ColorSpace                = 0xA001
	PixelXDimension           = 0xA002
	PixelYDimension           = 0xA003
	RelatedSoundFile          = 0xA004
	InteroperabilityIFD       = 0xA005
	FlashEnergy               = 0xA20B
	SpatialFrequencyResponse  = 0xA20C
	FocalPlaneXResolution     = 0xA20E
	FocalPlaneYResolution     = 0xA20F
	FocalPlaneResolutionUnit  = 0xA210
	SubjectLocation           = 0xA214
	ExposureIndex             = 0xA215
	SensingMethod             = 0xA217
	FileSource                = 0xA300
	SceneType                 = 0xA301
	CFAPattern                = 0xA302
	CustomRendered            = 0xA401
	ExposureMode              = 0xA402
	WhiteBalance              = 0xA403
	DigitalZoomRatio          = 0xA404
	FocalLengthIn35mmFilm     = 0xA405
	SceneCaptureType          = 0xA406
	GainControl               = 0xA407
	Contrast                  = 0xA408
	Saturation                = 0xA409
	Sharpness                 = 0xA40A
	DeviceSettingDescription  = 0xA40B
	SubjectDistanceRange      = 0xA40C
	ImageUniqueID             = 0xA420
	CameraOwnerName           = 0xA430
	BodySerialNumber          = 0xA431
	LensSpecification         = 0xA432
	LensMake                  = 0xA433
	LensModel                 = 0xA434
	LensSerialNumber          = 0xA435
	Gamma                     = 0xA500
)

// Mapping from Exif tags to strings.
var ExifTagNames = map[tiff.Tag]string{
	ExposureTime:            "ExposureTime",
	FNumber:                 "FNumber",
	ExposureProgram:         "ExposureProgram",
	SpectralSensitivity:     "SpectralSensitivity",
	PhotographicSensitivity: "PhotographicSensitivity",
	OECF:                      "OECF",
	SensitivityType:           "SensitivityType",
	StandardOutputSensitivity: "StandardOutputSensitivity",
	RecommendedExposureIndex:  "RecommendedExposureIndex",
	ISOSpeed:                  "ISOSpeed",
	ISOSpeedLatitudeyyy:       "ISOSpeedLatitudeyyy",
	ISOSpeedLatitudezzz:       "ISOSpeedLatitudezzz",
	ExifVersion:               "ExifVersion",
	DateTimeOriginal:          "DateTimeOriginal",
	DateTimeDigitized:         "DateTimeDigitized",
	ComponentsConfiguration:   "ComponentsConfiguration",
	CompressedBitsPerPixel:    "CompressedBitsPerPixel",
	ShutterSpeedValue:         "ShutterSpeedValue",
	ApertureValue:             "ApertureValue",
	BrightnessValue:           "BrightnessValue",
	ExposureBiasValue:         "ExposureBiasValue",
	MaxApertureValue:          "MaxApertureValue",
	SubjectDistance:           "SubjectDistance",
	MeteringMode:              "MeteringMode",
	LightSource:               "LightSource",
	Flash:                     "Flash",
	FocalLength:               "FocalLength",
	SubjectArea:               "SubjectArea",
	MakerNote:                 "MakerNote",
	UserComment:               "UserComment",
	SubSecTime:                "SubSecTime",
	SubSecTimeOriginal:        "SubSecTimeOriginal",
	SubSecTimeDigitized:       "SubSecTimeDigitized",
	FlashpixVersion:           "FlashpixVersion",
	ColorSpace:                "ColorSpace",
	PixelXDimension:           "PixelXDimension",
	PixelYDimension:           "PixelYDimension",
	RelatedSoundFile:          "RelatedSoundFile",
	InteroperabilityIFD:       "InteroperabilityIFD",
	FlashEnergy:               "FlashEnergy",
	SpatialFrequencyResponse:  "SpatialFrequencyResponse",
	FocalPlaneXResolution:     "FocalPlaneXResolution",
	FocalPlaneYResolution:     "FocalPlaneYResolution",
	FocalPlaneResolutionUnit:  "FocalPlaneResolutionUnit",
	SubjectLocation:           "SubjectLocation",
	ExposureIndex:             "ExposureIndex",
	SensingMethod:             "SensingMethod",
	FileSource:                "FileSource",
	SceneType:                 "SceneType",
	CFAPattern:                "CFAPattern",
	CustomRendered:            "CustomRendered",
	ExposureMode:              "ExposureMode",
	WhiteBalance:              "WhiteBalance",
	DigitalZoomRatio:          "DigitalZoomRatio",
	FocalLengthIn35mmFilm:     "FocalLengthIn35mmFilm",
	SceneCaptureType:          "SceneCaptureType",
	GainControl:               "GainControl",
	Contrast:                  "Contrast",
	Saturation:                "Saturation",
	Sharpness:                 "Sharpness",
	DeviceSettingDescription:  "DeviceSettingDescription",
	SubjectDistanceRange:      "SubjectDistanceRange",
	ImageUniqueID:             "ImageUniqueID",
	CameraOwnerName:           "CameraOwnerName",
	BodySerialNumber:          "BodySerialNumber",
	LensSpecification:         "LensSpecification",
	LensMake:                  "LensMake",
	LensModel:                 "LensModel",
	LensSerialNumber:          "LensSerialNumber",
	Gamma:                     "Gamma",
}

// Tags in the Interoperability IFD.
const (
	InteroperabilityIndex   = 0x1
	InteroperabilityVersion = 0x2
)

// Mapping from Interoperability tags to strings.
var InteropTagNames = map[tiff.Tag]string{
	InteroperabilityIndex:   "InteroperabilityIndex",
	InteroperabilityVersion: "InteroperabilityVersion",
}

// Tags in the GPS IFD.
const (
	GPSVersionID         = 0x00
	GPSLatitudeRef       = 0x01
	GPSLatitude          = 0x02
	GPSLongitudeRef      = 0x03
	GPSLongitude         = 0x04
	GPSAltitudeRef       = 0x05
	GPSAltitude          = 0x06
	GPSTimeStamp         = 0x07
	GPSSatellites        = 0x08
	GPSStatus            = 0x09
	GPSMeasureMode       = 0x0A
	GPSDOP               = 0x0B
	GPSSpeedRef          = 0x0C
	GPSSpeed             = 0x0D
	GPSTrackRef          = 0x0E
	GPSTrack             = 0x0F
	GPSImgDirectionRef   = 0x10
	GPSImgDirection      = 0x11
	GPSMapDatum          = 0x12
	GPSDestLatitudeRef   = 0x13
	GPSDestLatitude      = 0x14
	GPSDestLongitudeRef  = 0x15
	GPSDestLongitude     = 0x16
	GPSDestBearingRef    = 0x17
	GPSDestBearing       = 0x18
	GPSDestDistanceRef   = 0x19
	GPSDestDistance      = 0x1A
	GPSProcessingMethod  = 0x1B
	GPSAreaInformation   = 0x1C
	GPSDateStamp         = 0x1D
	GPSDifferential      = 0x1E
	GPSHPositioningError = 0x1F
)

// Mapping from GPS tags to strings.
var GPSTagNames = map[tiff.Tag]string{
	GPSVersionID:         "GPSVersionID",
	GPSLatitudeRef:       "GPSLatitudeRef",
	GPSLatitude:          "GPSLatitude",
	GPSLongitudeRef:      "GPSLongitudeRef",
	GPSLongitude:         "GPSLongitude",
	GPSAltitudeRef:       "GPSAltitudeRef",
	GPSAltitude:          "GPSAltitude",
	GPSTimeStamp:         "GPSTimeStamp",
	GPSSatellites:        "GPSSatellites",
	GPSStatus:            "GPSStatus",
	GPSMeasureMode:       "GPSMeasureMode",
	GPSDOP:               "GPSDOP",
	GPSSpeedRef:          "GPSSpeedRef",
	GPSSpeed:             "GPSSpeed",
	GPSTrackRef:          "GPSTrackRef",
	GPSTrack:             "GPSTrack",
	GPSImgDirectionRef:   "GPSImgDirectionRef",
	GPSImgDirection:      "GPSImgDirection",
	GPSMapDatum:          "GPSMapDatum",
	GPSDestLatitudeRef:   "GPSDestLatitudeRef",
	GPSDestLatitude:      "GPSDestLatitude",
	GPSDestLongitudeRef:  "GPSDestLongitudeRef",
	GPSDestLongitude:     "GPSDestLongitude",
	GPSDestBearingRef:    "GPSDestBearingRef",
	GPSDestBearing:       "GPSDestBearing",
	GPSDestDistanceRef:   "GPSDestDistanceRef",
	GPSDestDistance:      "GPSDestDistance",
	GPSProcessingMethod:  "GPSProcessingMethod",
	GPSAreaInformation:   "GPSAreaInformation",
	GPSDateStamp:         "GPSDateStamp",
	GPSDifferential:      "GPSDifferential",
	GPSHPositioningError: "GPSHPositioningError",
}

// Return the tag->name map for given namespace, or a nil map if the space
// is unknown.
func TagNameMap(space tiff.TagSpace) map[tiff.Tag]string {
	var names map[tiff.Tag]string
	switch space {
	case tiff.TIFFSpace:
		names = tiff.TagNames
	case tiff.ExifSpace:
		names = ExifTagNames
	case tiff.InteropSpace:
		names = InteropTagNames
	case tiff.GPSSpace:
		names = GPSTagNames
	case tiff.Panasonic1Space:
		names = Panasonic1TagNames
	}
	return names
}

// Exif header, as found in a JPEG APP1 segment.
var header = []byte("Exif\000\000")

// Size of an Exif header.
const HeaderSize = 6

// Check if a slice starts with an Exif header, as found in a JPEG
// APP1 segment.  Returns a flag and the position of the next byte.
func GetHeader(buf []byte) (bool, uint32) {
	if uint32(len(buf)) >= HeaderSize && bytes.Compare(buf[:HeaderSize], header) == 0 {
		return true, HeaderSize
	} else {
		return false, 0
	}
}

// Put an Exif header, as for a JPEG APP1 segment, at the start of a slice,
// returning the position of the next byte.
func PutHeader(buf []byte) uint32 {
	copy(buf, header)
	return HeaderSize
}

type Exif struct {
	TIFF      *tiff.IFDNode // Pointer to top-level TIFF node, IFD0. This is the root of the tree containing all other nodes.
	Exif      *tiff.IFDNode // Pointer to Exif in Tree.
	GPS       *tiff.IFDNode // Pointer to GPS in Tree.
	Interop   *tiff.IFDNode // Pointer to Interop in Tree.
	Thumbnail *tiff.IFDNode // Pointer to TIFF IFD1 in Tree.
	MakerNote *tiff.IFDNode // Pointer to maker note in Tree.
}

// Unpack a TIFF header and tree from a slice, as for GetHeader and
// GetIFDTree from tiff66, and also return pointers to any Exif
// subIFDs that are present. As for GetIFDTree, field data in the
// structures points into the original byte slice, so modifying one
// will modify the other.
func GetExifTree(buf []byte) (*Exif, error) {
	valid, order, ifdpos := tiff.GetHeader(buf)
	if !valid {
		return nil, errors.New("GetExif: Invalid Tiff header")
	}
	node, err := tiff.GetIFDTree(buf, order, ifdpos, tiff.TIFFSpace)
	if err != nil {
		return nil, err
	}
	exif := Exif{}
	exif.TIFF = node
	for _, sub := range node.SubIFDs {
		if sub.Node.Space == tiff.ExifSpace {
			exif.Exif = sub.Node
			for _, esub := range sub.Node.SubIFDs {
				if esub.Node.Space == tiff.InteropSpace {
					exif.Interop = esub.Node
				} else if esub.Node.Space.IsMakerNote() {
					exif.MakerNote = esub.Node
				}
			}
		} else if sub.Node.Space == tiff.GPSSpace {
			exif.GPS = sub.Node
		}
	}
	if node.Next != nil {
		exif.Thumbnail = node.Next
	}
	return &exif, nil
}

// Return the size of a buffer needed to serialize the tree in an Exif
// structure in TIFF format, including the TIFF header, but excluding
// the Exif header used in JPEG files.
func (exif Exif) TreeSize() uint32 {
	return tiff.HeaderSize + exif.TIFF.TreeSize()
}

// Pack Exif data into a slice in TIFF format. The slice should start
// with the first byte following any Exif header. Returns the position
// following the last byte used.
func (exif *Exif) Put(buf []byte) (uint32, error) {
	tiff.PutHeader(buf, exif.TIFF.Order, tiff.HeaderSize)
	return exif.TIFF.PutIFDTree(buf, tiff.HeaderSize)
}
<commit_msg>Fix an error message<commit_after>package exif44

import (
	"bytes"
	"errors"
	tiff "github.com/garyhouston/tiff66"
)

// Tags in the Exif IFD.
const (
	ExposureTime              = 0x829A
	FNumber                   = 0x829D
	ExposureProgram           = 0x8822
	SpectralSensitivity       = 0x8824
	PhotographicSensitivity   = 0x8827
	OECF                      = 0x8828
	SensitivityType           = 0x8830
	StandardOutputSensitivity = 0x8831
	RecommendedExposureIndex  = 0x8832
	ISOSpeed                  = 0x8833
	ISOSpeedLatitudeyyy       = 0x8834
	ISOSpeedLatitudezzz       = 0x8835
	ExifVersion               = 0x9000
	DateTimeOriginal          = 0x9003
	DateTimeDigitized         = 0x9004
	ComponentsConfiguration   = 0x9101
	CompressedBitsPerPixel    = 0x9102
	ShutterSpeedValue         = 0x9201
	ApertureValue             = 0x9202
	BrightnessValue           = 0x9203
	ExposureBiasValue         = 0x9204
	MaxApertureValue          = 0x9205
	SubjectDistance           = 0x9206
	MeteringMode              = 0x9207
	LightSource               = 0x9208
	Flash                     = 0x9209
	FocalLength               = 0x920A
	SubjectArea               = 0x9214
	MakerNote                 = 0x927C
	UserComment               = 0x9286
	SubSecTime                = 0x9290
	SubSecTimeOriginal        = 0x9291
	SubSecTimeDigitized       = 0x9292
	FlashpixVersion           = 0xA000
	ColorSpace                = 0xA001
	PixelXDimension           = 0xA002
	PixelYDimension           = 0xA003
	RelatedSoundFile          = 0xA004
	InteroperabilityIFD       = 0xA005
	FlashEnergy               = 0xA20B
	SpatialFrequencyResponse  = 0xA20C
	FocalPlaneXResolution     = 0xA20E
	FocalPlaneYResolution     = 0xA20F
	FocalPlaneResolutionUnit  = 0xA210
	SubjectLocation           = 0xA214
	ExposureIndex             = 0xA215
	SensingMethod             = 0xA217
	FileSource                = 0xA300
	SceneType                 = 0xA301
	CFAPattern                = 0xA302
	CustomRendered            = 0xA401
	ExposureMode              = 0xA402
	WhiteBalance              = 0xA403
	DigitalZoomRatio          = 0xA404
	FocalLengthIn35mmFilm     = 0xA405
	SceneCaptureType          = 0xA406
	GainControl               = 0xA407
	Contrast                  = 0xA408
	Saturation                = 0xA409
	Sharpness                 = 0xA40A
	DeviceSettingDescription  = 0xA40B
	SubjectDistanceRange      = 0xA40C
	ImageUniqueID             = 0xA420
	CameraOwnerName           = 0xA430
	BodySerialNumber          = 0xA431
	LensSpecification         = 0xA432
	LensMake                  = 0xA433
	LensModel                 = 0xA434
	LensSerialNumber          = 0xA435
	Gamma                     = 0xA500
)

// Mapping from Exif tags to strings.
var ExifTagNames = map[tiff.Tag]string{
	ExposureTime:            "ExposureTime",
	FNumber:                 "FNumber",
	ExposureProgram:         "ExposureProgram",
	SpectralSensitivity:     "SpectralSensitivity",
	PhotographicSensitivity: "PhotographicSensitivity",
	OECF:                      "OECF",
	SensitivityType:           "SensitivityType",
	StandardOutputSensitivity: "StandardOutputSensitivity",
	RecommendedExposureIndex:  "RecommendedExposureIndex",
	ISOSpeed:                  "ISOSpeed",
	ISOSpeedLatitudeyyy:       "ISOSpeedLatitudeyyy",
	ISOSpeedLatitudezzz:       "ISOSpeedLatitudezzz",
	ExifVersion:               "ExifVersion",
	DateTimeOriginal:          "DateTimeOriginal",
	DateTimeDigitized:         "DateTimeDigitized",
	ComponentsConfiguration:   "ComponentsConfiguration",
	CompressedBitsPerPixel:    "CompressedBitsPerPixel",
	ShutterSpeedValue:         "ShutterSpeedValue",
	ApertureValue:             "ApertureValue",
	BrightnessValue:           "BrightnessValue",
	ExposureBiasValue:         "ExposureBiasValue",
	MaxApertureValue:          "MaxApertureValue",
	SubjectDistance:           "SubjectDistance",
	MeteringMode:              "MeteringMode",
	LightSource:               "LightSource",
	Flash:                     "Flash",
	FocalLength:               "FocalLength",
	SubjectArea:               "SubjectArea",
	MakerNote:                 "MakerNote",
	UserComment:               "UserComment",
	SubSecTime:                "SubSecTime",
	SubSecTimeOriginal:        "SubSecTimeOriginal",
	SubSecTimeDigitized:       "SubSecTimeDigitized",
	FlashpixVersion:           "FlashpixVersion",
	ColorSpace:                "ColorSpace",
	PixelXDimension:           "PixelXDimension",
	PixelYDimension:           "PixelYDimension",
	RelatedSoundFile:          "RelatedSoundFile",
	InteroperabilityIFD:       "InteroperabilityIFD",
	FlashEnergy:               "FlashEnergy",
	SpatialFrequencyResponse:  "SpatialFrequencyResponse",
	FocalPlaneXResolution:     "FocalPlaneXResolution",
	FocalPlaneYResolution:     "FocalPlaneYResolution",
	FocalPlaneResolutionUnit:  "FocalPlaneResolutionUnit",
	SubjectLocation:           "SubjectLocation",
	ExposureIndex:             "ExposureIndex",
	SensingMethod:             "SensingMethod",
	FileSource:                "FileSource",
	SceneType:                 "SceneType",
	CFAPattern:                "CFAPattern",
	CustomRendered:            "CustomRendered",
	ExposureMode:              "ExposureMode",
	WhiteBalance:              "WhiteBalance",
	DigitalZoomRatio:          "DigitalZoomRatio",
	FocalLengthIn35mmFilm:     "FocalLengthIn35mmFilm",
	SceneCaptureType:          "SceneCaptureType",
	GainControl:               "GainControl",
	Contrast:                  "Contrast",
	Saturation:                "Saturation",
	Sharpness:                 "Sharpness",
	DeviceSettingDescription:  "DeviceSettingDescription",
	SubjectDistanceRange:      "SubjectDistanceRange",
	ImageUniqueID:             "ImageUniqueID",
	CameraOwnerName:           "CameraOwnerName",
	BodySerialNumber:          "BodySerialNumber",
	LensSpecification:         "LensSpecification",
	LensMake:                  "LensMake",
	LensModel:                 "LensModel",
	LensSerialNumber:          "LensSerialNumber",
	Gamma:                     "Gamma",
}

// Tags in the Interoperability IFD.
const (
	InteroperabilityIndex   = 0x1
	InteroperabilityVersion = 0x2
)

// Mapping from Interoperability tags to strings.
var InteropTagNames = map[tiff.Tag]string{
	InteroperabilityIndex:   "InteroperabilityIndex",
	InteroperabilityVersion: "InteroperabilityVersion",
}

// Tags in the GPS IFD.
const (
	GPSVersionID         = 0x00
	GPSLatitudeRef       = 0x01
	GPSLatitude          = 0x02
	GPSLongitudeRef      = 0x03
	GPSLongitude         = 0x04
	GPSAltitudeRef       = 0x05
	GPSAltitude          = 0x06
	GPSTimeStamp         = 0x07
	GPSSatellites        = 0x08
	GPSStatus            = 0x09
	GPSMeasureMode       = 0x0A
	GPSDOP               = 0x0B
	GPSSpeedRef          = 0x0C
	GPSSpeed             = 0x0D
	GPSTrackRef          = 0x0E
	GPSTrack             = 0x0F
	GPSImgDirectionRef   = 0x10
	GPSImgDirection      = 0x11
	GPSMapDatum          = 0x12
	GPSDestLatitudeRef   = 0x13
	GPSDestLatitude      = 0x14
	GPSDestLongitudeRef  = 0x15
	GPSDestLongitude     = 0x16
	GPSDestBearingRef    = 0x17
	GPSDestBearing       = 0x18
	GPSDestDistanceRef   = 0x19
	GPSDestDistance      = 0x1A
	GPSProcessingMethod  = 0x1B
	GPSAreaInformation   = 0x1C
	GPSDateStamp         = 0x1D
	GPSDifferential      = 0x1E
	GPSHPositioningError = 0x1F
)

// Mapping from GPS tags to strings.
var GPSTagNames = map[tiff.Tag]string{
	GPSVersionID:         "GPSVersionID",
	GPSLatitudeRef:       "GPSLatitudeRef",
	GPSLatitude:          "GPSLatitude",
	GPSLongitudeRef:      "GPSLongitudeRef",
	GPSLongitude:         "GPSLongitude",
	GPSAltitudeRef:       "GPSAltitudeRef",
	GPSAltitude:          "GPSAltitude",
	GPSTimeStamp:         "GPSTimeStamp",
	GPSSatellites:        "GPSSatellites",
	GPSStatus:            "GPSStatus",
	GPSMeasureMode:       "GPSMeasureMode",
	GPSDOP:               "GPSDOP",
	GPSSpeedRef:          "GPSSpeedRef",
	GPSSpeed:             "GPSSpeed",
	GPSTrackRef:          "GPSTrackRef",
	GPSTrack:             "GPSTrack",
	GPSImgDirectionRef:   "GPSImgDirectionRef",
	GPSImgDirection:      "GPSImgDirection",
	GPSMapDatum:          "GPSMapDatum",
	GPSDestLatitudeRef:   "GPSDestLatitudeRef",
	GPSDestLatitude:      "GPSDestLatitude",
	GPSDestLongitudeRef:  "GPSDestLongitudeRef",
	GPSDestLongitude:     "GPSDestLongitude",
	GPSDestBearingRef:    "GPSDestBearingRef",
	GPSDestBearing:       "GPSDestBearing",
	GPSDestDistanceRef:   "GPSDestDistanceRef",
	GPSDestDistance:      "GPSDestDistance",
	GPSProcessingMethod:  "GPSProcessingMethod",
	GPSAreaInformation:   "GPSAreaInformation",
	GPSDateStamp:         "GPSDateStamp",
	GPSDifferential:      "GPSDifferential",
	GPSHPositioningError: "GPSHPositioningError",
}

// Return the tag->name map for given namespace, or a nil map if the space
// is unknown.
func TagNameMap(space tiff.TagSpace) map[tiff.Tag]string {
	var names map[tiff.Tag]string
	switch space {
	case tiff.TIFFSpace:
		names = tiff.TagNames
	case tiff.ExifSpace:
		names = ExifTagNames
	case tiff.InteropSpace:
		names = InteropTagNames
	case tiff.GPSSpace:
		names = GPSTagNames
	case tiff.Panasonic1Space:
		names = Panasonic1TagNames
	}
	return names
}

// Exif header, as found in a JPEG APP1 segment.
var header = []byte("Exif\000\000")

// Size of an Exif header.
const HeaderSize = 6

// Check if a slice starts with an Exif header, as found in a JPEG
// APP1 segment.  Returns a flag and the position of the next byte.
func GetHeader(buf []byte) (bool, uint32) {
	if uint32(len(buf)) >= HeaderSize && bytes.Compare(buf[:HeaderSize], header) == 0 {
		return true, HeaderSize
	} else {
		return false, 0
	}
}

// Put an Exif header, as for a JPEG APP1 segment, at the start of a slice,
// returning the position of the next byte.
func PutHeader(buf []byte) uint32 {
	copy(buf, header)
	return HeaderSize
}

type Exif struct {
	TIFF      *tiff.IFDNode // Pointer to top-level TIFF node, IFD0. This is the root of the tree containing all other nodes.
	Exif      *tiff.IFDNode // Pointer to Exif in Tree.
	GPS       *tiff.IFDNode // Pointer to GPS in Tree.
	Interop   *tiff.IFDNode // Pointer to Interop in Tree.
	Thumbnail *tiff.IFDNode // Pointer to TIFF IFD1 in Tree.
	MakerNote *tiff.IFDNode // Pointer to maker note in Tree.
}

// Unpack a TIFF header and tree from a slice, as for GetHeader and
// GetIFDTree from tiff66, and also return pointers to any Exif
// subIFDs that are present. As for GetIFDTree, field data in the
// structures points into the original byte slice, so modifying one
// will modify the other.
func GetExifTree(buf []byte) (*Exif, error) {
	valid, order, ifdpos := tiff.GetHeader(buf)
	if !valid {
		return nil, errors.New("GetExifTree: Invalid Tiff header")
	}
	node, err := tiff.GetIFDTree(buf, order, ifdpos, tiff.TIFFSpace)
	if err != nil {
		return nil, err
	}
	exif := Exif{}
	exif.TIFF = node
	for _, sub := range node.SubIFDs {
		if sub.Node.Space == tiff.ExifSpace {
			exif.Exif = sub.Node
			for _, esub := range sub.Node.SubIFDs {
				if esub.Node.Space == tiff.InteropSpace {
					exif.Interop = esub.Node
				} else if esub.Node.Space.IsMakerNote() {
					exif.MakerNote = esub.Node
				}
			}
		} else if sub.Node.Space == tiff.GPSSpace {
			exif.GPS = sub.Node
		}
	}
	if node.Next != nil {
		exif.Thumbnail = node.Next
	}
	return &exif, nil
}

// Return the size of a buffer needed to serialize the tree in an Exif
// structure in TIFF format, including the TIFF header, but excluding
// the Exif header used in JPEG files.
func (exif Exif) TreeSize() uint32 {
	return tiff.HeaderSize + exif.TIFF.TreeSize()
}

// Pack Exif data into a slice in TIFF format. The slice should start
// with the first byte following any Exif header. Returns the position
// following the last byte used.
func (exif *Exif) Put(buf []byte) (uint32, error) {
	tiff.PutHeader(buf, exif.TIFF.Order, tiff.HeaderSize)
	return exif.TIFF.PutIFDTree(buf, tiff.HeaderSize)
}
<|endoftext|>


<commit_before>package feeder

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"net/http"
)

func ParseURL(URL string) (*Feed, error) {
	resp, err := http.Get(URL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return Parse(resp.Body)
}

func Parse(feed io.Reader) (*Feed, error) {
	result := new(Feed)
	var err error

	var buf bytes.Buffer
	tee := io.TeeReader(feed, &buf)

	ft := DetectFeedType(tee)

	r := io.MultiReader(&buf, feed)

	switch ft {
	case "feed":
		// fmt.Println("Atom FeedType")
		result, err = ParseAtom(r)
		return result, err
	case "rss":
		// fmt.Println("RSS FeedType")
		result, err := ParseRSS(r)
		return result, err
	}
	return result, err
}

func DetectFeedType(feed io.Reader) string {
	d := xml.NewDecoder(feed)
	for {
		token, err := d.Token()
		if err != nil {
			fmt.Println(err)
			break
		}
		tokentype, ok := token.(xml.StartElement)
		if ok {
			return tokentype.Name.Local
		}
	}
	return ""
}
<commit_msg>Detect unknown feed.<commit_after>package feeder

import (
	"bytes"
	"encoding/xml"
	"errors"
	"io"
	"net/http"
)

func ParseURL(URL string) (*Feed, error) {
	resp, err := http.Get(URL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return Parse(resp.Body)
}

func Parse(feed io.Reader) (*Feed, error) {
	result := new(Feed)
	var err error

	var buf bytes.Buffer
	tee := io.TeeReader(feed, &buf)

	ft, err := DetectFeedType(tee)
	if err != nil {
		return nil, err
	}

	r := io.MultiReader(&buf, feed)

	switch ft {
	case "feed":
		// fmt.Println("Atom FeedType")
		result, err = ParseAtom(r)
		return result, err
	case "rss":
		// fmt.Println("RSS FeedType")
		result, err := ParseRSS(r)
		return result, err
	default:
		return nil, errors.New("Unknown FeedType.")
	}
	return result, err
}

func DetectFeedType(feed io.Reader) (string, error) {
	d := xml.NewDecoder(feed)
	for {
		token, err := d.Token()
		if err != nil {
			return "", err
		}
		tokentype, ok := token.(xml.StartElement)
		if ok {
			return tokentype.Name.Local, nil
		}
	}
	return "unknown", errors.New("Unknown content.")
}
<|endoftext|>


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

package dashboard

// This file handles identities of people.

import (
	"sort"
)

var (
	emailToPerson  = make(map[string]string) // email => person
	preferredEmail = make(map[string]string) // person => email
	personList     []string
)

func init() {
	// People we assume have golang.org and google.com accounts,
	// and prefer to use their golang.org address for code review.
	gophers := [...]string{
		"adg",
		"agl",
		"bradfitz",
		"campoy",
		"cshapiro",
		"dsymonds",
		"gri",
		"iant",
		"mpvl",
		"nigeltao",
		"r",
		"rsc",
		"sameer",
	}
	for _, p := range gophers {
		personList = append(personList, p)
		emailToPerson[p+"@golang.org"] = p
		emailToPerson[p+"@google.com"] = p
		preferredEmail[p] = p + "@golang.org"
	}
	// Other people.
	others := map[string]string{
		"adonovan": "adonovan@google.com",
		"brainman": "alex.brainman@gmail.com",
		"ality":    "ality@pbrane.org",
		"dfc":      "dave@cheney.net",
		"dvyukov":  "dvyukov@google.com",
		"gustavo":  "gustavo@niemeyer.net",
		"jsing":    "jsing@google.com",
		"mikio":    "mikioh.mikioh@gmail.com",
		"minux":    "minux.ma@gmail.com",
		"remy":     "remyoudompheng@gmail.com",
		"rminnich": "rminnich@gmail.com",
	}
	for p, e := range others {
		personList = append(personList, p)
		emailToPerson[e] = p
		preferredEmail[p] = e
	}

	sort.Strings(personList)
}
<commit_msg>codereview: add khr as a person<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dashboard

// This file handles identities of people.

import (
	"sort"
)

var (
	emailToPerson  = make(map[string]string) // email => person
	preferredEmail = make(map[string]string) // person => email
	personList     []string
)

func init() {
	// People we assume have golang.org and google.com accounts,
	// and prefer to use their golang.org address for code review.
	gophers := [...]string{
		"adg",
		"agl",
		"bradfitz",
		"campoy",
		"cshapiro",
		"dsymonds",
		"gri",
		"iant",
		"khr",
		"mpvl",
		"nigeltao",
		"r",
		"rsc",
		"sameer",
	}
	for _, p := range gophers {
		personList = append(personList, p)
		emailToPerson[p+"@golang.org"] = p
		emailToPerson[p+"@google.com"] = p
		preferredEmail[p] = p + "@golang.org"
	}
	// Other people.
	others := map[string]string{
		"adonovan": "adonovan@google.com",
		"brainman": "alex.brainman@gmail.com",
		"ality":    "ality@pbrane.org",
		"dfc":      "dave@cheney.net",
		"dvyukov":  "dvyukov@google.com",
		"gustavo":  "gustavo@niemeyer.net",
		"jsing":    "jsing@google.com",
		"mikio":    "mikioh.mikioh@gmail.com",
		"minux":    "minux.ma@gmail.com",
		"remy":     "remyoudompheng@gmail.com",
		"rminnich": "rminnich@gmail.com",
	}
	for p, e := range others {
		personList = append(personList, p)
		emailToPerson[e] = p
		preferredEmail[p] = e
	}

	sort.Strings(personList)
}
<|endoftext|>