<commit_before>package imap

import (
	"errors"
	"strings"
	"time"
)

// TODO: support AND with same fields (e.g. BCC mickey BCC mouse)

// A search criteria.
// See RFC 3501 section 6.4.4 for a description of each field.
type SearchCriteria struct {
	SeqSet     *SeqSet
	Answered   bool
	Bcc        string
	Before     time.Time
	Body       string
	Cc         string
	Deleted    bool
	Draft      bool
	Flagged    bool
	From       string
	Header     [2]string
	Keyword    string
	Larger     uint32
	New        bool
	Not        *SearchCriteria
	Old        bool
	On         time.Time
	Or         [2]*SearchCriteria
	Recent     bool
	Seen       bool
	SentBefore time.Time
	SentOn     time.Time
	SentSince  time.Time
	Since      time.Time
	Smaller    uint32
	Subject    string
	Text       string
	To         string
	Uid        *SeqSet
	Unanswered bool
	Undeleted  bool
	Undraft    bool
	Unflagged  bool
	Unkeyword  string
	Unseen     bool
}

// Parse search criteria from fields.
func (c *SearchCriteria) Parse(fields []interface{}) error {
	// TODO: do not panic when criteria is malformed

	for i := 0; i < len(fields); i++ {
		f, ok := fields[i].(string)
		if !ok {
			return errors.New("Invalid search criteria field")
		}

		switch strings.ToUpper(f) {
		case "ALL":
			// Nothing to do
		case "ANSWERED":
			c.Answered = true
		case "BCC":
			i++
			c.Bcc, _ = fields[i].(string)
		case "BEFORE":
			i++
			c.Before, _ = time.Parse(DateFormat, fields[i].(string))
		case "BODY":
			i++
			c.Body, _ = fields[i].(string)
		case "CC":
			i++
			c.Cc, _ = fields[i].(string)
		case "DELETED":
			c.Deleted = true
		case "DRAFT":
			c.Draft = true
		case "FLAGGED":
			c.Flagged = true
		case "FROM":
			i++
			c.From, _ = fields[i].(string)
		case "HEADER":
			i++
			name, _ := fields[i].(string)

			i++
			value, _ := fields[i].(string)

			c.Header = [2]string{name, value}
		case "KEYWORD":
			i++
			c.Keyword, _ = fields[i].(string)
		case "LARGER":
			i++
			c.Larger, _ = ParseNumber(fields[i])
		case "NEW":
			c.New = true
		case "NOT":
			i++
			not, _ := fields[i].([]interface{})
			c.Not = &SearchCriteria{}
			if err := c.Not.Parse(not); err != nil {
				return err
			}
		case "OLD":
			c.Old = true
		case "ON":
			i++
			c.On, _ = time.Parse(DateFormat, fields[i].(string))
		case "OR":
			i++
			leftFields, _ := fields[i].([]interface{})

			i++
			rightFields, _ := fields[i].([]interface{})

			c.Or = [2]*SearchCriteria{&SearchCriteria{}, &SearchCriteria{}}
			if err := c.Or[0].Parse(leftFields); err != nil {
				return err
			}
			if err := c.Or[1].Parse(rightFields); err != nil {
				return err
			}
		case "RECENT":
			c.Recent = true
		case "SEEN":
			c.Seen = true
		case "SENTBEFORE":
			i++
			c.SentBefore, _ = time.Parse(DateFormat, fields[i].(string))
		case "SENTON":
			i++
			c.SentOn, _ = time.Parse(DateFormat, fields[i].(string))
		case "SENTSINCE":
			i++
			c.SentSince, _ = time.Parse(DateFormat, fields[i].(string))
		case "SINCE":
			i++
			c.Since, _ = time.Parse(DateFormat, fields[i].(string))
		case "SMALLER":
			i++
			c.Smaller, _ = ParseNumber(fields[i].(string))
		case "SUBJECT":
			i++
			c.Subject, _ = fields[i].(string)
		case "TEXT":
			i++
			c.Text, _ = fields[i].(string)
		case "TO":
			i++
			c.To, _ = fields[i].(string)
		case "UID":
			i++
			s, _ := fields[i].(string)
			c.Uid, _ = NewSeqSet(s)
		case "UNANSWERED":
			c.Unanswered = true
		case "UNDELETED":
			c.Undeleted = true
		case "UNDRAFT":
			c.Undraft = true
		case "UNFLAGGED":
			c.Unflagged = true
		case "UNKEYWORD":
			i++
			c.Unkeyword, _ = fields[i].(string)
		case "UNSEEN":
			c.Unseen = true
		default:
			// Try to parse a sequence set
			var err error
			if c.SeqSet, err = NewSeqSet(f); err != nil {
				return err
			}
		}
	}

	return nil
}

// Format search criteria to fields.
func (c *SearchCriteria) Format() (fields []interface{}) {
	if c.SeqSet != nil {
		fields = append(fields, c.SeqSet)
	}

	if c.Answered {
		fields = append(fields, "ANSWERED")
	}
	if c.Bcc != "" {
		fields = append(fields, "BCC", c.Bcc)
	}
	if !c.Before.IsZero() {
		fields = append(fields, "BEFORE", c.Before.Format(DateFormat))
	}
	if c.Body != "" {
		fields = append(fields, "BODY", c.Body)
	}
	if c.Cc != "" {
		fields = append(fields, "CC", c.Cc)
	}
	if c.Deleted {
		fields = append(fields, "DELETED")
	}
	if c.Draft {
		fields = append(fields, "DRAFT")
	}
	if c.Flagged {
		fields = append(fields, "FLAGGED")
	}
	if c.From != "" {
		fields = append(fields, "FROM", c.From)
	}
	if c.Header[0] != "" && c.Header[1] != "" {
		fields = append(fields, "HEADER", c.Header[0], c.Header[1])
	}
	if c.Keyword != "" {
		fields = append(fields, "KEYWORD", c.Keyword)
	}
	if c.Larger != 0 {
		fields = append(fields, "LARGER", c.Larger)
	}
	if c.New {
		fields = append(fields, "NEW")
	}
	if c.Not != nil {
		fields = append(fields, "NOT", c.Not.Format())
	}
	if c.Old {
		fields = append(fields, "OLD")
	}
	if !c.On.IsZero() {
		fields = append(fields, "ON", c.On.Format(DateFormat))
	}
	if c.Or[0] != nil && c.Or[1] != nil {
		fields = append(fields, "OR", c.Or[0].Format(), c.Or[1].Format())
	}
	if c.Recent {
		fields = append(fields, "RECENT")
	}
	if c.Seen {
		fields = append(fields, "SEEN")
	}
	if !c.SentBefore.IsZero() {
		fields = append(fields, "SENTBEFORE", c.SentBefore.Format(DateFormat))
	}
	if !c.SentOn.IsZero() {
		fields = append(fields, "SENTON", c.SentOn.Format(DateFormat))
	}
	if !c.SentSince.IsZero() {
		fields = append(fields, "SENTSINCE", c.SentSince.Format(DateFormat))
	}
	if !c.Since.IsZero() {
		fields = append(fields, "SINCE", c.Since.Format(DateFormat))
	}
	if c.Smaller != 0 {
		fields = append(fields, "SMALLER", c.Smaller)
	}
	if c.Subject != "" {
		fields = append(fields, "SUBJECT", c.Subject)
	}
	if c.Text != "" {
		fields = append(fields, "TEXT", c.Text)
	}
	if c.To != "" {
		fields = append(fields, "TO", c.To)
	}
	if c.Uid != nil {
		fields = append(fields, "UID", c.Uid)
	}
	if c.Unanswered {
		fields = append(fields, "UNANSWERED")
	}
	if c.Undeleted {
		fields = append(fields, "UNDELETED")
	}
	if c.Undraft {
		fields = append(fields, "UNDRAFT")
	}
	if c.Unflagged {
		fields = append(fields, "UNFLAGGED")
	}
	if c.Unkeyword != "" {
		fields = append(fields, "UNKEYWORD", c.Unkeyword)
	}
	if c.Unseen {
		fields = append(fields, "UNSEEN")
	}

	return
}
<commit_msg>Fixes a crash whenever fields[i] is not a string.<commit_after>package imap

import (
	"errors"
	"strings"
	"time"
)

// TODO: support AND with same fields (e.g. BCC mickey BCC mouse)

// A search criteria.
// See RFC 3501 section 6.4.4 for a description of each field.
type SearchCriteria struct {
	SeqSet     *SeqSet
	Answered   bool
	Bcc        string
	Before     time.Time
	Body       string
	Cc         string
	Deleted    bool
	Draft      bool
	Flagged    bool
	From       string
	Header     [2]string
	Keyword    string
	Larger     uint32
	New        bool
	Not        *SearchCriteria
	Old        bool
	On         time.Time
	Or         [2]*SearchCriteria
	Recent     bool
	Seen       bool
	SentBefore time.Time
	SentOn     time.Time
	SentSince  time.Time
	Since      time.Time
	Smaller    uint32
	Subject    string
	Text       string
	To         string
	Uid        *SeqSet
	Unanswered bool
	Undeleted  bool
	Undraft    bool
	Unflagged  bool
	Unkeyword  string
	Unseen     bool
}

func maybeString(mystery interface{}) string {
	s, ok := mystery.(string)
	if ok {
		return s
	}

	return ""
}

// Parse search criteria from fields.
func (c *SearchCriteria) Parse(fields []interface{}) error {
	// TODO: do not panic when criteria is malformed

	for i := 0; i < len(fields); i++ {
		f, ok := fields[i].(string)
		if !ok {
			return errors.New("Invalid search criteria field")
		}

		switch strings.ToUpper(f) {
		case "ALL":
			// Nothing to do
		case "ANSWERED":
			c.Answered = true
		case "BCC":
			i++
			c.Bcc, _ = fields[i].(string)
		case "BEFORE":
			i++

			c.Before, _ = time.Parse(DateFormat, maybeString(fields[i]))
		case "BODY":
			i++
			c.Body, _ = fields[i].(string)
		case "CC":
			i++
			c.Cc, _ = fields[i].(string)
		case "DELETED":
			c.Deleted = true
		case "DRAFT":
			c.Draft = true
		case "FLAGGED":
			c.Flagged = true
		case "FROM":
			i++
			c.From, _ = fields[i].(string)
		case "HEADER":
			i++
			name, _ := fields[i].(string)

			i++
			value, _ := fields[i].(string)

			c.Header = [2]string{name, value}
		case "KEYWORD":
			i++
			c.Keyword, _ = fields[i].(string)
		case "LARGER":
			i++
			c.Larger, _ = ParseNumber(fields[i])
		case "NEW":
			c.New = true
		case "NOT":
			i++
			not, _ := fields[i].([]interface{})
			c.Not = &SearchCriteria{}
			if err := c.Not.Parse(not); err != nil {
				return err
			}
		case "OLD":
			c.Old = true
		case "ON":
			i++
			c.On, _ = time.Parse(DateFormat, maybeString(fields[i]))
		case "OR":
			i++
			leftFields, _ := fields[i].([]interface{})

			i++
			rightFields, _ := fields[i].([]interface{})

			c.Or = [2]*SearchCriteria{&SearchCriteria{}, &SearchCriteria{}}
			if err := c.Or[0].Parse(leftFields); err != nil {
				return err
			}
			if err := c.Or[1].Parse(rightFields); err != nil {
				return err
			}
		case "RECENT":
			c.Recent = true
		case "SEEN":
			c.Seen = true
		case "SENTBEFORE":
			i++
			c.SentBefore, _ = time.Parse(DateFormat, maybeString(fields[i]))
		case "SENTON":
			i++
			c.SentOn, _ = time.Parse(DateFormat, maybeString(fields[i]))
		case "SENTSINCE":
			i++
			c.SentSince, _ = time.Parse(DateFormat, maybeString(fields[i]))
		case "SINCE":
			i++
			c.Since, _ = time.Parse(DateFormat, maybeString(fields[i]))
		case "SMALLER":
			i++
			c.Smaller, _ = ParseNumber(fields[i])
		case "SUBJECT":
			i++
			c.Subject, _ = fields[i].(string)
		case "TEXT":
			i++
			c.Text, _ = fields[i].(string)
		case "TO":
			i++
			c.To, _ = fields[i].(string)
		case "UID":
			i++
			s, _ := fields[i].(string)
			c.Uid, _ = NewSeqSet(s)
		case "UNANSWERED":
			c.Unanswered = true
		case "UNDELETED":
			c.Undeleted = true
		case "UNDRAFT":
			c.Undraft = true
		case "UNFLAGGED":
			c.Unflagged = true
		case "UNKEYWORD":
			i++
			c.Unkeyword, _ = fields[i].(string)
		case "UNSEEN":
			c.Unseen = true
		default:
			// Try to parse a sequence set
			var err error
			if c.SeqSet, err = NewSeqSet(f); err != nil {
				return err
			}
		}
	}

	return nil
}

// Format search criteria to fields.
func (c *SearchCriteria) Format() (fields []interface{}) {
	if c.SeqSet != nil {
		fields = append(fields, c.SeqSet)
	}

	if c.Answered {
		fields = append(fields, "ANSWERED")
	}
	if c.Bcc != "" {
		fields = append(fields, "BCC", c.Bcc)
	}
	if !c.Before.IsZero() {
		fields = append(fields, "BEFORE", c.Before.Format(DateFormat))
	}
	if c.Body != "" {
		fields = append(fields, "BODY", c.Body)
	}
	if c.Cc != "" {
		fields = append(fields, "CC", c.Cc)
	}
	if c.Deleted {
		fields = append(fields, "DELETED")
	}
	if c.Draft {
		fields = append(fields, "DRAFT")
	}
	if c.Flagged {
		fields = append(fields, "FLAGGED")
	}
	if c.From != "" {
		fields = append(fields, "FROM", c.From)
	}
	if c.Header[0] != "" && c.Header[1] != "" {
		fields = append(fields, "HEADER", c.Header[0], c.Header[1])
	}
	if c.Keyword != "" {
		fields = append(fields, "KEYWORD", c.Keyword)
	}
	if c.Larger != 0 {
		fields = append(fields, "LARGER", c.Larger)
	}
	if c.New {
		fields = append(fields, "NEW")
	}
	if c.Not != nil {
		fields = append(fields, "NOT", c.Not.Format())
	}
	if c.Old {
		fields = append(fields, "OLD")
	}
	if !c.On.IsZero() {
		fields = append(fields, "ON", c.On.Format(DateFormat))
	}
	if c.Or[0] != nil && c.Or[1] != nil {
		fields = append(fields, "OR", c.Or[0].Format(), c.Or[1].Format())
	}
	if c.Recent {
		fields = append(fields, "RECENT")
	}
	if c.Seen {
		fields = append(fields, "SEEN")
	}
	if !c.SentBefore.IsZero() {
		fields = append(fields, "SENTBEFORE", c.SentBefore.Format(DateFormat))
	}
	if !c.SentOn.IsZero() {
		fields = append(fields, "SENTON", c.SentOn.Format(DateFormat))
	}
	if !c.SentSince.IsZero() {
		fields = append(fields, "SENTSINCE", c.SentSince.Format(DateFormat))
	}
	if !c.Since.IsZero() {
		fields = append(fields, "SINCE", c.Since.Format(DateFormat))
	}
	if c.Smaller != 0 {
		fields = append(fields, "SMALLER", c.Smaller)
	}
	if c.Subject != "" {
		fields = append(fields, "SUBJECT", c.Subject)
	}
	if c.Text != "" {
		fields = append(fields, "TEXT", c.Text)
	}
	if c.To != "" {
		fields = append(fields, "TO", c.To)
	}
	if c.Uid != nil {
		fields = append(fields, "UID", c.Uid)
	}
	if c.Unanswered {
		fields = append(fields, "UNANSWERED")
	}
	if c.Undeleted {
		fields = append(fields, "UNDELETED")
	}
	if c.Undraft {
		fields = append(fields, "UNDRAFT")
	}
	if c.Unflagged {
		fields = append(fields, "UNFLAGGED")
	}
	if c.Unkeyword != "" {
		fields = append(fields, "UNKEYWORD", c.Unkeyword)
	}
	if c.Unseen {
		fields = append(fields, "UNSEEN")
	}

	return
}
<|endoftext|>


<commit_before>package qb

import "fmt"

// Selectable is any clause from which we can select columns and is suitable
// as a FROM clause element
type Selectable interface {
	Clause
	All() []Clause
	ColumnList() []ColumnElem
	C(column string) ColumnElem
	DefaultName() string
}

// Select generates a select statement and returns it
func Select(clauses ...Clause) SelectStmt {
	return SelectStmt{
		sel:     clauses,
		groupBy: []ColumnElem{},
		having:  []HavingClause{},
	}
}

// SelectStmt is the base struct for building select statements
type SelectStmt struct {
	sel     []Clause
	from    Selectable
	groupBy []ColumnElem
	orderBy *OrderByClause
	having  []HavingClause
	where   *WhereClause
	offset  *int
	count   *int
}

// From sets the from selectable of select statement
func (s SelectStmt) From(selectable Selectable) SelectStmt {
	s.from = selectable
	return s
}

// Where sets the where clause of select statement
func (s SelectStmt) Where(clause Clause) SelectStmt {
	where := Where(clause)
	s.where = &where
	return s
}

// InnerJoin appends an inner join clause to the select statement
func (s SelectStmt) InnerJoin(right Selectable, onClauses ...Clause) SelectStmt {
	return s.From(Join("INNER JOIN", s.from, right, onClauses...))
}

// CrossJoin appends an cross join clause to the select statement
func (s SelectStmt) CrossJoin(right Selectable) SelectStmt {
	return s.From(Join("CROSS JOIN", s.from, right, nil))
}

// LeftJoin appends an left outer join clause to the select statement
func (s SelectStmt) LeftJoin(right Selectable, leftCol ColumnElem, rightCol ColumnElem) SelectStmt {
	return s.From(Join("LEFT OUTER JOIN", s.from, right, leftCol, rightCol))
}

// RightJoin appends a right outer join clause to select statement
func (s SelectStmt) RightJoin(right Selectable, leftCol ColumnElem, rightCol ColumnElem) SelectStmt {
	return s.From(Join("RIGHT OUTER JOIN", s.from, right, leftCol, rightCol))
}

// OrderBy generates an OrderByClause and sets select statement's orderbyclause
// OrderBy(usersTable.C("id")).Asc()
// OrderBy(usersTable.C("email")).Desc()
func (s SelectStmt) OrderBy(columns ...ColumnElem) SelectStmt {
	s.orderBy = &OrderByClause{columns, "ASC"}
	return s
}

// Asc sets the t type of current order by clause
// NOTE: Please use it after calling OrderBy()
func (s SelectStmt) Asc() SelectStmt {
	s.orderBy.t = "ASC"
	return s
}

// Desc sets the t type of current order by clause
// NOTE: Please use it after calling OrderBy()
func (s SelectStmt) Desc() SelectStmt {
	s.orderBy.t = "DESC"
	return s
}

// GroupBy appends columns to group by clause of the select statement
func (s SelectStmt) GroupBy(cols ...ColumnElem) SelectStmt {
	s.groupBy = append(s.groupBy, cols...)
	return s
}

// Having appends a having clause to select statement
func (s SelectStmt) Having(aggregate AggregateClause, op string, value interface{}) SelectStmt {
	s.having = append(s.having, HavingClause{aggregate, op, value})
	return s
}

// Limit sets the offset & count values of the select statement
func (s SelectStmt) Limit(offset int, count int) SelectStmt {
	s.offset = &offset
	s.count = &count
	return s
}

// Accept calls the compiler VisitSelect method
func (s SelectStmt) Accept(context *CompilerContext) string {
	return context.Compiler.VisitSelect(context, s)
}

// Build compiles the select statement and returns the Stmt
func (s SelectStmt) Build(dialect Dialect) *Stmt {
	defer dialect.Reset()

	context := NewCompilerContext(dialect)
	statement := Statement()
	statement.AddSQLClause(s.Accept(context))
	statement.AddBinding(context.Binds...)

	return statement
}

type joinOnClauseCandidate struct {
	source TableElem
	fkey   ForeignKeyConstraint
	target TableElem
}

// GuessJoinOnClause finds a join 'ON' clause between two tables
func GuessJoinOnClause(left Selectable, right Selectable) Clause {
	leftTable, ok := left.(TableElem)
	if !ok {
		panic("left Selectable is not a Table: Cannot guess join onClause")
	}
	rightTable, ok := right.(TableElem)
	if !ok {
		panic("right Selectable is not a Table: Cannot guess join onClause")
	}

	var candidates []joinOnClauseCandidate

	for _, fkey := range leftTable.ForeignKeyConstraints.FKeys {
		if fkey.RefTable != rightTable.Name {
			continue
		}
		candidates = append(
			candidates,
			joinOnClauseCandidate{leftTable, fkey, rightTable})
	}

	for _, fkey := range rightTable.ForeignKeyConstraints.FKeys {
		if fkey.RefTable != leftTable.Name {
			continue
		}
		candidates = append(
			candidates,
			joinOnClauseCandidate{rightTable, fkey, leftTable})
	}
	switch len(candidates) {
	case 0:
		panic(fmt.Sprintf(
			"No foreign keys found between %s and %s",
			leftTable.Name, rightTable.Name))
	case 1:
		candidate := candidates[0]
		var clauses []Clause
		for i, col := range candidate.fkey.Cols {
			refCol := candidate.fkey.RefCols[i]
			clauses = append(
				clauses,
				Eq(candidate.source.C(col), candidate.target.C(refCol)),
			)
		}
		if len(clauses) == 1 {
			return clauses[0]
		}
		return And(clauses...)
	default:
		panic(fmt.Sprintf(
			"Found %d foreign keys between %s and %s",
			len(candidates), leftTable.Name, rightTable.Name))
	}
}

// MakeJoinOnClause assemble a 'ON' clause for a join from either:
// 0 clause: attempt to guess the join clause (only if left & right are tables),
//           otherwise panics
// 1 clause: returns it
// 2 clauses: returns a Eq() of both
// otherwise if panics
func MakeJoinOnClause(left Selectable, right Selectable, onClause ...Clause) Clause {
	switch len(onClause) {
	case 0:
		return GuessJoinOnClause(left, right)
	case 1:
		return onClause[0]
	case 2:
		return Eq(onClause[0], onClause[1])
	default:
		panic("Cannot make a join condition with more than 2 clauses")
	}
}

func Join(joinType string, left Selectable, right Selectable, onClause ...Clause) JoinClause {
	return JoinClause{
		JoinType: joinType,
		Left:     left,
		Right:    right,
		OnClause: MakeJoinOnClause(left, right, onClause...),
	}
}

// JoinClause is the base struct for generating join clauses when using select
// It satisfies Clause interface
type JoinClause struct {
	JoinType string
	Left     Selectable
	Right    Selectable
	OnClause Clause
}

// Accept calls the compiler VisitJoin method
func (c JoinClause) Accept(context *CompilerContext) string {
	return context.Compiler.VisitJoin(context, c)
}

func (c JoinClause) All() []Clause {
	return append(c.Left.All(), c.Right.All()...)
}

func (c JoinClause) ColumnList() []ColumnElem {
	return append(c.Left.ColumnList(), c.Right.ColumnList()...)
}

func (c JoinClause) C(name string) ColumnElem {
	for _, c := range c.ColumnList() {
		if c.Name == name {
			return c
		}
	}
	panic(fmt.Sprintf("No such column '%s' in join %v", name, c))
}

func (c JoinClause) DefaultName() string {
	return ""
}

// OrderByClause is the base struct for generating order by clauses when using select
// It satisfies SQLClause interface
type OrderByClause struct {
	columns []ColumnElem
	t       string
}

// Accept generates an order by clause
func (c OrderByClause) Accept(context *CompilerContext) string {
	return context.Compiler.VisitOrderBy(context, c)
}

// HavingClause is the base struct for generating having clauses when using select
// It satisfies SQLClause interface
type HavingClause struct {
	aggregate AggregateClause
	op        string
	value     interface{}
}

// Accept generates having sql & bindings out of HavingClause struct
func (c HavingClause) Accept(context *CompilerContext) string {
	return context.Compiler.VisitHaving(context, c)
}

func Alias(name string, selectable Selectable) AliasClause {
	return AliasClause{
		Name:       name,
		Selectable: selectable,
	}
}

type AliasClause struct {
	Name       string
	Selectable Selectable
}

func (c AliasClause) Accept(context *CompilerContext) string {
	return context.Compiler.VisitAlias(context, c)
}

func (c AliasClause) C(name string) ColumnElem {
	col := c.Selectable.C(name)
	col.Table = c.Name
	return col
}

func (c AliasClause) All() []Clause {
	var clauses []Clause
	for _, col := range c.ColumnList() {
		clauses = append(clauses, col)
	}
	return clauses
}

func (c AliasClause) ColumnList() []ColumnElem {
	var cols []ColumnElem
	for _, col := range c.Selectable.ColumnList() {
		col.Table = c.Name
		cols = append(cols, col)
	}
	return cols
}

func (c AliasClause) DefaultName() string {
	return c.Name
}
<commit_msg>SelectStmt.*Join now takes ...Clause<commit_after>package qb

import "fmt"

// Selectable is any clause from which we can select columns and is suitable
// as a FROM clause element
type Selectable interface {
	Clause
	All() []Clause
	ColumnList() []ColumnElem
	C(column string) ColumnElem
	DefaultName() string
}

// Select generates a select statement and returns it
func Select(clauses ...Clause) SelectStmt {
	return SelectStmt{
		sel:     clauses,
		groupBy: []ColumnElem{},
		having:  []HavingClause{},
	}
}

// SelectStmt is the base struct for building select statements
type SelectStmt struct {
	sel     []Clause
	from    Selectable
	groupBy []ColumnElem
	orderBy *OrderByClause
	having  []HavingClause
	where   *WhereClause
	offset  *int
	count   *int
}

// From sets the from selectable of select statement
func (s SelectStmt) From(selectable Selectable) SelectStmt {
	s.from = selectable
	return s
}

// Where sets the where clause of select statement
func (s SelectStmt) Where(clause Clause) SelectStmt {
	where := Where(clause)
	s.where = &where
	return s
}

// InnerJoin appends an inner join clause to the select statement
func (s SelectStmt) InnerJoin(right Selectable, onClause ...Clause) SelectStmt {
	return s.From(Join("INNER JOIN", s.from, right, onClause...))
}

// CrossJoin appends an cross join clause to the select statement
func (s SelectStmt) CrossJoin(right Selectable) SelectStmt {
	return s.From(Join("CROSS JOIN", s.from, right, nil))
}

// LeftJoin appends an left outer join clause to the select statement
func (s SelectStmt) LeftJoin(right Selectable, onClause ...Clause) SelectStmt {
	return s.From(Join("LEFT OUTER JOIN", s.from, right, onClause...))
}

// RightJoin appends a right outer join clause to select statement
func (s SelectStmt) RightJoin(right Selectable, onClause ...Clause) SelectStmt {
	return s.From(Join("RIGHT OUTER JOIN", s.from, right, onClause...))
}

// OrderBy generates an OrderByClause and sets select statement's orderbyclause
// OrderBy(usersTable.C("id")).Asc()
// OrderBy(usersTable.C("email")).Desc()
func (s SelectStmt) OrderBy(columns ...ColumnElem) SelectStmt {
	s.orderBy = &OrderByClause{columns, "ASC"}
	return s
}

// Asc sets the t type of current order by clause
// NOTE: Please use it after calling OrderBy()
func (s SelectStmt) Asc() SelectStmt {
	s.orderBy.t = "ASC"
	return s
}

// Desc sets the t type of current order by clause
// NOTE: Please use it after calling OrderBy()
func (s SelectStmt) Desc() SelectStmt {
	s.orderBy.t = "DESC"
	return s
}

// GroupBy appends columns to group by clause of the select statement
func (s SelectStmt) GroupBy(cols ...ColumnElem) SelectStmt {
	s.groupBy = append(s.groupBy, cols...)
	return s
}

// Having appends a having clause to select statement
func (s SelectStmt) Having(aggregate AggregateClause, op string, value interface{}) SelectStmt {
	s.having = append(s.having, HavingClause{aggregate, op, value})
	return s
}

// Limit sets the offset & count values of the select statement
func (s SelectStmt) Limit(offset int, count int) SelectStmt {
	s.offset = &offset
	s.count = &count
	return s
}

// Accept calls the compiler VisitSelect method
func (s SelectStmt) Accept(context *CompilerContext) string {
	return context.Compiler.VisitSelect(context, s)
}

// Build compiles the select statement and returns the Stmt
func (s SelectStmt) Build(dialect Dialect) *Stmt {
	defer dialect.Reset()

	context := NewCompilerContext(dialect)
	statement := Statement()
	statement.AddSQLClause(s.Accept(context))
	statement.AddBinding(context.Binds...)

	return statement
}

type joinOnClauseCandidate struct {
	source TableElem
	fkey   ForeignKeyConstraint
	target TableElem
}

// GuessJoinOnClause finds a join 'ON' clause between two tables
func GuessJoinOnClause(left Selectable, right Selectable) Clause {
	leftTable, ok := left.(TableElem)
	if !ok {
		panic("left Selectable is not a Table: Cannot guess join onClause")
	}
	rightTable, ok := right.(TableElem)
	if !ok {
		panic("right Selectable is not a Table: Cannot guess join onClause")
	}

	var candidates []joinOnClauseCandidate

	for _, fkey := range leftTable.ForeignKeyConstraints.FKeys {
		if fkey.RefTable != rightTable.Name {
			continue
		}
		candidates = append(
			candidates,
			joinOnClauseCandidate{leftTable, fkey, rightTable})
	}

	for _, fkey := range rightTable.ForeignKeyConstraints.FKeys {
		if fkey.RefTable != leftTable.Name {
			continue
		}
		candidates = append(
			candidates,
			joinOnClauseCandidate{rightTable, fkey, leftTable})
	}
	switch len(candidates) {
	case 0:
		panic(fmt.Sprintf(
			"No foreign keys found between %s and %s",
			leftTable.Name, rightTable.Name))
	case 1:
		candidate := candidates[0]
		var clauses []Clause
		for i, col := range candidate.fkey.Cols {
			refCol := candidate.fkey.RefCols[i]
			clauses = append(
				clauses,
				Eq(candidate.source.C(col), candidate.target.C(refCol)),
			)
		}
		if len(clauses) == 1 {
			return clauses[0]
		}
		return And(clauses...)
	default:
		panic(fmt.Sprintf(
			"Found %d foreign keys between %s and %s",
			len(candidates), leftTable.Name, rightTable.Name))
	}
}

// MakeJoinOnClause assemble a 'ON' clause for a join from either:
// 0 clause: attempt to guess the join clause (only if left & right are tables),
//           otherwise panics
// 1 clause: returns it
// 2 clauses: returns a Eq() of both
// otherwise if panics
func MakeJoinOnClause(left Selectable, right Selectable, onClause ...Clause) Clause {
	switch len(onClause) {
	case 0:
		return GuessJoinOnClause(left, right)
	case 1:
		return onClause[0]
	case 2:
		return Eq(onClause[0], onClause[1])
	default:
		panic("Cannot make a join condition with more than 2 clauses")
	}
}

func Join(joinType string, left Selectable, right Selectable, onClause ...Clause) JoinClause {
	return JoinClause{
		JoinType: joinType,
		Left:     left,
		Right:    right,
		OnClause: MakeJoinOnClause(left, right, onClause...),
	}
}

// JoinClause is the base struct for generating join clauses when using select
// It satisfies Clause interface
type JoinClause struct {
	JoinType string
	Left     Selectable
	Right    Selectable
	OnClause Clause
}

// Accept calls the compiler VisitJoin method
func (c JoinClause) Accept(context *CompilerContext) string {
	return context.Compiler.VisitJoin(context, c)
}

func (c JoinClause) All() []Clause {
	return append(c.Left.All(), c.Right.All()...)
}

func (c JoinClause) ColumnList() []ColumnElem {
	return append(c.Left.ColumnList(), c.Right.ColumnList()...)
}

func (c JoinClause) C(name string) ColumnElem {
	for _, c := range c.ColumnList() {
		if c.Name == name {
			return c
		}
	}
	panic(fmt.Sprintf("No such column '%s' in join %v", name, c))
}

func (c JoinClause) DefaultName() string {
	return ""
}

// OrderByClause is the base struct for generating order by clauses when using select
// It satisfies SQLClause interface
type OrderByClause struct {
	columns []ColumnElem
	t       string
}

// Accept generates an order by clause
func (c OrderByClause) Accept(context *CompilerContext) string {
	return context.Compiler.VisitOrderBy(context, c)
}

// HavingClause is the base struct for generating having clauses when using select
// It satisfies SQLClause interface
type HavingClause struct {
	aggregate AggregateClause
	op        string
	value     interface{}
}

// Accept generates having sql & bindings out of HavingClause struct
func (c HavingClause) Accept(context *CompilerContext) string {
	return context.Compiler.VisitHaving(context, c)
}

func Alias(name string, selectable Selectable) AliasClause {
	return AliasClause{
		Name:       name,
		Selectable: selectable,
	}
}

type AliasClause struct {
	Name       string
	Selectable Selectable
}

func (c AliasClause) Accept(context *CompilerContext) string {
	return context.Compiler.VisitAlias(context, c)
}

func (c AliasClause) C(name string) ColumnElem {
	col := c.Selectable.C(name)
	col.Table = c.Name
	return col
}

func (c AliasClause) All() []Clause {
	var clauses []Clause
	for _, col := range c.ColumnList() {
		clauses = append(clauses, col)
	}
	return clauses
}

func (c AliasClause) ColumnList() []ColumnElem {
	var cols []ColumnElem
	for _, col := range c.Selectable.ColumnList() {
		col.Table = c.Name
		cols = append(cols, col)
	}
	return cols
}

func (c AliasClause) DefaultName() string {
	return c.Name
}
<|endoftext|>


<commit_before>package semver

import (
	"fmt"
	"regexp"
	"strings"
)

// Version represents a SemVer 2.0.0 version and implements some high-level
// methods to manage multiple versions.
type SemVer struct {
	Major  string // Backward-incompatible changes
	Minor  string // New functionality
	Patch  string // Bug fixes
	PreRel string // Optional pre-release tag
	Build  string // Optional build metadata
}

// String will return a flat string representing the semantic version
func (s *SemVer) String() string {
	res := fmt.Sprintf("%s.%s.%s", s.Major, s.Minor, s.Patch)
	if s.PreRel != "" {
		res = fmt.Sprintf("%s-%s", res, s.PreRel)
	}
	if s.Build != "" {
		res = fmt.Sprintf("%s+%s", res, s.Build)
	}
	return res
}

// parts will return all version components as a slice of strings.
func (s *SemVer) parts() []string {
	return []string{s.Major, s.Minor, s.Patch, s.PreRel, s.Build}
}

// New creates a new semver object from individual version components.
func New(major, minor, patch, preRel, build string) (*SemVer, error) {
	s := &SemVer{
		Major:  major,
		Minor:  minor,
		Patch:  patch,
		PreRel: preRel,
		Build:  build,
	}
	if err := s.verify(); err != nil {
		return nil, err
	}
	return s, nil
}

// New will create a new semantic versioning object from a flat
// string and populate all struct fields.
func NewFromString(vstr string) (*SemVer, error) {
	build := takeR(&vstr, "+")
	preRe := takeR(&vstr, "-")
	patch := takeR(&vstr, ".")
	minor := takeR(&vstr, ".")
	major := vstr
	return New(major, minor, patch, preRe, build)
}

// verify is used to ensure that a semver object complies with the format
// defined by semver.org.
func (s *SemVer) verify() error {
	baseRe, err := regexp.Compile("^[0-9]+$")
	extRe, err := regexp.Compile("^([0-9a-zA-Z-]+)?$")
	if err != nil {
		return err
	}

	if !(baseRe.MatchString(s.Major) && baseRe.MatchString(s.Minor) &&
		baseRe.MatchString(s.Patch) && extRe.MatchString(s.PreRel) &&
		extRe.MatchString(s.Build)) {

		return fmt.Errorf("semver: invalid version: %s", s.String())
	}

	return nil
}

// takeR will take all characters in a string from the right side of the subject
// until sep is encountered. The subject will be pruned in-place of both sep and
// the taken string. If sep is not present in subj, then "" is returned.
func takeR(subj *string, sep string) string {
	if !strings.Contains(*subj, sep) {
		return ""
	}
	parts := strings.Split(*subj, sep)
	last := len(parts) - 1
	*subj = strings.Join(parts[0:last], sep)
	return parts[last]
}
<commit_msg>Refactored string loading and regexp comparison to support dots in prerelease/build numbers as well as additional dashes, which are allowed per semver 2.0.<commit_after>package semver

import (
	"fmt"
	"regexp"
	"strings"
)

var (
	baseRe    *regexp.Regexp
	extReList []*regexp.Regexp
)

// Version represents a SemVer 2.0.0 version and implements some high-level
// methods to manage multiple versions.
type SemVer struct {
	Major  string // Backward-incompatible changes
	Minor  string // New functionality
	Patch  string // Bug fixes
	PreRel string // Optional pre-release tag
	Build  string // Optional build metadata
}

func init() {
	baseRe = regexp.MustCompile("^(([1-9][0-9]+)|[0-9])?$")
	extReList = []*regexp.Regexp{
		regexp.MustCompile("^([1-9a-zA-Z]([0-9a-zA-Z-]+)?)?$"),
		regexp.MustCompile("^([1-9]([0-9]+)?)?$"),
	}
}

// String will return a flat string representing the semantic version
func (s *SemVer) String() string {
	res := s.BaseString()
	if s.PreRel != "" {
		res = fmt.Sprintf("%s-%s", res, s.PreRel)
	}
	if s.Build != "" {
		res = fmt.Sprintf("%s+%s", res, s.Build)
	}
	return res
}

// BaseString will return the base version number (sans pre-release and build)
// as a formatted string.
func (s *SemVer) BaseString() string {
	return fmt.Sprintf("%s.%s.%s", s.Major, s.Minor, s.Patch)
}

// parts will return all version components as a slice of strings.
func (s *SemVer) parts() []string {
	return []string{s.Major, s.Minor, s.Patch, s.PreRel, s.Build}
}

// New creates a new semver object from individual version components.
func New(major, minor, patch, preRel, build string) (*SemVer, error) {
	s := &SemVer{
		Major:  major,
		Minor:  minor,
		Patch:  patch,
		PreRel: preRel,
		Build:  build,
	}
	if err := s.verify(); err != nil {
		return nil, err
	}
	return s, nil
}

// New will create a new semantic versioning object from a flat
// string and populate all struct fields.
func NewFromString(vstr string) (*SemVer, error) {
	var major, minor, patch, pre, build string

	parts := strings.SplitN(vstr, ".", 3)
	if len(parts) < 3 {
		return nil, fmt.Errorf("semver: version too short: %s", vstr)
	}
	major, minor, patch = parts[0], parts[1], parts[2]

	parts = strings.SplitN(patch, "-", 2)
	patch = parts[0]
	if len(parts) > 1 {
		pre = parts[1]
	}

	parts = strings.SplitN(pre, "+", 2)
	pre = parts[0]
	if len(parts) > 1 {
		build = parts[1]
	}

	return New(major, minor, patch, pre, build)
}

// matchAny simplifies iterating over a slice of regexp patterns and testing if
// any of them match a subject text.
func matchAny(patterns []*regexp.Regexp, subj string) bool {
	for _, pattern := range patterns {
		if pattern.MatchString(subj) {
			return true
		}
	}
	return false
}

// verify is used to ensure that a semver object complies with the format
// defined by semver.org.
func (s *SemVer) verify() error {
	if !(baseRe.MatchString(s.Major) &&
		baseRe.MatchString(s.Minor) &&
		baseRe.MatchString(s.Patch)) {
		return fmt.Errorf("semver: invalid base version: %s", s.BaseString())
	}

	for _, subj := range strings.Split(s.PreRel, ".") {
		if !matchAny(extReList, subj) {
			return fmt.Errorf("semver: invalid pre-release tag: %s", s.PreRel)
		}
	}

	for _, subj := range strings.Split(s.Build, ".") {
		if !matchAny(extReList, subj) {
			return fmt.Errorf("semver: invalid build metadata: %s", s.Build)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/send-to/sendto/client"
)

const (
	v = "0.1"
)

func main() {
	command := ""
	args := os.Args[1:] // remove app path from args

	// We expect either a username or a subcommand and then a set of files in args
	if len(args) > 0 {
		command = args[0]
		args = args[1:]
	}

	// Load our configuration
	err := client.LoadConfig()
	if err != nil {
		log.Fatalf("Sorry, an error occurred:\n\t%s", err)
	}

	switch command {
	case "encrypt", "e":
		err = Encrypt(args)
	case "decrypt", "d":
		err = Decrypt(args)
	case "identity", "i":
		err = Identity(args)
	case "version", "v":
		Version()
	case "help", "h":
		Help()
	default:
		// Default action is to send to (if we have a username and files)
		if len(args) > 0 {
			err = SendTo(command, args)
		} else {
			Help()
		}
	}

	if err != nil {
		log.Fatalf("Sorry, an error occurred:\n\t%s", err)
	}
}

// Version prints the version of this app
func Version() {
	fmt.Printf("\n\t-----\n\tSend to client - version:%s\n\t-----\n", v)
}

// Usage returns standard usage as a string
func Usage() string {
	return fmt.Sprintf("\tUsage: sendto kennygrant [files] - send files to the username kennygrant\n")
}

// Help prints the usage and commands
func Help() {
	Version()
	fmt.Printf(Usage())
	fmt.Printf("\t-----\n")
	fmt.Printf("\tCommands:\n")
	fmt.Printf("\tsendto version - display version\n")
	fmt.Printf("\tsendto [username] [files] - encrypt files for a given user\n")
	fmt.Printf("\tsendto encrypt [file] - encrypt a file\n")
	//	fmt.Printf("\tsendto decrypt [file] - decrypt a file\n")
	fmt.Printf("\tsendto identity [name] - sets default sender identity\n\n")
}

// Decrypt files specified, using the user's private key
// TODO: to support decryption we'd need access to private keys, perhaps leave this for hackathon
func Decrypt(args []string) error {
	log.Printf("Sorry, this client does not yet support decrypt")

	return nil
}

// Encrypt the files specified
func Encrypt(args []string) error {

	log.Printf("Sorry, this client does not yet support encryption")
	return nil
}

// SendTo sends files held in args to recipient
func SendTo(recipient string, args []string) error {

	// We expect at least 1 file to send
	if len(args) < 1 {
		return fmt.Errorf("Not enough arguments - %s", Usage())
	}

	// Notify the user that we're starting to send
	fmt.Printf("Sending %d %s to %s as %s...\n", len(args), filesString(len(args)), recipient, client.Config["sender"])

	// Fetch the recipient's key (from disk or server)

	// For the moment as a test, use keybase.io, should be using our server
	keyURL := fmt.Sprintf(client.Config["keyserver"], recipient)
	keyPath, err := client.LoadKey(recipient, keyURL)
	if err != nil {
		// Warn user in a nicer way here that key could not be found
		return fmt.Errorf("Failed to find key:%s", err)
	}
	fmt.Printf("Loaded key for %s:\n%s\n", recipient, keyPath)

	// Zip and Encrypt our arguments (files or folders) using key
	dataPath, err := client.EncryptFiles(args, recipient, keyPath)
	if err != nil {
		return err
	}

	// Send the file to the recipient on the server
	postURL := fmt.Sprintf("%s/files/create", client.Config["server"])

	fmt.Printf("Sending files for %s to %s\n", recipient, postURL)

	err = client.PostData(client.Config["sender"], recipient, dataPath, postURL)
	if err != nil {
		return err
	}

	return nil
}

// Identity sets the default sender identity (as opposed to username)
func Identity(args []string) error {
	if len(args) < 1 {
		return fmt.Errorf("Identity command requires a sender name")
	}

	identity := args[0]
	client.Config["sender"] = identity

	fmt.Printf("Setting sender identity to:%s\n", identity)

	return client.SaveConfig()
}

// Perhaps also allow setting default server?

// Return a nicely formatted string for the word files
func filesString(i int) string {
	if i > 1 {
		return "files"
	}
	return "file"
}
<commit_msg>Adjusted error messages to add more detail<commit_after>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/send-to/sendto/client"
)

const (
	v = "0.1"
)

func main() {
	command := ""
	args := os.Args[1:] // remove app path from args

	// We expect either a username or a subcommand and then a set of files in args
	if len(args) > 0 {
		command = args[0]
		args = args[1:]
	}

	// Load our configuration
	err := client.LoadConfig()
	if err != nil {
		log.Fatalf("Sorry, an error occurred loading config:\n\t%s", err)
	}

	switch command {
	case "encrypt", "e":
		err = Encrypt(args)
	case "decrypt", "d":
		err = Decrypt(args)
	case "identity", "i":
		err = Identity(args)
	case "version", "v":
		Version()
	case "help", "h":
		Help()
	default:
		// Default action is to send to (if we have a username and files)
		if len(args) > 0 {
			err = SendTo(command, args)
		} else {
			Help()
		}
	}

	if err != nil {
		log.Fatalf("Sorry, an error occurred:\n\t%s", err)
	}
}

// Version prints the version of this app
func Version() {
	fmt.Printf("\n\t-----\n\tSend to client - version:%s\n\t-----\n", v)
}

// Usage returns standard usage as a string
func Usage() string {
	return fmt.Sprintf("\tUsage: sendto kennygrant [files] - send files to the username kennygrant\n")
}

// Help prints the usage and commands
func Help() {
	Version()
	fmt.Printf(Usage())
	fmt.Printf("\t-----\n")
	fmt.Printf("\tCommands:\n")
	fmt.Printf("\tsendto version - display version\n")
	fmt.Printf("\tsendto [username] [files] - encrypt files for a given user\n")
	fmt.Printf("\tsendto encrypt [file] - encrypt a file\n")
	//	fmt.Printf("\tsendto decrypt [file] - decrypt a file\n")
	fmt.Printf("\tsendto identity [name] - sets default sender identity\n\n")
}

// Decrypt files specified, using the user's private key
// TODO: to support decryption we'd need access to private keys, perhaps leave this for hackathon
func Decrypt(args []string) error {
	log.Printf("Sorry, this client does not yet support decrypt")

	return nil
}

// Encrypt the files specified
func Encrypt(args []string) error {

	log.Printf("Sorry, this client does not yet support encryption")
	return nil
}

// SendTo sends files held in args to recipient
func SendTo(recipient string, args []string) error {

	// We expect at least 1 file to send
	if len(args) < 1 {
		return fmt.Errorf("Not enough arguments - %s", Usage())
	}

	// Notify the user that we're starting to send
	fmt.Printf("Sending %d %s to %s as %s...\n", len(args), filesString(len(args)), recipient, client.Config["sender"])

	// Fetch the recipient's key (from disk or server)

	// For the moment as a test, use keybase.io, should be using our server
	keyURL := fmt.Sprintf(client.Config["keyserver"], recipient)
	keyPath, err := client.LoadKey(recipient, keyURL)
	if err != nil {
		// Warn user in a nicer way here that key could not be found
		return fmt.Errorf("Failed to find key:%s", err)
	}
	fmt.Printf("Loaded key for %s:\n%s\n", recipient, keyPath)

	// Zip and Encrypt our arguments (files or folders) using key
	dataPath, err := client.EncryptFiles(args, recipient, keyPath)
	if err != nil {
		return err
	}

	// Send the file to the recipient on the server
	postURL := fmt.Sprintf("%s/files/create", client.Config["server"])

	fmt.Printf("Sending files for %s to %s\n", recipient, postURL)

	err = client.PostData(client.Config["sender"], recipient, dataPath, postURL)
	if err != nil {
		return err
	}

	return nil
}

// Identity sets the default sender identity (as opposed to username)
func Identity(args []string) error {
	if len(args) < 1 {
		return fmt.Errorf("Identity command requires a sender name")
	}

	identity := args[0]
	client.Config["sender"] = identity

	fmt.Printf("Setting sender identity to:%s\n", identity)

	return client.SaveConfig()
}

// Perhaps also allow setting default server?

// Return a nicely formatted string for the word files
func filesString(i int) string {
	if i > 1 {
		return "files"
	}
	return "file"
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/pboehm/series/config"
	"github.com/pboehm/series/index"
	"github.com/pboehm/series/renamer"
	"github.com/pboehm/series/util"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"regexp"
)

var CONFIG_DIR, CONFIG_FILE string
var DEFAULT_CONFIG, APP_CONFIG config.Config

func setup() {
	CONFIG_DIR = path.Join(util.HomeDirectory(), ".series")
	CONFIG_FILE = path.Join(CONFIG_DIR, "config.json")

	DEFAULT_CONFIG = config.Config{
		EpisodeDirectory: path.Join(util.HomeDirectory(), "Downloads"),
		IndexFile:        path.Join(CONFIG_DIR, "index.xml"),
	}
}

func GetInterestingDirEntries() []string {
	content, err := ioutil.ReadDir(".")
	if err != nil {
		panic(err)
	}

	valid_regex := regexp.MustCompile("^S\\d+E\\d+.-.\\w+.*\\.\\w+$")

	interesting := []string{}
	for _, entry := range content {
		entry_path := entry.Name()

		if !renamer.IsInterestingDirEntry(entry_path) {
			continue
		}
		if valid_regex.Match([]byte(entry_path)) {
			continue
		}

		interesting = append(interesting, entry_path)
	}

	return interesting
}

func HandleInterestingEpisodes(index *index.SeriesIndex, entries []string) []*renamer.Episode {
	renameable_episodes := []*renamer.Episode{}

	for _, entry_path := range entries {

		episode, err := renamer.CreateEpisodeFromPath(entry_path)
		if err != nil {
			fmt.Printf("!!! '%s' - %s\n\n", entry_path, err)
			continue
		}

		episode.RemoveTrashwords()
		if !episode.HasValidEpisodeName() {
			episode.SetDefaultEpisodeName()
		}

		fmt.Printf("<<< %s\n", entry_path)
		fmt.Printf(">>> %s\n", episode.CleanedFileName())

		if !episode.CanBeRenamed() {
			fmt.Printf("!!! '%s' is currently not renameable\n\n", entry_path)
			continue
		}

		added, added_err := index.AddEpisode(episode)
		if !added {
			fmt.Printf("!!! couldn't be added to the index: %s\n\n", added_err)
			continue
		}
		fmt.Println("---> succesfully added to series index\n")

		renameable_episodes = append(renameable_episodes, episode)
	}

	return renameable_episodes
}

func main() {
	setup()
	APP_CONFIG = config.GetConfig(CONFIG_FILE, DEFAULT_CONFIG)

	// parse command flags/args
	FlagRenameFiles := flag.Bool("rename", true, "should the files be renamed")

	flag.Parse()
	argv := flag.Args()

	// change to the series directory
	dir := path.Join(APP_CONFIG.EpisodeDirectory)
	if len(argv) > 0 {
		dir = argv[0]
	}

	err := os.Chdir(dir)
	if err != nil {
		panic(err)
	}

	// get all interesting episodes and stop if there aren't any
	interesting_entries := GetInterestingDirEntries()
	if len(interesting_entries) == 0 {
		os.Exit(0)
	}

	// Call PreProcessingHook
	if APP_CONFIG.PreProcessingHook != "" {
		fmt.Println("### Calling PreProcessingHook ...")

		cmd := exec.Command("/bin/sh", "-c", APP_CONFIG.PreProcessingHook)
		out, err := cmd.Output()
		if err != nil {
			fmt.Printf("PreProcessingHook ended with an error: %s\n", err)
		}
		fmt.Println(string(out))
	}

	fmt.Println("### Parsing series index ...")
	index, index_err := index.ParseSeriesIndex(APP_CONFIG.IndexFile)
	if index_err != nil {
		panic(index_err)
	}

	fmt.Println("### Process all interesting files ...")
	renameable_episodes := HandleInterestingEpisodes(index, interesting_entries)

	if len(renameable_episodes) > 0 && *FlagRenameFiles {
		fmt.Println("### Writing new index version ...")
		index.WriteToFile(APP_CONFIG.IndexFile)

		fmt.Println("### Renaming episodes ...")

		for _, episode := range renameable_episodes {
			fmt.Printf("> %s: %s", episode.Series, episode.CleanedFileName())

			// Rename episode file
			rename_err := episode.Rename(".")
			if rename_err != nil {
				panic(rename_err)
			}

			fmt.Printf("  [OK]\n")

			// Call EpisodeHook
			if APP_CONFIG.EpisodeHook != "" {
				fmt.Println("# Calling EpisodeHook ...")

				hook_cmd := fmt.Sprintf("%s \"%s\" \"%s\"",
					APP_CONFIG.EpisodeHook,
					episode.CleanedFileName(), episode.Series)

				cmd := exec.Command("/bin/sh", "-c", hook_cmd)
				out, err := cmd.Output()
				if err != nil {
					fmt.Printf("EpisodeHook ended with an error: %s\n", err)
				}
				fmt.Println(string(out))
			}
		}

		// Call PostProcessingHook
		if APP_CONFIG.PostProcessingHook != "" {
			fmt.Println("\n### Calling PostProcessingHook ...")

			cmd := exec.Command("/bin/sh", "-c", APP_CONFIG.PostProcessingHook)
			out, err := cmd.Output()
			if err != nil {
				fmt.Printf("PostProcessingHook ended with an error: %s\n", err)
			}
			fmt.Println(string(out))
		}
	}
}
<commit_msg>Refactored hook execution<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/pboehm/series/config"
	"github.com/pboehm/series/index"
	"github.com/pboehm/series/renamer"
	"github.com/pboehm/series/util"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"regexp"
)

var CONFIG_DIR, CONFIG_FILE string
var DEFAULT_CONFIG, APP_CONFIG config.Config

func setup() {
	CONFIG_DIR = path.Join(util.HomeDirectory(), ".series")
	CONFIG_FILE = path.Join(CONFIG_DIR, "config.json")

	DEFAULT_CONFIG = config.Config{
		EpisodeDirectory: path.Join(util.HomeDirectory(), "Downloads"),
		IndexFile:        path.Join(CONFIG_DIR, "index.xml"),
	}
}

func GetInterestingDirEntries() []string {
	content, err := ioutil.ReadDir(".")
	if err != nil {
		panic(err)
	}

	valid_regex := regexp.MustCompile("^S\\d+E\\d+.-.\\w+.*\\.\\w+$")

	interesting := []string{}
	for _, entry := range content {
		entry_path := entry.Name()

		if !renamer.IsInterestingDirEntry(entry_path) {
			continue
		}
		if valid_regex.Match([]byte(entry_path)) {
			continue
		}

		interesting = append(interesting, entry_path)
	}

	return interesting
}

func HandleInterestingEpisodes(index *index.SeriesIndex, entries []string) []*renamer.Episode {
	renameable_episodes := []*renamer.Episode{}

	for _, entry_path := range entries {

		episode, err := renamer.CreateEpisodeFromPath(entry_path)
		if err != nil {
			fmt.Printf("!!! '%s' - %s\n\n", entry_path, err)
			continue
		}

		episode.RemoveTrashwords()
		if !episode.HasValidEpisodeName() {
			episode.SetDefaultEpisodeName()
		}

		fmt.Printf("<<< %s\n", entry_path)
		fmt.Printf(">>> %s\n", episode.CleanedFileName())

		if !episode.CanBeRenamed() {
			fmt.Printf("!!! '%s' is currently not renameable\n\n", entry_path)
			continue
		}

		added, added_err := index.AddEpisode(episode)
		if !added {
			fmt.Printf("!!! couldn't be added to the index: %s\n\n", added_err)
			continue
		}
		fmt.Println("---> succesfully added to series index\n")

		renameable_episodes = append(renameable_episodes, episode)
	}

	return renameable_episodes
}

// This executes the supplied cmd by /bin/sh and returns an error if it returns
// unexpectedly
func System(cmd_string string) error {

    cmd := exec.Command("/bin/sh", "-c", cmd_string)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    return cmd.Run()
}

func main() {
	setup()
	APP_CONFIG = config.GetConfig(CONFIG_FILE, DEFAULT_CONFIG)

	// parse command flags/args
	FlagRenameFiles := flag.Bool("rename", true, "should the files be renamed")

	flag.Parse()
	argv := flag.Args()

	// change to the series directory
	dir := path.Join(APP_CONFIG.EpisodeDirectory)
	if len(argv) > 0 {
		dir = argv[0]
	}

	err := os.Chdir(dir)
	if err != nil {
		panic(err)
	}

	// get all interesting episodes and stop if there aren't any
	interesting_entries := GetInterestingDirEntries()
	if len(interesting_entries) == 0 {
		os.Exit(0)
	}

	// Call PreProcessingHook
	if APP_CONFIG.PreProcessingHook != "" {
		fmt.Println("### Calling PreProcessingHook ...")

		err := System(APP_CONFIG.PreProcessingHook)
		if err != nil {
			fmt.Printf("PreProcessingHook ended with an error: %s\n", err)
		}
	}

	fmt.Println("### Parsing series index ...")
	index, index_err := index.ParseSeriesIndex(APP_CONFIG.IndexFile)
	if index_err != nil {
		panic(index_err)
	}

	fmt.Println("### Process all interesting files ...")
	renameable_episodes := HandleInterestingEpisodes(index, interesting_entries)

	if len(renameable_episodes) > 0 && *FlagRenameFiles {
		fmt.Println("### Writing new index version ...")
		index.WriteToFile(APP_CONFIG.IndexFile)

		fmt.Println("### Renaming episodes ...")

		for _, episode := range renameable_episodes {
			fmt.Printf("> %s: %s", episode.Series, episode.CleanedFileName())

			// Rename episode file
			rename_err := episode.Rename(".")
			if rename_err != nil {
				panic(rename_err)
			}

			fmt.Printf("  [OK]\n")

			// Call EpisodeHook
			if APP_CONFIG.EpisodeHook != "" {
				fmt.Println("# Calling EpisodeHook ...")

				hook_cmd := fmt.Sprintf("%s \"%s\" \"%s\"",
					APP_CONFIG.EpisodeHook,
					episode.CleanedFileName(), episode.Series)

				err := System(hook_cmd)
				if err != nil {
					fmt.Printf("EpisodeHook ended with an error: %s\n", err)
				}
			}
		}

		// Call PostProcessingHook
		if APP_CONFIG.PostProcessingHook != "" {
			fmt.Println("\n### Calling PostProcessingHook ...")

			err := System(APP_CONFIG.PostProcessingHook)
			if err != nil {
				fmt.Printf("PostProcessingHook ended with an error: %s\n", err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/atahani/golang-rest-api-sample/controller/article"
	"github.com/atahani/golang-rest-api-sample/controller/client"
	"github.com/atahani/golang-rest-api-sample/controller/user"
	"github.com/atahani/golang-rest-api-sample/util"
	"github.com/atahani/golang-rest-api-sample/util/specialerror"
	"github.com/labstack/echo"
	"github.com/labstack/echo/engine/standard"
	"github.com/labstack/echo/middleware"
	"gopkg.in/mgo.v2"
	"os"
	"time"
)

func main() {
	//Echo instance
	app := echo.New()

	//set custom binder to validate payloads
	bi := util.NewCustomBinderWithValidation()
	app.SetBinder(bi)

	//set custom error handler
	app.SetHTTPErrorHandler(specialerror.CustomErrorHandler)

	//set the port listener
	port := "8090"
	if os.Getenv("PORT") != "" {
		port = os.Getenv("PORT")
	}

	//Configs in different app environment mode
	var applicationEnv string
	var mongoDBDialInfo *mgo.DialInfo
	switch os.Getenv("APP_ENV") {
	case "development":
		applicationEnv = "development"
		mongoDBDialInfo = &mgo.DialInfo{
			Addrs:    []string{"localhost:27017"},
			Timeout:  60 * time.Second,
			Database: "golang_sample_dev",
		}
		app.SetDebug(true)
		//Custom logger for console
		app.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
			Format: "${method}-${status} at > ${uri} < in ${response_time} - ${response_size} bytes\n",
		}))
	case "production":
		applicationEnv = "production"
		mongoDBDialInfo = &mgo.DialInfo{
			Addrs:    []string{"localhost"},
			Timeout:  60 * time.Second,
			Database: "golang_sample",
		}
		app.Use(middleware.Recover())
		app.SetDebug(false)
		app.Use(middleware.GzipWithConfig(middleware.GzipConfig{
			Level: 5,
		}))
	default:
		applicationEnv = "development"
		mongoDBDialInfo = &mgo.DialInfo{
			Addrs:    []string{"localhost:27017"},
			Timeout:  60 * time.Second,
			Database: "golang_sample_dev",
		}
		app.SetDebug(true)
		//Custom logger for console
		app.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
			Format: "${method}-${status} at > ${uri} < in ${response_time} - ${response_size} bytes\n",
		}))
	}

	//create a session with maintains a pool of socket connections to out mongodb
	mongoSession, err := mgo.DialWithInfo(mongoDBDialInfo)
	if err != nil {
		fmt.Printf("connection %s\n", err)
	}

	clientController := client.NewClientController(mongoSession, mongoDBDialInfo.Database)
	userController := user.NewUserController(mongoSession, mongoDBDialInfo.Database)
	articleController := article.NewArticleController(mongoSession, mongoDBDialInfo.Database)
	//auth endpoint
	app.Post("/auth/signup", userController.SignUpNewUser)
	app.Post("/auth/singin", userController.SignIn)
	app.Post("/auth/token/refresh", userController.RefreshAccessToken)

	//manage endpoint for client
	apiAdmin := app.Group("/api/manage", user.JWTAuthenticationMiddleware(mongoSession, mongoDBDialInfo.Database), user.AuthorizeUserByRolesMiddleware([]string{"admin"}))
	//manage clients
	apiAdmin.Get("/client", clientController.GetClients)
	apiAdmin.Post("/client", clientController.CreateNewClient)
	apiAdmin.Get("/client/:id", clientController.GetClientById)
	apiAdmin.Put("/client/:id", clientController.UpdateClientById)
	apiAdmin.Delete("/client/:id", clientController.DeleteClientById)

	apiUser := app.Group("/api", user.JWTAuthenticationMiddleware(mongoSession, mongoDBDialInfo.Database), user.AuthorizeUserByRolesMiddleware([]string{"user"}))
	//user profile
	apiUser.Put("/user/profile", userController.UpdateUserProfile)
	apiUser.Put("/user/password", userController.ChangeUserPassword)
	//article
	apiUser.Get("/article", articleController.GetArticlesOfUser)
	apiUser.Post("/article", articleController.CreateArticle)
	apiUser.Get("/article/:id", articleController.GetArticleById)
	apiUser.Put("/article/:id", articleController.UpdateArticleById)
	apiUser.Delete("/article/:id", articleController.DeleteArticleById)

	//start server
	fmt.Printf("API Management Listen to %s port in %s\n", port, applicationEnv)
	app.Run(standard.New(fmt.Sprint(":", port)))
}
<commit_msg>create TTL index for accessTokens<commit_after>package main

import (
	"fmt"
	"github.com/atahani/golang-rest-api-sample/controller/article"
	"github.com/atahani/golang-rest-api-sample/controller/client"
	"github.com/atahani/golang-rest-api-sample/controller/user"
	"github.com/atahani/golang-rest-api-sample/util"
	"github.com/atahani/golang-rest-api-sample/util/specialerror"
	"github.com/labstack/echo"
	"github.com/labstack/echo/engine/standard"
	"github.com/labstack/echo/middleware"
	"gopkg.in/mgo.v2"
	"os"
	"time"
)

func main() {
	//Echo instance
	app := echo.New()

	//set custom binder to validate payloads
	bi := util.NewCustomBinderWithValidation()
	app.SetBinder(bi)

	//set custom error handler
	app.SetHTTPErrorHandler(specialerror.CustomErrorHandler)

	//set the port listener
	port := "8090"
	if os.Getenv("PORT") != "" {
		port = os.Getenv("PORT")
	}

	//Configs in different app environment mode
	var applicationEnv string
	var mongoDBDialInfo *mgo.DialInfo
	switch os.Getenv("APP_ENV") {
	case "development":
		applicationEnv = "development"
		mongoDBDialInfo = &mgo.DialInfo{
			Addrs:    []string{"localhost:27017"},
			Timeout:  60 * time.Second,
			Database: "golang_sample_dev",
		}
		app.SetDebug(true)
		//Custom logger for console
		app.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
			Format: "${method}-${status} at > ${uri} < in ${response_time} - ${response_size} bytes\n",
		}))
	case "production":
		applicationEnv = "production"
		mongoDBDialInfo = &mgo.DialInfo{
			Addrs:    []string{"localhost"},
			Timeout:  60 * time.Second,
			Database: "golang_sample",
		}
		app.Use(middleware.Recover())
		app.SetDebug(false)
		app.Use(middleware.GzipWithConfig(middleware.GzipConfig{
			Level: 5,
		}))
	default:
		applicationEnv = "development"
		mongoDBDialInfo = &mgo.DialInfo{
			Addrs:    []string{"localhost:27017"},
			Timeout:  60 * time.Second,
			Database: "golang_sample_dev",
		}
		app.SetDebug(true)
		//Custom logger for console
		app.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
			Format: "${method}-${status} at > ${uri} < in ${response_time} - ${response_size} bytes\n",
		}))
	}

	//create a session with maintains a pool of socket connections to out mongodb
	mongoSession, err := mgo.DialWithInfo(mongoDBDialInfo)
	if err != nil {
		fmt.Printf("connection %s\n", err)
	}
	//check and ensure database indexes
	mongoSession.DB(mongoDBDialInfo.Database).C(user.ACCESS_TOKEN_COLLECTION_NAME).EnsureIndex(mgo.Index{
		Key:         []string{"expire_at"},
		Unique:      false,
		DropDups:    false,
		Background:  true,
		ExpireAfter: time.Second * 1,
	})

	clientController := client.NewClientController(mongoSession, mongoDBDialInfo.Database)
	userController := user.NewUserController(mongoSession, mongoDBDialInfo.Database)
	articleController := article.NewArticleController(mongoSession, mongoDBDialInfo.Database)
	//auth endpoint
	app.Post("/auth/signup", userController.SignUpNewUser)
	app.Post("/auth/singin", userController.SignIn)
	app.Post("/auth/token/refresh", userController.RefreshAccessToken)

	//manage endpoint for client
	apiAdmin := app.Group("/api/manage", user.JWTAuthenticationMiddleware(mongoSession, mongoDBDialInfo.Database), user.AuthorizeUserByRolesMiddleware([]string{"admin"}))
	//manage clients
	apiAdmin.Get("/client", clientController.GetClients)
	apiAdmin.Post("/client", clientController.CreateNewClient)
	apiAdmin.Get("/client/:id", clientController.GetClientById)
	apiAdmin.Put("/client/:id", clientController.UpdateClientById)
	apiAdmin.Delete("/client/:id", clientController.DeleteClientById)

	apiUser := app.Group("/api", user.JWTAuthenticationMiddleware(mongoSession, mongoDBDialInfo.Database), user.AuthorizeUserByRolesMiddleware([]string{"user"}))
	//user profile
	apiUser.Put("/user/profile", userController.UpdateUserProfile)
	apiUser.Put("/user/password", userController.ChangeUserPassword)
	//article
	apiUser.Get("/article", articleController.GetArticlesOfUser)
	apiUser.Post("/article", articleController.CreateArticle)
	apiUser.Get("/article/:id", articleController.GetArticleById)
	apiUser.Put("/article/:id", articleController.UpdateArticleById)
	apiUser.Delete("/article/:id", articleController.DeleteArticleById)

	//start server
	fmt.Printf("API Management Listen to %s port in %s\n", port, applicationEnv)
	app.Run(standard.New(fmt.Sprint(":", port)))
}
<|endoftext|>


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

package main

import (
	"errors"
	"flag"
	"fmt"
	"net/http"
	"strings"
)

var (
	serverPort = flag.Int("port", 0, "The port on which the standalone HTTP server will run.")
)

type blogServer struct {
	r *render
}

func (b *blogServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	url := strings.Trim(req.URL.Path, "/")

	if url == "" {
		serveNode(rw, req, b.r)
		return
	}

	parts := strings.Split(url, "/")
	node := b.r
	for _, part := range parts {
		if child, ok := node.object.(renderTree)[part]; ok {
			node = child
		} else {
			http.NotFound(rw, req)
			return
		}
	}

	serveNode(rw, req, node)
}

func serveNode(rw http.ResponseWriter, req *http.Request, render *render) {
	switch render.t {
	case renderTypePost:
		post := render.object.(*Post)
		data, err := post.GetContents()
		if err != nil {
			rw.WriteHeader(http.StatusNotFound)
			fmt.Fprint(rw, err.Error())
			return
		}
		content := RenderPost(post, data)
		rw.Write(content)
	case renderTypeRedirect:
		fallthrough
	case renderTypeDirectory:
		// The root element should generate a post list.
		if render.t == renderTypeDirectory && render.parent == nil {
			fmt.Fprint(rw, "Need to implmenet post list for HTTP server :(")
			return
		}

		// Other directories when accessed directly should fallback to the
		// redirect.
		if render.t == renderTypeDirectory {
			render = render.object.(renderTree)["index.html"]
		}

		http.Redirect(rw, req, render.object.(string), http.StatusMovedPermanently)
	default:
		rw.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(rw, "Unknown render: %v", render)
	}
}

func RunAsServer() bool {
	return *serverPort != 0
}

func StartBlogServer(posts []*Post) error {
	if !RunAsServer() {
		return errors.New("No --port specified to start the server")
	}

	root, err := createRenderTree(posts)
	if err != nil {
		return err
	}

	fmt.Printf("Starting blog server on port %d\n", *serverPort)
	return http.ListenAndServe(fmt.Sprintf(":%d", *serverPort), &blogServer{root})
}

func newBlogServer(r *render) http.Handler {
	return &blogServer{
		r: r,
	}
}
<commit_msg>Implement the post list with the new CreateIndex.<commit_after>//
// Blackblog
// Copyright 2012 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package main

import (
	"errors"
	"flag"
	"fmt"
	"net/http"
	"strings"
)

var (
	serverPort = flag.Int("port", 0, "The port on which the standalone HTTP server will run.")
)

type blogServer struct {
	posts PostList
	r     *render
}

func (b *blogServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	url := strings.Trim(req.URL.Path, "/")

	if url == "" {
		b.serveNode(rw, req, b.r)
		return
	}

	parts := strings.Split(url, "/")
	node := b.r
	for _, part := range parts {
		if child, ok := node.object.(renderTree)[part]; ok {
			node = child
		} else {
			http.NotFound(rw, req)
			return
		}
	}

	b.serveNode(rw, req, node)
}

func (b *blogServer) serveNode(rw http.ResponseWriter, req *http.Request, render *render) {
	switch render.t {
	case renderTypePost:
		post := render.object.(*Post)
		data, err := post.GetContents()
		if err != nil {
			rw.WriteHeader(http.StatusNotFound)
			fmt.Fprint(rw, err.Error())
			return
		}
		content := RenderPost(post, data)
		rw.Write(content)
	case renderTypeRedirect:
		fallthrough
	case renderTypeDirectory:
		// The root element should generate a post list.
		if render.t == renderTypeDirectory && render.parent == nil {
			index, err := CreateIndex(b.posts)
			if err != nil {
				rw.WriteHeader(http.StatusInternalServerError)
				fmt.Fprint(rw, err.Error())
				return
			}
			rw.Write(index)
			return
		}

		// Other directories when accessed directly should fallback to the
		// redirect.
		if render.t == renderTypeDirectory {
			render = render.object.(renderTree)["index.html"]
		}

		http.Redirect(rw, req, render.object.(string), http.StatusMovedPermanently)
	default:
		rw.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(rw, "Unknown render: %v", render)
	}
}

func RunAsServer() bool {
	return *serverPort != 0
}

func StartBlogServer(posts PostList) error {
	if !RunAsServer() {
		return errors.New("No --port specified to start the server")
	}

	root, err := createRenderTree(posts)
	if err != nil {
		return err
	}

	fmt.Printf("Starting blog server on port %d\n", *serverPort)
	return http.ListenAndServe(fmt.Sprintf(":%d", *serverPort), &blogServer{
		posts: posts,
		r:     root,
	})
}

func newBlogServer(r *render) http.Handler {
	return &blogServer{
		r: r,
	}
}
<|endoftext|>


<commit_before>
// Simple chat server which uses connection properties from "connection.json" in same directory
// Simple chat client is intended to be used but a standard telnet connection can be used
// > telnet {host} {port}
// > /user {username}
// > /message {message}
//
// reference: https://parroty00.wordpress.com/2013/07/18/golang-tcp-server-example/
package main

import (
  "net"
  "fmt"
  "bufio"
  "strings"
  "regexp"
)

// Container for client username and connection details
type Client struct {
  Connection net.Conn
  Username string
}

// Close the client connection and clenup
func (client *Client) Close(doSendMessage bool) {
  if (doSendMessage) {
    // if we send the close command, the connection will terminate causing another close
    // which will send the message
    sendMessage("leave", "", client, false)
  }
  client.Connection.Close();
  clients = removeEntry(client, clients);
}

// Register the connection and cache it
func (client *Client) Register() {
  clients = append(clients, client);
}

// static client list
var clients []*Client

// program main
func main() {
  // start the server
  psock, err := net.Listen("tcp", ":5000")
  if err != nil {
    fmt.Printf("Can't create server %v\n", err)
    return
  }

  for {
    // accept connections
    conn, err := psock.Accept()
    if err != nil {
      fmt.Printf("Can't accept connections %v\n", err)
      return
    }

    // keep track of the client details
    client := Client{Connection: conn}
    client.Register();

    // allow non-blocking client request handling
    channel := make(chan string)
    go waitForInput(channel, &client)
    go handleInput(channel, &client)
  }
}

// wait for client input (buffered by newlines) and signal the channel
func waitForInput(out chan string, client *Client) {
  defer close(out)

  for {
    line, err := bufio.NewReader(client.Connection).ReadBytes('\n')
    if err != nil {
      // connection has been closed, remove the client
      client.Close(true);
      return
    }
    out <- string(line)
  }
}

// listen for channel updates for a client and handle the message
// messages must be in the format of /{action} {content} where content is optional depending on the action
// supported actions are "user", "chat", and "quit".  the "user" must be set before any chat messages are allowed
func handleInput(in <-chan string, client *Client) {
  for {
    message := <- in
    message = strings.TrimSpace(message)
    action, body := getAction(message)

    if (action != "") {
      switch action {
        case "message":
          sendMessage("message", body, client, false)
        case "user":
          client.Username = body
          sendMessage("enter", "", client, false)
        case "leave":
          client.Close(false);
        default:
          sendMessage("unrecognized", action, client, true)
      }
    }
  }
}

// sent a message to all clients (except the sender)
func sendMessage(messageType string, message string, client *Client, thisClientOnly bool) {
  message = fmt.Sprintf("/%v [%v] %v\n", messageType, client.Username, message);

  for _, _client := range clients {
    // write the message to the client
    if ((thisClientOnly && _client.Username == client.Username) ||
        (!thisClientOnly && _client != client && _client.Username != "")) {
      // you won't hear any activity if you are anonymous unless thisClientOnly
      // when current client will *only* be messaged
      fmt.Fprintf(_client.Connection, message)
    }
  }
}

// parse out message contents (/{action} {message}) and return individual values
func getAction(message string) (string, string) {
  actionRegex, _ := regexp.Compile(`^\/([^\s]*)\s*(.*)$`)
  res := actionRegex.FindAllStringSubmatch(message, -1)
  if (len(res) == 1) {
    return res[0][1], res[0][2]
  }
  return "", ""
}

// remove client entry from stored clients
func removeEntry(client *Client, arr []*Client) []*Client {
  rtn := arr
  index := -1
  for i, value := range arr {
    if (value == client) {
      index = i;
      break;
    }
  }

  if (index >= 0) {
    // we have a match, create a new array without the match
    rtn = make([]*Client, len(arr)-1)
    copy(rtn, arr[:index])
    copy(rtn[index:], arr[index+1:])
    fmt.Printf("found entry and new arr is %v", rtn);
  }

  return rtn;
}
<commit_msg>add logs<commit_after>
// Simple chat server which uses connection properties from "connection.json" in same directory
// Simple chat client is intended to be used but a standard telnet connection can be used
// > telnet {host} {port}
// > /user {username}
// > /message {message}
//
// reference: https://parroty00.wordpress.com/2013/07/18/golang-tcp-server-example/
package main

import (
  "net"
  "fmt"
  "bufio"
  "strings"
  "regexp"
)

// Container for client username and connection details
type Client struct {
  Connection net.Conn
  Username string
}

// Close the client connection and clenup
func (client *Client) Close(doSendMessage bool) {
  if (doSendMessage) {
    // if we send the close command, the connection will terminate causing another close
    // which will send the message
    sendMessage("leave", "", client, false)
  }
  client.Connection.Close();
  clients = removeEntry(client, clients);
}

// Register the connection and cache it
func (client *Client) Register() {
  clients = append(clients, client);
}

// static client list
var clients []*Client

// program main
func main() {
  // start the server
  psock, err := net.Listen("tcp", ":5000")
  if err != nil {
    fmt.Printf("Can't create server %v\n", err)
    return
  }
  println("Chat server started...")

  for {
    // accept connections
    conn, err := psock.Accept()
    if err != nil {
      fmt.Printf("Can't accept connections %v\n", err)
      return
    }

    // keep track of the client details
    client := Client{Connection: conn}
    client.Register();

    // allow non-blocking client request handling
    channel := make(chan string)
    go waitForInput(channel, &client)
    go handleInput(channel, &client)

    println("User connection")
  }
}

// wait for client input (buffered by newlines) and signal the channel
func waitForInput(out chan string, client *Client) {
  defer close(out)

  for {
    line, err := bufio.NewReader(client.Connection).ReadBytes('\n')
    if err != nil {
      // connection has been closed, remove the client
      client.Close(true);
      return
    }
    out <- string(line)
  }
}

// listen for channel updates for a client and handle the message
// messages must be in the format of /{action} {content} where content is optional depending on the action
// supported actions are "user", "chat", and "quit".  the "user" must be set before any chat messages are allowed
func handleInput(in <-chan string, client *Client) {
  fmt.Printf("input received \"%v\"\n", in);

  for {
    message := <- in
    message = strings.TrimSpace(message)
    action, body := getAction(message)

    if (action != "") {
      switch action {
        case "message":
          sendMessage("message", body, client, false)
        case "user":
          client.Username = body
          sendMessage("enter", "", client, false)
        case "leave":
          client.Close(false);
        default:
          sendMessage("unrecognized", action, client, true)
      }
    }
  }
}

// sent a message to all clients (except the sender)
func sendMessage(messageType string, message string, client *Client, thisClientOnly bool) {
  message = fmt.Sprintf("/%v [%v] %v", messageType, client.Username, message);
  if (thisClientOnly) {
      fmt.Printf("sending message to only %v \"%v\"\n", client.Username, message)
    } else {
      fmt.Printf("sending message to all but %v \"%v\"\n", client.Username, message)
    }

  for _, _client := range clients {
    // write the message to the client
    if ((thisClientOnly && _client.Username == client.Username) ||
        (!thisClientOnly && _client != client && _client.Username != "")) {
      // you won't hear any activity if you are anonymous unless thisClientOnly
      // when current client will *only* be messaged
      fmt.Fprintln(_client.Connection, message)
    }
  }
}

// parse out message contents (/{action} {message}) and return individual values
func getAction(message string) (string, string) {
  actionRegex, _ := regexp.Compile(`^\/([^\s]*)\s*(.*)$`)
  res := actionRegex.FindAllStringSubmatch(message, -1)
  if (len(res) == 1) {
    return res[0][1], res[0][2]
  }
  return "", ""
}

// remove client entry from stored clients
func removeEntry(client *Client, arr []*Client) []*Client {
  rtn := arr
  index := -1
  for i, value := range arr {
    if (value == client) {
      index = i;
      break;
    }
  }

  if (index >= 0) {
    // we have a match, create a new array without the match
    rtn = make([]*Client, len(arr)-1)
    copy(rtn, arr[:index])
    copy(rtn[index:], arr[index+1:])
  }

  return rtn;
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/influxdata/influxdb/client/v2"
)

// AkamaiPayload is a Golang representation of the Cloudmonitor JSON datastructure
type AkamaiPayload struct {
	// Content Provider ID
	CP string `json:"cp"`
	// Defines the format of the payload (?)
	Format  string        `json:"format"`
	Geo     GeoStruct     `json:"geo"`
	ID      string        `json:"id"`
	Message MessageStruct `json:"message"`
	NetPerf NetPerfStruct `json:"netPerf"`
	Network NetworkStruct `json:"network"`
	ReqHdr  ReqHdrStruct  `json:"reqHdr"`
	RespHdr RespHdrStruct `json:"respHdr"`
	Start   string        `json:"start"`
	Type    string        `json:"type"`
	Version string        `json:"version"`
}

// GeoStruct is used for storing the JSON subfields
type GeoStruct struct {
	City    string `json:"city"`
	Country string `json:"country"`
	Lat     string `json:"lat"`
	Long    string `json:"long"`
	Region  string `json:"region"`
}

// MessageStruct is used for storing the JSON subfields
type MessageStruct struct {
	UA        string `json:"UA"`
	Bytes     string `json:"bytes"`
	CliIP     string `json:"cliIP"`
	FwdHost   string `json:"fwdHost"`
	Proto     string `json:"proto"`
	ProtoVer  string `json:"protoVer"`
	ReqHost   string `json:"reqHost"`
	ReqMethod string `json:"reqMethod"`
	ReqPath   string `json:"reqPath"`
	ReqPort   string `json:"reqPort"`
	RespCT    string `json:"respCT"`
	RespLen   string `json:"respLen"`
	Status    string `json:"status"`
}

// NetPerfStruct is used for storing the JSON subfields
type NetPerfStruct struct {
	Asnum        string `json:"asnum"`
	CacheStatus  string `json:"cacheStatus"`
	DownloadTime string `json:"downloadTime"`
	EdgeIP       string `json:"edgeIP"`
	FirstByte    string `json:"firstByte"`
	LastByte     string `json:"lastByte"`
	LastMileRTT  string `json:"lastMileRTT"`
}

// NetworkStruct is used for storing the JSON subfields
type NetworkStruct struct {
	Asnum       string `json:"asnum"`
	EdgeIP      string `json:"edgeIP"`
	Network     string `json:"network"`
	NetworkType string `json:"networkType"`
}

// ReqHdrStruct is used for storing the JSON subfields
type ReqHdrStruct struct {
	Cookie string `json:"cookie"`
}

// RespHdrStruct is used for storing the JSON subfields
type RespHdrStruct struct {
	Server  string `json:"server"`
	ContEnc string `json:"contEnc"`
}

// CreateObjects creates a list of AkamaiPayloads from a raw byte slice
func CreateObjects(jsonFile []byte) (_ []AkamaiPayload, err error) {
	var arrayObject []AkamaiPayload
	err = json.Unmarshal(jsonFile, &arrayObject)
	return arrayObject, err
}

// Handle parses the incoming request data
func Handle(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "OK! I got you Bro! -> ")
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}
	obj, err := CreateObjects(body)
	if err != nil {
		log.Fatal(err)
	}
	c, err := client.NewHTTPClient(client.HTTPConfig{
		Addr: "http://influxDB:8086",
	})

	// Create a new point batch
	bp, err := client.NewBatchPoints(client.BatchPointsConfig{
		Database: "metrics",
		//Precision: "s",
	})
	if err != nil {
		log.Fatal(err)
	}

	for key, o := range obj {
		//payload[0].Geo["city"]
		fmt.Println("Server is:", o.RespHdr.Server, "KEY:", key)

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

		// Create a point and add to batch
		tags := map[string]string{
			"city":    o.Geo.City,
			"country": o.Geo.Country,
		}
		lat, err := strconv.ParseFloat(o.Geo.Lat, 64)
		long, err := strconv.ParseFloat(o.Geo.Long, 64)
		if err != nil {
			log.Fatal(err)
		}
		fields := map[string]interface{}{
			"lat":  lat,
			"long": long,
		}

		pt, err := client.NewPoint("measurement", tags, fields, time.Now())
		if err != nil {
			log.Fatal(err)
		}
		bp.AddPoint(pt)
	}

	// Write the batch
	if err := c.Write(bp); err != nil {
		log.Fatal(err)
	}
}

func main() {

	http.HandleFunc("/", Handle)
	http.ListenAndServe(":9143", nil)
}
<commit_msg>Reorganised AkamaiPayload<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/influxdata/influxdb/client/v2"
)

// AkamaiPayload is a Golang representation of the Cloudmonitor JSON datastructure
type AkamaiPayload struct {
	// Content Provider ID
	CP string `json:"cp"`
	// Defines the format of the payload (?)
	Format  string `json:"format"`
	ID      string `json:"id"`
	Start   string `json:"start"`
	Type    string `json:"type"`
	Version string `json:"version"`

	Geo     GeoStruct     `json:"geo"`
	Message MessageStruct `json:"message"`
	NetPerf NetPerfStruct `json:"netPerf"`
	Network NetworkStruct `json:"network"`
	ReqHdr  ReqHdrStruct  `json:"reqHdr"`
	RespHdr RespHdrStruct `json:"respHdr"`
}

// GeoStruct is used for storing the JSON subfields
type GeoStruct struct {
	City    string `json:"city"`
	Country string `json:"country"`
	Lat     string `json:"lat"`
	Long    string `json:"long"`
	Region  string `json:"region"`
}

// MessageStruct is used for storing the JSON subfields
type MessageStruct struct {
	UA        string `json:"UA"`
	Bytes     string `json:"bytes"`
	CliIP     string `json:"cliIP"`
	FwdHost   string `json:"fwdHost"`
	Proto     string `json:"proto"`
	ProtoVer  string `json:"protoVer"`
	ReqHost   string `json:"reqHost"`
	ReqMethod string `json:"reqMethod"`
	ReqPath   string `json:"reqPath"`
	ReqPort   string `json:"reqPort"`
	RespCT    string `json:"respCT"`
	RespLen   string `json:"respLen"`
	Status    string `json:"status"`
}

// NetPerfStruct is used for storing the JSON subfields
type NetPerfStruct struct {
	Asnum        string `json:"asnum"`
	CacheStatus  string `json:"cacheStatus"`
	DownloadTime string `json:"downloadTime"`
	EdgeIP       string `json:"edgeIP"`
	FirstByte    string `json:"firstByte"`
	LastByte     string `json:"lastByte"`
	LastMileRTT  string `json:"lastMileRTT"`
}

// NetworkStruct is used for storing the JSON subfields
type NetworkStruct struct {
	Asnum       string `json:"asnum"`
	EdgeIP      string `json:"edgeIP"`
	Network     string `json:"network"`
	NetworkType string `json:"networkType"`
}

// ReqHdrStruct is used for storing the JSON subfields
type ReqHdrStruct struct {
	Cookie string `json:"cookie"`
}

// RespHdrStruct is used for storing the JSON subfields
type RespHdrStruct struct {
	Server  string `json:"server"`
	ContEnc string `json:"contEnc"`
}

// CreateObjects creates a list of AkamaiPayloads from a raw byte slice
func CreateObjects(jsonFile []byte) (_ []AkamaiPayload, err error) {
	var arrayObject []AkamaiPayload
	err = json.Unmarshal(jsonFile, &arrayObject)
	return arrayObject, err
}

// Handle parses the incoming request data
func Handle(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "OK! I got you Bro! -> ")
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}
	obj, err := CreateObjects(body)
	if err != nil {
		log.Fatal(err)
	}
	c, err := client.NewHTTPClient(client.HTTPConfig{
		Addr: "http://influxDB:8086",
	})

	// Create a new point batch
	bp, err := client.NewBatchPoints(client.BatchPointsConfig{
		Database: "metrics",
		//Precision: "s",
	})
	if err != nil {
		log.Fatal(err)
	}

	for key, o := range obj {
		//payload[0].Geo["city"]
		fmt.Println("Server is:", o.RespHdr.Server, "KEY:", key)

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

		// Create a point and add to batch
		tags := map[string]string{
			"cp":      o.CP,
			"format":  o.Format,
			"city":    o.Geo.City,
			"country": o.Geo.Country,
			o.Geo.Region,
		}
		lat, err := strconv.ParseFloat(o.Geo.Lat, 64)
		long, err := strconv.ParseFloat(o.Geo.Long, 64)
		if err != nil {
			log.Fatal(err)
		}
		fields := map[string]interface{}{
			"lat":  lat,
			"long": long,
		}

		pt, err := client.NewPoint("measurement", tags, fields, time.Now())
		if err != nil {
			log.Fatal(err)
		}
		bp.AddPoint(pt)
	}

	// Write the batch
	if err := c.Write(bp); err != nil {
		log.Fatal(err)
	}
}

func main() {

	http.HandleFunc("/", Handle)
	http.ListenAndServe(":9143", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/thoj/go-ircevent"
	"os"
	"strings"
)

type Configuration struct {
	Network  string
	Nick     string
	Username string
	Password string
	Channel  string
}

type Handler interface {
	Id() string
	Matches(e *irc.Event) bool
	Handle(man *Manager, e *irc.Event)
}

type Manager struct {
	conn     *irc.Connection
	config   Configuration
	handlers map[string]Handler
}

func (man *Manager) Remove(h Handler) {
	fmt.Println("Removing handler ", h.Id())
	if _, ok := man.handlers[h.Id()]; ok {
		delete(man.handlers, h.Id())
	}
}

func (man *Manager) Add(h Handler) {
	fmt.Println("Adding handler ", h.Id())
	man.handlers[h.Id()] = h
}

func NewManager(conn *irc.Connection, config Configuration) *Manager {
	man := &Manager{conn, config, make(map[string]Handler, 4)}

	man.Add(&NickservHandler{})
	man.Add(&AliasHandler{make(map[string]string, 4)})

	return man
}

func main() {
	file, err := os.Open("config.json")
	if err != nil {
		panic("Could not open config.json: " + err.Error())
	}

	decoder := json.NewDecoder(file)

	config := Configuration{}
	if err := decoder.Decode(&config); err != nil {
		panic("Could not decode config.json: " + err.Error())
	}

	conn := irc.IRC(config.Nick, config.Username)
	conn.Debug = true
	conn.VerboseCallbackHandler = true

	err = conn.Connect(config.Network)
	if err != nil {
		panic(err)
	}

	man := NewManager(conn, config)

	matchAndHandle := func(e *irc.Event) {
		for _, h := range man.handlers {
			if h.Matches(e) {
				h.Handle(man, e)
			}
		}
	}

	conn.AddCallback("001", func(e *irc.Event) { conn.Join(config.Channel) })

	conn.AddCallback("PRIVMSG", matchAndHandle)
	conn.AddCallback("NOTICE", matchAndHandle)

	conn.Loop()
}

func replyTarget(e *irc.Event) string {
	if strings.HasPrefix(e.Arguments[0], "#") {
		return e.Arguments[0]
	} else {
		return e.Nick
	}
}

func parseCommand(msg string) (string, []string) {
	fields := strings.Fields(msg)
	if len(fields) < 1 {
		panic("No command")
	}

	command := fields[0][1:]
	args := fields[1:]

	return command, args
}

type NickservHandler struct{}

func (h *NickservHandler) Id() string {
	return "nickserv"
}

func (h *NickservHandler) Matches(e *irc.Event) bool {
	return strings.Contains(strings.ToLower(e.Message()), "identify") && e.User == "NickServ"
}

func (h *NickservHandler) Handle(man *Manager, e *irc.Event) {
	man.Remove(h)
	man.conn.Privmsgf("NickServ", "IDENTIFY %s", man.config.Password)
}

type AliasHandler struct{
	aliases map[string]string
}

func (h *AliasHandler) Id() string {
	return "alias"
}

func (h *AliasHandler) Matches(e *irc.Event) bool {
	return strings.HasPrefix(strings.ToLower(e.Message()), "!")
}

func (h *AliasHandler) Handle(man *Manager, e *irc.Event) {
	command, args := parseCommand(e.Message())

	message, ok := h.aliases[command]
	switch {
	case command == "alias":
		if len(args) < 2 {
			man.conn.Privmsgf(replyTarget(e), "Usage: !alias <add/remove> name [message]")

		} else if args[0] == "add" {
			h.aliases[args[1]] = strings.Join(args[2:], " ")
			man.conn.Privmsgf(replyTarget(e), "Added '%s'", fields[2])

		} else if args[0] == "remove" {
			if _, ok := h.aliases[fields[2]]; ok {
				delete(h.aliases, fields[2])
				man.conn.Privmsgf(replyTarget(e), "Removed '%s'", fields[2])
			}
		}

	case ok:
		man.conn.Privmsgf(replyTarget(e), message)
	}
}
<commit_msg>Fixed bad var references<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/thoj/go-ircevent"
	"os"
	"strings"
)

type Configuration struct {
	Network  string
	Nick     string
	Username string
	Password string
	Channel  string
}

type Handler interface {
	Id() string
	Matches(e *irc.Event) bool
	Handle(man *Manager, e *irc.Event)
}

type Manager struct {
	conn     *irc.Connection
	config   Configuration
	handlers map[string]Handler
}

func (man *Manager) Remove(h Handler) {
	fmt.Println("Removing handler ", h.Id())
	if _, ok := man.handlers[h.Id()]; ok {
		delete(man.handlers, h.Id())
	}
}

func (man *Manager) Add(h Handler) {
	fmt.Println("Adding handler ", h.Id())
	man.handlers[h.Id()] = h
}

func NewManager(conn *irc.Connection, config Configuration) *Manager {
	man := &Manager{conn, config, make(map[string]Handler, 4)}

	man.Add(&NickservHandler{})
	man.Add(&AliasHandler{make(map[string]string, 4)})

	return man
}

func main() {
	file, err := os.Open("config.json")
	if err != nil {
		panic("Could not open config.json: " + err.Error())
	}

	decoder := json.NewDecoder(file)

	config := Configuration{}
	if err := decoder.Decode(&config); err != nil {
		panic("Could not decode config.json: " + err.Error())
	}

	conn := irc.IRC(config.Nick, config.Username)
	conn.Debug = true
	conn.VerboseCallbackHandler = true

	err = conn.Connect(config.Network)
	if err != nil {
		panic(err)
	}

	man := NewManager(conn, config)

	matchAndHandle := func(e *irc.Event) {
		for _, h := range man.handlers {
			if h.Matches(e) {
				h.Handle(man, e)
			}
		}
	}

	conn.AddCallback("001", func(e *irc.Event) { conn.Join(config.Channel) })

	conn.AddCallback("PRIVMSG", matchAndHandle)
	conn.AddCallback("NOTICE", matchAndHandle)

	conn.Loop()
}

func replyTarget(e *irc.Event) string {
	if strings.HasPrefix(e.Arguments[0], "#") {
		return e.Arguments[0]
	} else {
		return e.Nick
	}
}

func parseCommand(msg string) (string, []string) {
	fields := strings.Fields(msg)
	if len(fields) < 1 {
		panic("No command")
	}

	command := fields[0][1:]
	args := fields[1:]

	return command, args
}

type NickservHandler struct{}

func (h *NickservHandler) Id() string {
	return "nickserv"
}

func (h *NickservHandler) Matches(e *irc.Event) bool {
	return strings.Contains(strings.ToLower(e.Message()), "identify") && e.User == "NickServ"
}

func (h *NickservHandler) Handle(man *Manager, e *irc.Event) {
	man.Remove(h)
	man.conn.Privmsgf("NickServ", "IDENTIFY %s", man.config.Password)
}

type AliasHandler struct{
	aliases map[string]string
}

func (h *AliasHandler) Id() string {
	return "alias"
}

func (h *AliasHandler) Matches(e *irc.Event) bool {
	return strings.HasPrefix(strings.ToLower(e.Message()), "!")
}

func (h *AliasHandler) Handle(man *Manager, e *irc.Event) {
	command, args := parseCommand(e.Message())

	message, ok := h.aliases[command]
	switch {
	case command == "alias":
		if len(args) < 2 {
			man.conn.Privmsgf(replyTarget(e), "Usage: !alias <add/remove> name [message]")

		} else if args[0] == "add" {
			h.aliases[args[1]] = strings.Join(args[2:], " ")
			man.conn.Privmsgf(replyTarget(e), "Added '%s'", args[1])

		} else if args[0] == "remove" {
			if _, ok := h.aliases[args[1]]; ok {
				delete(h.aliases, args[1])
				man.conn.Privmsgf(replyTarget(e), "Removed '%s'", args[1])
			}
		}

	case ok:
		man.conn.Privmsgf(replyTarget(e), message)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/vanng822/go-solr/solr"
	"log"
	"net/http"
	"strconv"
	"time"
)

// Article models the result for the /getAll/ route
type Article struct {
	ID               int
	Title            string
	Subtitle         string
	ShortDescription string
	BuyNowPrice      float32
	CurrentBidPrice  float32
	URL              string
	MainImageURL     string
}

var solrServer *solr.SolrInterface

// During init we populate Solr with dummy data
func init() {
	var err error
	solrServer, err = solr.NewSolrInterface("http://localhost:8983/solr/", "searchAws")
	if err != nil {
		log.Fatal(err)
	}
	_, errs := solrServer.DeleteAll()
	if errs != nil {
		log.Fatal(err)
	}
	docs := make([]solr.Document, 1)
	doc1 := make(solr.Document)
	doc1["ID"] = 1
	doc1["Title"] = "Test title"
	doc1["Subtitle"] = "Test subtitle"
	docs = append(docs, doc1)
	response, err := solrServer.Add(docs, 1, nil)
	if err != nil {
		log.Fatal(err)
	}
	response, err = solrServer.Commit()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Commit response: %s", strconv.FormatBool(response.Success))
	for key, value := range response.Result {
		fmt.Println(key, "=", value)
	}
}

func main() {
	r := mux.NewRouter().StrictSlash(true)
	r.HandleFunc("/getAll", GetAllHandler).Methods("GET")
	http.Handle("/", r)
	log.Printf("Server started and listening on port %d.", 3232)
	log.Fatal(http.ListenAndServe(":3232", nil))
}

// GetAllHandler handles requests
func GetAllHandler(w http.ResponseWriter, r *http.Request) {
	start := time.Now()

	w.Header().Set("Content-Type", "application/json")

	query := solr.NewQuery()
	query.Q("Title:Test title")
	s := solrServer.Search(query)
	resp, _ := s.Result(nil)
	fmt.Println(resp.Results.Docs)
	response, err := json.Marshal(resp.Results.Docs)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(response)
	duration := time.Since(start)
	log.Printf("\t%s\t%s",
		r.RequestURI,
		duration)
	return
}
<commit_msg>return a single Doc<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/vanng822/go-solr/solr"
	"log"
	"net/http"
	"strconv"
	"time"
)

// Article models the result for the /getAll/ route
type Article struct {
	ID               int
	Title            string
	Subtitle         string
	ShortDescription string
	BuyNowPrice      float32
	CurrentBidPrice  float32
	URL              string
	MainImageURL     string
}

var solrServer *solr.SolrInterface

// During init we populate Solr with dummy data
func init() {
	var err error
	solrServer, err = solr.NewSolrInterface("http://localhost:8983/solr/", "searchAws")
	if err != nil {
		log.Fatal(err)
	}
	_, errs := solrServer.DeleteAll()
	if errs != nil {
		log.Fatal(err)
	}
	docs := make([]solr.Document, 1)
	doc1 := make(solr.Document)
	doc1["ID"] = 1
	doc1["Title"] = "Test title"
	doc1["Subtitle"] = "Test subtitle"
	docs = append(docs, doc1)
	response, err := solrServer.Add(docs, 1, nil)
	if err != nil {
		log.Fatal(err)
	}
	response, err = solrServer.Commit()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Commit response: %s", strconv.FormatBool(response.Success))
	for key, value := range response.Result {
		fmt.Println(key, "=", value)
	}
}

func main() {
	r := mux.NewRouter().StrictSlash(true)
	r.HandleFunc("/getAll", GetAllHandler).Methods("GET")
	http.Handle("/", r)
	log.Printf("Server started and listening on port %d.", 3232)
	log.Fatal(http.ListenAndServe(":3232", nil))
}

// GetAllHandler handles requests
func GetAllHandler(w http.ResponseWriter, r *http.Request) {
	start := time.Now()

	w.Header().Set("Content-Type", "application/json")

	query := solr.NewQuery()
	query.Q("Title:Test title")
	s := solrServer.Search(query)
	resp, _ := s.Result(nil)
	fmt.Println(resp.Results.Docs)
	response, err := json.Marshal(resp.Results.Docs[0])
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(response)
	duration := time.Since(start)
	log.Printf("\t%s\t%s",
		r.RequestURI,
		duration)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/ViBiOh/docker-deploy/docker"
	"log"
	"net/http"
	"runtime"
)

const port = `1080`

const host = `DOCKER_HOST`
const version = `DOCKER_VERSION`

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	http.Handle(`/`, docker.Handler{})
	http.Handle(`/ws/`, docker.WsHandler{})

	log.Print(`Starting server on port ` + port)
	log.Fatal(http.ListenAndServe(`:`+port, nil))
}
<commit_msg>Changing handle order<commit_after>package main

import (
	"github.com/ViBiOh/docker-deploy/docker"
	"log"
	"net/http"
	"runtime"
)

const port = `1080`

const host = `DOCKER_HOST`
const version = `DOCKER_VERSION`

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	http.Handle(`/ws/`, docker.WsHandler{})
	http.Handle(`/`, docker.Handler{})

	log.Print(`Starting server on port ` + port)
	log.Fatal(http.ListenAndServe(`:`+port, nil))
}
<|endoftext|>