<commit_before>package mstate

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"launchpad.net/juju-core/charm"
	"sort"
	"strings"
)

// RelationRole defines the role of a relation endpoint.
type RelationRole string

const (
	RoleProvider RelationRole = "provider"
	RoleRequirer RelationRole = "requirer"
	RolePeer     RelationRole = "peer"
)

// counterpartRole returns the RelationRole that this RelationRole
// can relate to.
// This should remain an internal method because the relation
// model does not guarantee that for every role there will
// necessarily exist a single counterpart role that is sensible
// for basing algorithms upon.
func (r RelationRole) counterpartRole() RelationRole {
	switch r {
	case RoleProvider:
		return RoleRequirer
	case RoleRequirer:
		return RoleProvider
	case RolePeer:
		return RolePeer
	}
	panic(fmt.Errorf("unknown RelationRole: %q", r))
}

// RelationEndpoint represents one endpoint of a relation.
type RelationEndpoint struct {
	ServiceName   string
	Interface     string
	RelationName  string
	RelationRole  RelationRole
	RelationScope charm.RelationScope
}

// CanRelateTo returns whether a relation may be established between e and other.
func (e *RelationEndpoint) CanRelateTo(other *RelationEndpoint) bool {
	if e.Interface != other.Interface {
		return false
	}
	if e.RelationRole == RolePeer {
		// Peer relations do not currently work with multiple endpoints.
		return false
	}
	return e.RelationRole.counterpartRole() == other.RelationRole
}

// String returns the unique identifier of the relation endpoint.
func (e RelationEndpoint) String() string {
	return e.ServiceName + ":" + e.RelationName
}

// relationKey returns a string describing the relation defined by
// endpoints, for use in various contexts (including error messages).
func relationKey(endpoints []RelationEndpoint) string {
	names := []string{}
	for _, ep := range endpoints {
		names = append(names, ep.String())
	}
	sort.Strings(names)
	return strings.Join(names, " ")
}

// relationDoc is the internal representation of a Relation in MongoDB.
type relationDoc struct {
	Id        int `bson:"_id"`
	Key       string
	Endpoints []RelationEndpoint
	Life      Life
}

// Relation represents a relation between one or two service endpoints.
type Relation struct {
	st  *State
	doc relationDoc
}

func newRelation(st *State, doc *relationDoc) *Relation {
	return &Relation{
		st:  st,
		doc: *doc,
	}
}

func (r *Relation) String() string {
	return r.doc.Key
}

func (r *Relation) Refresh() error {
	doc := relationDoc{}
	err := r.st.relations.FindId(r.doc.Id).One(&doc)
	if err != nil {
		return fmt.Errorf("cannot refresh relation %v: %v", r, err)
	}
	r.doc = doc
	return nil
}

func (r *Relation) Life() Life {
	return r.doc.Life
}

// ensureLife changes the lifecycle state of the relation.
// See the Life type for more details.
func (r *Relation) ensureLife(life Life) error {
	if life == Alive {
		panic("cannot set life to alive")
	}
	sel := bson.D{
		{"_id", r.doc.Id},
		// $lte is used so that we don't overwrite a previous
		// change we don't know about.
		{"life", bson.D{{"$lte", life}}},
	}
	change := bson.D{{"$set", bson.D{{"life", life}}}}
	err := r.st.relations.Update(sel, change)
	if err == mgo.ErrNotFound {
		return nil
	}
	if err != nil {
		return fmt.Errorf("cannot set life to %v for relation %v: %v", life, r, err)
	}
	r.doc.Life = life
	return nil
}

// Kill sets the relation lifecycle to Dying if it is Alive.
// It does nothing otherwise.
func (r *Relation) Kill() error {
	return r.ensureLife(Dying)
}

// Die sets the relation lifecycle to Dead if it is Alive or Dying.
// It does nothing otherwise.
func (r *Relation) Die() error {
	return r.ensureLife(Dead)
}

// Id returns the integer internal relation key. This is exposed
// because the unit agent needs to expose a value derived from this
// (as JUJU_RELATION_ID) to allow relation hooks to differentiate
// between relations with different services.
func (r *Relation) Id() int {
	return r.doc.Id
}

// Endpoint returns the endpoint of the relation for the named service.
// If the service is not part of the relation, an error will be returned.
func (r *Relation) Endpoint(serviceName string) (RelationEndpoint, error) {
	for _, ep := range r.doc.Endpoints {
		if ep.ServiceName == serviceName {
			return ep, nil
		}
	}
	return RelationEndpoint{}, fmt.Errorf("service %q is not a member of %q", serviceName, r)
}

// RelatedEndpoints returns the endpoints of the relation r with which
// units of the named service will establish relations. If the service
// is not part of the relation r, an error will be returned.
func (r *Relation) RelatedEndpoints(serviceName string) ([]RelationEndpoint, error) {
	local, err := r.Endpoint(serviceName)
	if err != nil {
		return nil, err
	}
	role := local.RelationRole.counterpartRole()
	var eps []RelationEndpoint
	for _, ep := range r.doc.Endpoints {
		if ep.RelationRole == role {
			eps = append(eps, ep)
		}
	}
	if eps == nil {
		return nil, fmt.Errorf("no endpoints of %q relate to service %q", r, serviceName)
	}
	return eps, nil
}
<commit_msg>mstate: basic relation units<commit_after>package mstate

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"launchpad.net/juju-core/charm"
	"sort"
	"strings"
)

// RelationRole defines the role of a relation endpoint.
type RelationRole string

const (
	RoleProvider RelationRole = "provider"
	RoleRequirer RelationRole = "requirer"
	RolePeer     RelationRole = "peer"
)

// counterpartRole returns the RelationRole that this RelationRole
// can relate to.
// This should remain an internal method because the relation
// model does not guarantee that for every role there will
// necessarily exist a single counterpart role that is sensible
// for basing algorithms upon.
func (r RelationRole) counterpartRole() RelationRole {
	switch r {
	case RoleProvider:
		return RoleRequirer
	case RoleRequirer:
		return RoleProvider
	case RolePeer:
		return RolePeer
	}
	panic(fmt.Errorf("unknown RelationRole: %q", r))
}

// RelationEndpoint represents one endpoint of a relation.
type RelationEndpoint struct {
	ServiceName   string
	Interface     string
	RelationName  string
	RelationRole  RelationRole
	RelationScope charm.RelationScope
}

// CanRelateTo returns whether a relation may be established between e and other.
func (e *RelationEndpoint) CanRelateTo(other *RelationEndpoint) bool {
	if e.Interface != other.Interface {
		return false
	}
	if e.RelationRole == RolePeer {
		// Peer relations do not currently work with multiple endpoints.
		return false
	}
	return e.RelationRole.counterpartRole() == other.RelationRole
}

// String returns the unique identifier of the relation endpoint.
func (e RelationEndpoint) String() string {
	return e.ServiceName + ":" + e.RelationName
}

// relationKey returns a string describing the relation defined by
// endpoints, for use in various contexts (including error messages).
func relationKey(endpoints []RelationEndpoint) string {
	names := []string{}
	for _, ep := range endpoints {
		names = append(names, ep.String())
	}
	sort.Strings(names)
	return strings.Join(names, " ")
}

// relationDoc is the internal representation of a Relation in MongoDB.
type relationDoc struct {
	Id        int `bson:"_id"`
	Key       string
	Endpoints []RelationEndpoint
	Life      Life
}

// Relation represents a relation between one or two service endpoints.
type Relation struct {
	st  *State
	doc relationDoc
}

func newRelation(st *State, doc *relationDoc) *Relation {
	return &Relation{
		st:  st,
		doc: *doc,
	}
}

func (r *Relation) String() string {
	return r.doc.Key
}

func (r *Relation) Refresh() error {
	doc := relationDoc{}
	err := r.st.relations.FindId(r.doc.Id).One(&doc)
	if err != nil {
		return fmt.Errorf("cannot refresh relation %v: %v", r, err)
	}
	r.doc = doc
	return nil
}

func (r *Relation) Life() Life {
	return r.doc.Life
}

// ensureLife changes the lifecycle state of the relation.
// See the Life type for more details.
func (r *Relation) ensureLife(life Life) error {
	if life == Alive {
		panic("cannot set life to alive")
	}
	sel := bson.D{
		{"_id", r.doc.Id},
		// $lte is used so that we don't overwrite a previous
		// change we don't know about.
		{"life", bson.D{{"$lte", life}}},
	}
	change := bson.D{{"$set", bson.D{{"life", life}}}}
	err := r.st.relations.Update(sel, change)
	if err == mgo.ErrNotFound {
		return nil
	}
	if err != nil {
		return fmt.Errorf("cannot set life to %v for relation %v: %v", life, r, err)
	}
	r.doc.Life = life
	return nil
}

// Kill sets the relation lifecycle to Dying if it is Alive.
// It does nothing otherwise.
func (r *Relation) Kill() error {
	return r.ensureLife(Dying)
}

// Die sets the relation lifecycle to Dead if it is Alive or Dying.
// It does nothing otherwise.
func (r *Relation) Die() error {
	return r.ensureLife(Dead)
}

// Id returns the integer internal relation key. This is exposed
// because the unit agent needs to expose a value derived from this
// (as JUJU_RELATION_ID) to allow relation hooks to differentiate
// between relations with different services.
func (r *Relation) Id() int {
	return r.doc.Id
}

// Endpoint returns the endpoint of the relation for the named service.
// If the service is not part of the relation, an error will be returned.
func (r *Relation) Endpoint(serviceName string) (RelationEndpoint, error) {
	for _, ep := range r.doc.Endpoints {
		if ep.ServiceName == serviceName {
			return ep, nil
		}
	}
	return RelationEndpoint{}, fmt.Errorf("service %q is not a member of %q", serviceName, r)
}

// RelatedEndpoints returns the endpoints of the relation r with which
// units of the named service will establish relations. If the service
// is not part of the relation r, an error will be returned.
func (r *Relation) RelatedEndpoints(serviceName string) ([]RelationEndpoint, error) {
	local, err := r.Endpoint(serviceName)
	if err != nil {
		return nil, err
	}
	role := local.RelationRole.counterpartRole()
	var eps []RelationEndpoint
	for _, ep := range r.doc.Endpoints {
		if ep.RelationRole == role {
			eps = append(eps, ep)
		}
	}
	if eps == nil {
		return nil, fmt.Errorf("no endpoints of %q relate to service %q", r, serviceName)
	}
	return eps, nil
}

// RelationUnit holds information about a single unit in a relation, and
// allows clients to conveniently access unit-specific functionality.
type RelationUnit struct {
	st       *State
	relation *Relation
	unit     *Unit
	endpoint RelationEndpoint
}

// Relation returns the relation associated with the unit.
func (ru *RelationUnit) Relation() *Relation {
	return ru.relation
}

// Endpoint returns the relation endpoint that defines the unit's
// participation in the relation.
func (ru *RelationUnit) Endpoint() RelationEndpoint {
	return ru.endpoint
}

// Unit returns a RelationUnit for the supplied unit.
func (r *Relation) Unit(u *Unit) (*RelationUnit, error) {
	ep, err := r.Endpoint(u.doc.Service)
	if err != nil {
		return nil, err
	}
	return &RelationUnit{
		st:       r.st,
		relation: r,
		unit:     u,
		endpoint: ep,
	}, nil
}
<|endoftext|>


<commit_before>package main

////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2016, Gianluca Fiore
//
////////////////////////////////////////////////////////////////////////////////

import (
	"flag"
	"fmt"
	"os"
	"path"
	"regexp"
	"strconv"
)

var mgntType string
var watchdir string

var usageMessage = `
m2t [-t|-type <type>] [-w|watchdir <directory>] <magnetlink>

M2T (Magnet To Torrent) will convert magnet links to torrent files. It works by using the "watch directory" feature of many torrent clients

Arguments:
	-t|-type <type>
		The type of the file contained in the magnet link. Defaults to "others"

	-w|-watchdir <directory>
		The directory where the torrent client watches for new torrents.
		It must exist. Defaults to '/media/private/torrent/watch
	`

// Parse flags
func init() {

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usageMessage)
	}

	const (
		defWatchdir = "/media/private/torrent/watch"
		defType     = "others"
	)

	flag.StringVar(&mgntType, "type", defType, "")
	flag.StringVar(&mgntType, "t", defType, "")
	flag.StringVar(&watchdir, "watchdir", defWatchdir, "")
	flag.StringVar(&watchdir, "w", defWatchdir, "")

}

func main() {
	var torrentFilename, fileName string

	// initialize cli arguments
	flag.Parse()

	// at least the magnet link is needed, bail out if it was not given
	if flag.NArg() == 0 {
		fmt.Println("No magnet link given, exiting...")
		os.Exit(1)
	}

	// Compose the watch dir's path for the torrent file
	outputDir := path.Join(watchdir, mgntType)
	// Reassign first flag to a variable
	magnetLink := flag.Arg(0)

	// Compile a couple of regexp we need
	var validMagnet = regexp.MustCompile(`xt=urn(\.[0-9]*)?:btih:([^&/]+)`)
	var displayName = regexp.MustCompile(`dn=([^&/]+)`)

	if validMagnet.MatchString(magnetLink) {
		if displayName.MatchString(magnetLink) {
			torrentFilename = displayName.FindString(magnetLink)
			// split at '='
			fileName = regexp.MustCompile(`=`).Split(torrentFilename, -1)[1]
			if len(fileName) == 0 {
				xt := validMagnet.FindString(magnetLink)
				fileName = regexp.MustCompile(`:`).Split(xt, -1)[2]
			}
			// Add torrent extension
			fileName = fileName + ".torrent"
		}
	} else {
		// not a valid magnet URI given
		fmt.Println("The magnet URI is not correct or unparseable")
		os.Exit(1)
	}

	// Create torrent file and output magnet link string to it
	f, err := os.Create(path.Join(outputDir, fileName))
	if err != nil {
		panic(err)
	}
	_, wErr := f.WriteString("d10:magnet-uri" + strconv.Itoa(len(magnetLink)) + ":" + magnetLink + "e")
	if wErr != nil {
		panic(err)
	}

	defer f.Close()

	os.Exit(0)
}
<commit_msg>update copyright year<commit_after>package main

////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2016-2019, Gianluca Fiore
//
////////////////////////////////////////////////////////////////////////////////

import (
	"flag"
	"fmt"
	"os"
	"path"
	"regexp"
	"strconv"
)

var mgntType string
var watchdir string

var usageMessage = `
m2t [-t|-type <type>] [-w|watchdir <directory>] <magnetlink>

M2T (Magnet To Torrent) will convert magnet links to torrent files. It works by using the "watch directory" feature of many torrent clients

Arguments:
	-t|-type <type>
		The type of the file contained in the magnet link. Defaults to "others"

	-w|-watchdir <directory>
		The directory where the torrent client watches for new torrents.
		It must exist. Defaults to '/media/private/torrent/watch
	`

// Parse flags
func init() {

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usageMessage)
	}

	const (
		defWatchdir = "/media/private/torrent/watch"
		defType     = "others"
	)

	flag.StringVar(&mgntType, "type", defType, "")
	flag.StringVar(&mgntType, "t", defType, "")
	flag.StringVar(&watchdir, "watchdir", defWatchdir, "")
	flag.StringVar(&watchdir, "w", defWatchdir, "")

}

func main() {
	var torrentFilename, fileName string

	// initialize cli arguments
	flag.Parse()

	// at least the magnet link is needed, bail out if it was not given
	if flag.NArg() == 0 {
		fmt.Println("No magnet link given, exiting...")
		os.Exit(1)
	}

	// Compose the watch dir's path for the torrent file
	outputDir := path.Join(watchdir, mgntType)
	// Reassign first flag to a variable
	magnetLink := flag.Arg(0)

	// Compile a couple of regexp we need
	var validMagnet = regexp.MustCompile(`xt=urn(\.[0-9]*)?:btih:([^&/]+)`)
	var displayName = regexp.MustCompile(`dn=([^&/]+)`)

	if validMagnet.MatchString(magnetLink) {
		if displayName.MatchString(magnetLink) {
			torrentFilename = displayName.FindString(magnetLink)
			// split at '='
			fileName = regexp.MustCompile(`=`).Split(torrentFilename, -1)[1]
			if len(fileName) == 0 {
				xt := validMagnet.FindString(magnetLink)
				fileName = regexp.MustCompile(`:`).Split(xt, -1)[2]
			}
			// Add torrent extension
			fileName = fileName + ".torrent"
		}
	} else {
		// not a valid magnet URI given
		fmt.Println("The magnet URI is not correct or unparseable")
		os.Exit(1)
	}

	// Create torrent file and output magnet link string to it
	f, err := os.Create(path.Join(outputDir, fileName))
	if err != nil {
		panic(err)
	}
	_, wErr := f.WriteString("d10:magnet-uri" + strconv.Itoa(len(magnetLink)) + ":" + magnetLink + "e")
	if wErr != nil {
		panic(err)
	}

	defer f.Close()

	os.Exit(0)
}
<|endoftext|>


<commit_before>package mumble

import (
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/TF2Stadium/fumble/database"
	"github.com/layeh/gumble/gumble"
)

var ErrChanNotFound = errors.New("channel not found")

func printchannels(c gumble.Channels) {
	for _, channel := range c {
		log.Println(channel.Name)
	}
}

func AddLobbyChannel(l *Conn, lobbyID uint, maxplayers int) {
	name := fmt.Sprintf("Lobby #%d", lobbyID)

	l.wait.Add(1)
	l.client.Do(func() { l.client.Channels[0].Add(name, false) })
	l.wait.Wait()

	l.client.Do(func() {
		channel := l.client.Channels[0].Find(name)
		channel.SetDescription("Mumble channel for TF2Stadium " + name)
		channel.SetMaxUsers(uint32(maxplayers))

		l.wait.Add(2)
		channel.Add("RED", false)
		channel.Add("BLU", false)
	})

	l.wait.Wait()
}

//MoveUsersToRoot moves all users from the RED and BLU channels of the given lobbyID channel
//to the lobby's root channel
func MoveUsersToRoot(conn *Conn, lobbyID uint) error {
	var err error

	conn.client.Do(func() {
		name := fmt.Sprintf("Lobby #%d", lobbyID)
		root := conn.client.Channels[0].Find(name) // root lobby channel
		if root == nil {
			err = ErrChanNotFound
			return
		}

		for _, channel := range root.Children {
			for _, user := range channel.Users {
				user.Move(channel.Parent) // move to root lobby channel, but use channel.Parent
			}

			conn.wait.Add(1)
			channel.Remove()
		}
		return
	})

	conn.wait.Wait()
	return err
}

func getLobbyID(channel *gumble.Channel) uint {
	name := channel.Name
	switch name[0] {
	case 'L': // name is "Lobby #<id>"
		id, _ := strconv.ParseUint(name[strings.Index(name, "#")+1:], 10, 32)
		return uint(id)
	default: // RED or blu
		return getLobbyID(channel.Parent)

	}
}

func isUserAllowed(user *gumble.User, channel *gumble.Channel) bool {
	if channel.IsRoot() {
		return true
	}

	lobbyID := getLobbyID(channel)

	return database.IsAllowed(user.UserID, lobbyID)
}

func (conn Conn) removeEmptyChannels() {
	conn.client.Do(func() {
		for _, c := range conn.client.Channels {
			if len(c.Users) == 0 && !database.IsLobbyClosed(getLobbyID(c)) {
				conn.wait.Add(1)
				c.Remove()
			}
		}
	})

	conn.wait.Wait()
}
<commit_msg>Rename MoveUsersToRoot to MoveUsersToLobbyRoot<commit_after>package mumble

import (
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/TF2Stadium/fumble/database"
	"github.com/layeh/gumble/gumble"
)

var ErrChanNotFound = errors.New("channel not found")

func printchannels(c gumble.Channels) {
	for _, channel := range c {
		log.Println(channel.Name)
	}
}

func AddLobbyChannel(l *Conn, lobbyID uint, maxplayers int) {
	name := fmt.Sprintf("Lobby #%d", lobbyID)

	l.wait.Add(1)
	l.client.Do(func() { l.client.Channels[0].Add(name, false) })
	l.wait.Wait()

	l.client.Do(func() {
		channel := l.client.Channels[0].Find(name)
		channel.SetDescription("Mumble channel for TF2Stadium " + name)
		channel.SetMaxUsers(uint32(maxplayers))

		l.wait.Add(2)
		channel.Add("RED", false)
		channel.Add("BLU", false)
	})

	l.wait.Wait()
}

//MoveUsersToLobbyRoot moves all users from the RED and BLU channels of the given lobbyID channel
//to the lobby's root channel
func MoveUsersToLobbyRoot(conn *Conn, lobbyID uint) error {
	var err error

	conn.client.Do(func() {
		name := fmt.Sprintf("Lobby #%d", lobbyID)
		root := conn.client.Channels[0].Find(name) // root lobby channel
		if root == nil {
			err = ErrChanNotFound
			return
		}

		for _, channel := range root.Children {
			for _, user := range channel.Users {
				user.Move(channel.Parent) // move to root lobby channel, but use channel.Parent
			}

			conn.wait.Add(1)
			channel.Remove()
		}
		return
	})

	conn.wait.Wait()
	return err
}

func getLobbyID(channel *gumble.Channel) uint {
	name := channel.Name
	switch name[0] {
	case 'L': // name is "Lobby #<id>"
		id, _ := strconv.ParseUint(name[strings.Index(name, "#")+1:], 10, 32)
		return uint(id)
	default: // RED or blu
		return getLobbyID(channel.Parent)

	}
}

func isUserAllowed(user *gumble.User, channel *gumble.Channel) bool {
	if channel.IsRoot() {
		return true
	}

	lobbyID := getLobbyID(channel)

	return database.IsAllowed(user.UserID, lobbyID)
}

func (conn Conn) removeEmptyChannels() {
	conn.client.Do(func() {
		for _, c := range conn.client.Channels {
			if len(c.Users) == 0 && !database.IsLobbyClosed(getLobbyID(c)) {
				conn.wait.Add(1)
				c.Remove()
			}
		}
	})

	conn.wait.Wait()
}
<|endoftext|>


<commit_before>package eventsocket

import (
	"bufio"
	"bytes"
	"fmt"
	_ "fmt"
	"net"
	"sync"
	"time"
)

type ServerListener interface {
	OnNewConnection(con *Connection)
}

type ConnectionListener interface {
	OnConnect(con *Connection)
	OnEvent(con *Connection, evt *Event)
	OnDisconnect(con *Connection, msg *Event)
	OnClose(con *Connection)
}

type ServerSettings struct {
	Address  string
	Listener ServerListener
}

type Connection struct {
	//server specific
	Server *Server

	//client specific
	Reconnects  int
	ChannelData ESLkv
	Connected   bool

	//generic
	Listener ConnectionListener
	eslCon   net.Conn
	rw       *bufio.ReadWriter
	lock     sync.Mutex
	apiChan  chan *Event
}

type Server struct {
	Settings    ServerSettings
	NetListener net.Listener
	EvListener  ServerListener
}

/* Connection */

func (con *Connection) Send(cmd string, args ...string) (*Event, error) {
	bbuf := bytes.NewBufferString(cmd)
	for _, item := range args {
		bbuf.WriteString(" ")
		bbuf.WriteString(item)
	}
	bbuf.Write(doubleLine)

	//all commands block until FS replies
	con.lock.Lock()
	defer con.lock.Unlock()

	sendBytes(con.rw, bbuf.Bytes())
	evt := <-con.apiChan

	return evt, nil
}

func (con *Connection) Event(cmd string, headers map[string]string, body []byte) (*Event, error) {
	bbuf := bytes.NewBufferString("sendevent ")
	bbuf.WriteString(cmd)
	bbuf.Write(singleLine)

	for k, v := range headers {
		bbuf.WriteString(k)
		bbuf.WriteString(": ")
		bbuf.WriteString(v)
		bbuf.Write(singleLine)
	}

	ll := len(body)
	lf := fmt.Sprintf("content-length: %d%s", ll, doubleLine)
	bbuf.WriteString(lf)

	bbuf.Write(body)

	//all commands block until FS replies
	con.lock.Lock()
	defer con.lock.Unlock()

	sendBytes(con.rw, bbuf.Bytes())
	evt := <-con.apiChan

	return evt, nil
}

func (con *Connection) Execute(cmd *Command) (*Event, error) {
	con.lock.Lock()
	defer con.lock.Unlock()

	sendBytes(con.rw, cmd.GetExecute())
	evt := <-con.apiChan

	return evt, nil
}
func (con *Connection) tryConnect(client *Client) bool {
	var err error
	con.eslCon, err = net.DialTimeout("tcp", client.Settings.Address, client.Settings.Timeout)

	if err != nil {
		return false
	}

	con.rw = bufio.NewReadWriter(
		bufio.NewReaderSize(con.eslCon, BufferSize),
		bufio.NewWriter(con.eslCon))

	auth := readMessage(con.rw)
	if auth.Type != EventAuth {
		con.eslCon.Close()
		return false
	}

	pwBuf := bytes.NewBufferString("auth ")
	pwBuf.WriteString(client.Settings.Password)
	pwBuf.Write(doubleLine)
	con.eslCon.Write(pwBuf.Bytes())
	err = con.rw.Flush()

	if err != nil {
		con.eslCon.Close()
		return false
	}

	authResp := readMessage(con.rw)

	if authResp.Type != EventReply || !authResp.Success {
		con.eslCon.Close()
		return false
	}

	con.Connected = true
	con.Reconnects += 1
	return true
}

func (con *Connection) Close() {
	con.Connected = false
	con.Listener.OnClose(con)
	con.eslCon.Close()
}

func (con *Connection) setupConnect() bool {
	//authenticate socket
	cBuf := bytes.NewBufferString("connect")
	cBuf.Write(doubleLine)
	con.rw.Write(cBuf.Bytes())
	err := con.rw.Flush()

	if err != nil {
		con.eslCon.Close()
		return false
	}

	channelData := readMessage(con.rw)

	if channelData.Type != EventReply {
		con.eslCon.Close()
		return false
	}

	con.ChannelData = channelData.Headers
	con.Connected = true
	return true
}

func (con *Connection) Loop() {
	//spin this on a separate goroutine so we can start handling api events
	//people will likely subscribe to events here
	go con.Listener.OnConnect(con)
	for con.Connected {
		message := readMessage(con.rw)

		switch message.Type {
		case EventError:
			//disconnect
			con.Close()
		case EventDisconnect:
			//disconnect
			con.Connected = false
			con.Listener.OnDisconnect(con, message)
		case EventReply, EventApi:
			con.apiChan <- message
		case EventGeneric:
			con.Listener.OnEvent(con, message)
		}

	}
}

/* Server */

func CreateServer(settings ServerSettings) (*Server, error) {
	var err error
	retServer := new(Server)
	retServer.Settings = settings
	retServer.EvListener = settings.Listener
	//bind and go listen for clients
	retServer.NetListener, err = net.Listen("tcp", retServer.Settings.Address)
	if err != nil {
		return nil, err
	}
	return retServer, nil
}
func (server *Server) Loop() {
	for {
		conn, err := server.NetListener.Accept()
		if err != nil {
			//what to do here?
			return
		}
		scon := new(Connection)
		scon.apiChan = make(chan *Event)
		scon.Server = server
		scon.eslCon = conn
		scon.rw = bufio.NewReadWriter(
			bufio.NewReaderSize(scon.eslCon, BufferSize),
			bufio.NewWriter(scon.eslCon))
		if scon.setupConnect() {
			server.EvListener.OnNewConnection(scon)
		}
	}
}

/* CLIENT */

type ClientSettings struct {
	Address  string
	Timeout  time.Duration
	Password string
	Listener ConnectionListener
}
type Client struct {
	Settings   ClientSettings
	Connected  bool
	Connection Connection
}

func CreateClient(settings ClientSettings) (*Client, error) {
	retClient := new(Client)
	retClient.Settings = settings
	retClient.Connection.Listener = settings.Listener
	retClient.Connection.apiChan = make(chan *Event)
	return retClient, nil
}

func (client *Client) Loop() {
	for {
		if !client.Connected {
			client.Connected = client.Connection.tryConnect(client)
			if !client.Connected {
				time.Sleep(client.Settings.Timeout)
			}
			continue
		}
		client.Connection.Loop()
		client.Connected = false
	}
}
<commit_msg>linger wasnt working as disconnect event triggered first<commit_after>package eventsocket

import (
	"bufio"
	"bytes"
	"fmt"
	_ "fmt"
	"net"
	"sync"
	"time"
)

type ServerListener interface {
	OnNewConnection(con *Connection)
}

type ConnectionListener interface {
	OnConnect(con *Connection)
	OnEvent(con *Connection, evt *Event)
	OnDisconnect(con *Connection, msg *Event)
	OnClose(con *Connection)
}

type ServerSettings struct {
	Address  string
	Listener ServerListener
}

type Connection struct {
	//server specific
	Server *Server

	//client specific
	Reconnects  int
	ChannelData ESLkv
	Connected   bool

	//generic
	Listener ConnectionListener
	eslCon   net.Conn
	rw       *bufio.ReadWriter
	lock     sync.Mutex
	apiChan  chan *Event
}

type Server struct {
	Settings    ServerSettings
	NetListener net.Listener
	EvListener  ServerListener
}

/* Connection */

func (con *Connection) Send(cmd string, args ...string) (*Event, error) {
	bbuf := bytes.NewBufferString(cmd)
	for _, item := range args {
		bbuf.WriteString(" ")
		bbuf.WriteString(item)
	}
	bbuf.Write(doubleLine)

	//all commands block until FS replies
	con.lock.Lock()
	defer con.lock.Unlock()

	sendBytes(con.rw, bbuf.Bytes())
	evt := <-con.apiChan

	return evt, nil
}

func (con *Connection) Event(cmd string, headers map[string]string, body []byte) (*Event, error) {
	bbuf := bytes.NewBufferString("sendevent ")
	bbuf.WriteString(cmd)
	bbuf.Write(singleLine)

	for k, v := range headers {
		bbuf.WriteString(k)
		bbuf.WriteString(": ")
		bbuf.WriteString(v)
		bbuf.Write(singleLine)
	}

	ll := len(body)
	lf := fmt.Sprintf("content-length: %d%s", ll, doubleLine)
	bbuf.WriteString(lf)

	bbuf.Write(body)

	//all commands block until FS replies
	con.lock.Lock()
	defer con.lock.Unlock()

	sendBytes(con.rw, bbuf.Bytes())
	evt := <-con.apiChan

	return evt, nil
}

func (con *Connection) Execute(cmd *Command) (*Event, error) {
	con.lock.Lock()
	defer con.lock.Unlock()

	sendBytes(con.rw, cmd.GetExecute())
	evt := <-con.apiChan

	return evt, nil
}
func (con *Connection) tryConnect(client *Client) bool {
	var err error
	con.eslCon, err = net.DialTimeout("tcp", client.Settings.Address, client.Settings.Timeout)

	if err != nil {
		return false
	}

	con.rw = bufio.NewReadWriter(
		bufio.NewReaderSize(con.eslCon, BufferSize),
		bufio.NewWriter(con.eslCon))

	auth := readMessage(con.rw)
	if auth.Type != EventAuth {
		con.eslCon.Close()
		return false
	}

	pwBuf := bytes.NewBufferString("auth ")
	pwBuf.WriteString(client.Settings.Password)
	pwBuf.Write(doubleLine)
	con.eslCon.Write(pwBuf.Bytes())
	err = con.rw.Flush()

	if err != nil {
		con.eslCon.Close()
		return false
	}

	authResp := readMessage(con.rw)

	if authResp.Type != EventReply || !authResp.Success {
		con.eslCon.Close()
		return false
	}

	con.Connected = true
	con.Reconnects += 1
	return true
}

func (con *Connection) Close() {
	con.Connected = false
	con.Listener.OnClose(con)
	con.eslCon.Close()
}

func (con *Connection) setupConnect() bool {
	//authenticate socket
	cBuf := bytes.NewBufferString("connect")
	cBuf.Write(doubleLine)
	con.rw.Write(cBuf.Bytes())
	err := con.rw.Flush()

	if err != nil {
		con.eslCon.Close()
		return false
	}

	channelData := readMessage(con.rw)

	if channelData.Type != EventReply {
		con.eslCon.Close()
		return false
	}

	con.ChannelData = channelData.Headers
	con.Connected = true
	return true
}

func (con *Connection) Loop() {
	//spin this on a separate goroutine so we can start handling api events
	//people will likely subscribe to events here
	go con.Listener.OnConnect(con)
	for con.Connected {
		message := readMessage(con.rw)

		switch message.Type {
		case EventError:
			//disconnect
			con.Close()
		case EventDisconnect:
			//disconnect
			con.Listener.OnDisconnect(con, message)
		case EventReply, EventApi:
			con.apiChan <- message
		case EventGeneric:
			con.Listener.OnEvent(con, message)
		}

	}
}

/* Server */

func CreateServer(settings ServerSettings) (*Server, error) {
	var err error
	retServer := new(Server)
	retServer.Settings = settings
	retServer.EvListener = settings.Listener
	//bind and go listen for clients
	retServer.NetListener, err = net.Listen("tcp", retServer.Settings.Address)
	if err != nil {
		return nil, err
	}
	return retServer, nil
}
func (server *Server) Loop() {
	for {
		conn, err := server.NetListener.Accept()
		if err != nil {
			//what to do here?
			return
		}
		scon := new(Connection)
		scon.apiChan = make(chan *Event)
		scon.Server = server
		scon.eslCon = conn
		scon.rw = bufio.NewReadWriter(
			bufio.NewReaderSize(scon.eslCon, BufferSize),
			bufio.NewWriter(scon.eslCon))
		if scon.setupConnect() {
			server.EvListener.OnNewConnection(scon)
		}
	}
}

/* CLIENT */

type ClientSettings struct {
	Address  string
	Timeout  time.Duration
	Password string
	Listener ConnectionListener
}
type Client struct {
	Settings   ClientSettings
	Connected  bool
	Connection Connection
}

func CreateClient(settings ClientSettings) (*Client, error) {
	retClient := new(Client)
	retClient.Settings = settings
	retClient.Connection.Listener = settings.Listener
	retClient.Connection.apiChan = make(chan *Event)
	return retClient, nil
}

func (client *Client) Loop() {
	for {
		if !client.Connected {
			client.Connected = client.Connection.tryConnect(client)
			if !client.Connected {
				time.Sleep(client.Settings.Timeout)
			}
			continue
		}
		client.Connection.Loop()
		client.Connected = false
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
)

const (
	NONE  = 0
	DUP   = 1
	PRINT = 2
	POP   = 3
	SWAP  = 4
	ZERO  = 5
)

func main() {
	ind := ZERO
	for ; ind == ZERO; {
		ind, _, _ = run(false, 0)
	}
	fmt.Println("Invalid entry: bottom of stack reached")
	os.Exit(1)
}

/*
	push indicates whether to push the passed value onto the stack or
	to wait for user input.

	Returns an operator indicator. This indicator can have values
	NONE, DUP, or PRINT

	NONE:
		The operator entered was a normal arithmetic operator

	DUP:
		The operator entered was the duplicate operator

	PRINT:
		The operator entered was the print operator

	POP:
		The operator entered was the pop operator

	SWAP:
		The operator entered was the swap operator

	ZERO:
		The operator entered was the zero operator

	If the indicator is equal to NONE, then one of the two returned
	functions will be the function corresponding to the operator entered.

*/
func run(push bool, n int) (int, unop, binop) {

	var s string
	var uo unop
	var bo binop

	// Operator indicator
	var ind int

	// If the duplicate operator was entered, then n
	// is already the equal to the value which should
	// be pushed onto the stack.
	if !push {
		for {
			fmt.Scan(&s)
			_, err := fmt.Sscanf(s, "%d", &n)

			// If it was not a number (ie, an operator)
			if err != nil {
				switch s {
				case "+":
					return NONE, nil, add
				case "-":
					return NONE, nil, subtract
				case "*":
					return NONE, nil, multiply
				case "/":
					return NONE, nil, divide
				case "|":
					return NONE, nil, or
				case "&":
					return NONE, nil, and
				case "c":
					return NONE, negate, nil
				case "~":
					return NONE, not, nil
				case "dup":
					return DUP, nil, nil
				case "print":
					return PRINT, nil, nil
				case "pop":
					return POP, nil, nil
				case "swap":
					return SWAP, nil, swap
				case "zero":
					return ZERO, nil, nil
				case "quit":
					os.Exit(0)
				}
				fmt.Printf("Unrecognized command: %s\n", s)
			} else {
				break
			}
		}
	}

	// Once control reaches this part of the function,
	// n is equal to the value on the top of the stack.

	push = false

	for {
		ind, uo, bo = run(push, n)

		TOP:

		push = false

		switch ind {
		case NONE:
			if uo != nil {
				n = uo(n)
			} else {
				return NONE, bo(n), nil
			}
		case DUP:
			// Simply set push to true, since on next iteration of loop,
			// run(push, n) will be called, and n is already the correct value
			push = true
		case PRINT:
			fmt.Println(n)
		case POP:
			// Effectively letting the previous instance of run perform the call,
			// but way easier than having to pass back sentinal values, etc
			return run(false, 0)
		case SWAP:
			if uo == nil {
				// bo will return a function which, when given an argument,
				// will discard the argument and simply return this n
				return SWAP, bo(n), nil
			} else {
				// uo will discard its argument and return the argument which
				// was passed in the previous call
				m := uo(0)
				ind, uo, bo = run(true, n)
				n = m

				// Necessary to avoid double-calling run
				goto TOP;
			}
		case ZERO:
			return ZERO, nil, nil
		}
	}

	// Control should never reach this
	return NONE, nil, nil
}
<commit_msg>Added command line indicator, "> "<commit_after>package main

import (
	"fmt"
	"os"
)

const (
	NONE  = 0
	DUP   = 1
	PRINT = 2
	POP   = 3
	SWAP  = 4
	ZERO  = 5
)

func main() {
	for {
		ind := ZERO
		for ; ind == ZERO; {
			fmt.Print("> ")
			ind, _, _ = run(false, 0)
		}
		fmt.Println("Invalid entry: bottom of stack reached")
	}
}

/*
	push indicates whether to push the passed value onto the stack or
	to wait for user input.

	Returns an operator indicator. This indicator can have values
	NONE, DUP, or PRINT

	NONE:
		The operator entered was a normal arithmetic operator

	DUP:
		The operator entered was the duplicate operator

	PRINT:
		The operator entered was the print operator

	POP:
		The operator entered was the pop operator

	SWAP:
		The operator entered was the swap operator

	ZERO:
		The operator entered was the zero operator

	If the indicator is equal to NONE, then one of the two returned
	functions will be the function corresponding to the operator entered.

*/
func run(push bool, n int) (int, unop, binop) {

	var s string
	var uo unop
	var bo binop

	// Operator indicator
	var ind int

	// If the duplicate operator was entered, then n
	// is already the equal to the value which should
	// be pushed onto the stack.
	if !push {
		for {
			fmt.Scan(&s)
			_, err := fmt.Sscanf(s, "%d", &n)

			// If it was not a number (ie, an operator)
			if err != nil {
				switch s {
				case "+":
					return NONE, nil, add
				case "-":
					return NONE, nil, subtract
				case "*":
					return NONE, nil, multiply
				case "/":
					return NONE, nil, divide
				case "|":
					return NONE, nil, or
				case "&":
					return NONE, nil, and
				case "c":
					return NONE, negate, nil
				case "~":
					return NONE, not, nil
				case "dup":
					return DUP, nil, nil
				case "print":
					return PRINT, nil, nil
				case "pop":
					return POP, nil, nil
				case "swap":
					return SWAP, nil, swap
				case "zero":
					return ZERO, nil, nil
				case "quit":
					os.Exit(0)
				}
				fmt.Printf("Unrecognized command: %s\n", s)
				fmt.Print("> ")
			} else {
				break
			}
		}
	}

	// Once control reaches this part of the function,
	// n is equal to the value on the top of the stack.

	push = false

	for {
		ind, uo, bo = run(push, n)

		TOP:

		push = false

		switch ind {
		case NONE:
			if uo != nil {
				n = uo(n)
			} else {
				return NONE, bo(n), nil
			}
		case DUP:
			// Simply set push to true, since on next iteration of loop,
			// run(push, n) will be called, and n is already the correct value
			push = true
		case PRINT:
			fmt.Println(n)
			fmt.Print("> ")
		case POP:
			// Effectively letting the previous instance of run perform the call,
			// but way easier than having to pass back sentinal values, etc
			return run(false, 0)
		case SWAP:
			if uo == nil {
				// bo will return a function which, when given an argument,
				// will discard the argument and simply return this n
				return SWAP, bo(n), nil
			} else {
				// uo will discard its argument and return the argument which
				// was passed in the previous call
				m := uo(0)
				ind, uo, bo = run(true, n)
				n = m

				// Necessary to avoid double-calling run
				goto TOP;
			}
		case ZERO:
			return ZERO, nil, nil
		}
	}

	// Control should never reach this
	return NONE, nil, nil
}
<|endoftext|>


<commit_before>package buffalo

import (
	"encoding/json"
	"encoding/xml"
	"net/http"
	"sync"
	"time"

	"github.com/monoculum/formam"
	"github.com/pkg/errors"
)

var binderLock = &sync.Mutex{}
var binders = map[string]BinderFunc{}
var decoder *formam.Decoder

var timeLayouts = []string{
	"2006-01-02T15:04:05Z07:00",
}

// BinderFunc takes a request and binds it to an interface.
// If there is a problem it should return an error.
type BinderFunc func(*http.Request, interface{}) error

// RegisterBinder maps a request Content-Type (application/json)
// to a BinderFunc.
func RegisterBinder(contentType string, fn BinderFunc) {
	binderLock.Lock()
	defer binderLock.Unlock()
	binders[contentType] = fn
}

// RegisterTimeLayout allows to add custom time layouts that
// the binder will be able to use for decoding.
func RegisterTimeLayout(layout string) {
	timeLayouts = append(timeLayouts, layout)
}

// RegisterCustomTypeDecoder
func RegisterBinderTypeDecoder(fn formam.DecodeCustomTypeFunc, types []interface{}, fields []interface{}) {
	decoder.RegisterCustomType(fn, types, fields)
}

func init() {
	decoder = formam.NewDecoder(&formam.DecoderOptions{
		TagName:           "schema",
		IgnoreUnknownKeys: true,
	})

	decoder.RegisterCustomType(func(vals []string) (interface{}, error) {
		var t time.Time
		var err error

		for _, layout := range timeLayouts {
			t, er := time.Parse(layout, vals[0])
			if er == nil {
				return t, er
			}

			err = er
		}

		return t, err
	}, []interface{}{time.Time{}}, nil)

	sb := func(req *http.Request, i interface{}) error {
		err := req.ParseForm()
		if err != nil {
			return errors.WithStack(err)
		}

		if err := decoder.Decode(req.Form, i); err != nil {
			return errors.WithStack(err)
		}
		return nil
	}

	binders["application/html"] = sb
	binders["text/html"] = sb
	binders["application/x-www-form-urlencoded"] = sb
	binders["multipart/form-data"] = sb
}

func init() {
	jb := func(req *http.Request, value interface{}) error {
		return json.NewDecoder(req.Body).Decode(value)
	}
	binders["application/json"] = jb
	binders["text/json"] = jb
	binders["json"] = jb
}

func init() {
	xb := func(req *http.Request, value interface{}) error {
		return xml.NewDecoder(req.Body).Decode(value)
	}
	binders["application/xml"] = xb
	binders["text/xml"] = xb
	binders["xml"] = xb
}
<commit_msg>fixing lint issue<commit_after>package buffalo

import (
	"encoding/json"
	"encoding/xml"
	"net/http"
	"sync"
	"time"

	"github.com/monoculum/formam"
	"github.com/pkg/errors"
)

var binderLock = &sync.Mutex{}
var binders = map[string]BinderFunc{}
var decoder *formam.Decoder

var timeLayouts = []string{
	"2006-01-02T15:04:05Z07:00",
}

// BinderFunc takes a request and binds it to an interface.
// If there is a problem it should return an error.
type BinderFunc func(*http.Request, interface{}) error

// RegisterBinder maps a request Content-Type (application/json)
// to a BinderFunc.
func RegisterBinder(contentType string, fn BinderFunc) {
	binderLock.Lock()
	defer binderLock.Unlock()
	binders[contentType] = fn
}

// RegisterTimeLayout allows to add custom time layouts that
// the binder will be able to use for decoding.
func RegisterTimeLayout(layout string) {
	timeLayouts = append(timeLayouts, layout)
}

// RegisterBinderTypeDecoder allows to define custom type decoders.
func RegisterBinderTypeDecoder(fn formam.DecodeCustomTypeFunc, types []interface{}, fields []interface{}) {
	decoder.RegisterCustomType(fn, types, fields)
}

func init() {
	decoder = formam.NewDecoder(&formam.DecoderOptions{
		TagName:           "schema",
		IgnoreUnknownKeys: true,
	})

	decoder.RegisterCustomType(func(vals []string) (interface{}, error) {
		var t time.Time
		var err error

		for _, layout := range timeLayouts {
			t, er := time.Parse(layout, vals[0])
			if er == nil {
				return t, er
			}

			err = er
		}

		return t, err
	}, []interface{}{time.Time{}}, nil)

	sb := func(req *http.Request, i interface{}) error {
		err := req.ParseForm()
		if err != nil {
			return errors.WithStack(err)
		}

		if err := decoder.Decode(req.Form, i); err != nil {
			return errors.WithStack(err)
		}
		return nil
	}

	binders["application/html"] = sb
	binders["text/html"] = sb
	binders["application/x-www-form-urlencoded"] = sb
	binders["multipart/form-data"] = sb
}

func init() {
	jb := func(req *http.Request, value interface{}) error {
		return json.NewDecoder(req.Body).Decode(value)
	}
	binders["application/json"] = jb
	binders["text/json"] = jb
	binders["json"] = jb
}

func init() {
	xb := func(req *http.Request, value interface{}) error {
		return xml.NewDecoder(req.Body).Decode(value)
	}
	binders["application/xml"] = xb
	binders["text/xml"] = xb
	binders["xml"] = xb
}
<|endoftext|>


<commit_before>// Package bittrex is an implementation of the Biitrex API (public and private).
package bittrex

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
)

const (
	API_BASE                   = "https://bittrex.com/api/" // Bittrex API endpoint
	API_VERSION                = "v1.1"                     // Bittrex API version
	DEFAULT_HTTPCLIENT_TIMEOUT = 30                         // HTTP client timeout
)

// New return a instanciate bittrex struct
func New(apiKey, apiSecret string) *Bittrex {
	client := NewClient(apiKey, apiSecret)
	return &bittrex{client}
}

// handleErr gets JSON response from Bittrex API en deal with error
func handleErr(r jsonResponse) error {
	if !r.Success {
		return errors.New(r.Message)
	}
	return nil
}

// bittrex represent a bittrex client
type Bittrex struct {
	client *client
}

// GetMarkets is used to get the open and available trading markets at Bittrex along with other meta data.
func (b *bittrex) GetMarkets() (markets []Market, err error) {
	r, err := b.client.do("GET", "public/getmarkets", "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &markets)
	return
}

// GetTicker is used to get the current ticker values for a market.
func (b *bittrex) GetTicker(market string) (ticker Ticker, err error) {
	r, err := b.client.do("GET", "public/getticker?market="+strings.ToUpper(market), "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &ticker)
	return
}

// GetMarketSummaries is used to get the last 24 hour summary of all active exchanges
func (b *bittrex) GetMarketSummaries() (marketSummaries []MarketSummary, err error) {
	r, err := b.client.do("GET", "public/getmarketsummaries", "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &marketSummaries)
	return
}

// GetOrderBook is used to get retrieve the orderbook for a given market
// market: a string literal for the market (ex: BTC-LTC)
// cat: buy, sell or both to identify the type of orderbook to return.
// depth: how deep of an order book to retrieve. Max is 100
func (b *bittrex) GetOrderBook(market, cat string, depth int) (orderBook OrderBook, err error) {
	if cat != "buy" && cat != "sell" && cat != "both" {
		cat = "both"
	}
	if depth > 100 {
		depth = 100
	}
	if depth < 1 {
		depth = 1
	}
	r, err := b.client.do("GET", fmt.Sprintf("public/getorderbook?market=%s&type=%s&depth=%d", strings.ToUpper(market), cat, depth), "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &orderBook)
	return
}

// GetMarketHistory is used to retrieve the latest trades that have occured for a specific market.
// mark a string literal for the market (ex: BTC-LTC)
// count a number between 1-100 for the number of entries to return
func (b *bittrex) GetMarketHistory(market string, count int) (trades []Trade, err error) {
	if count > 100 {
		count = 100
	}
	if count < 1 {
		count = 1
	}
	r, err := b.client.do("GET", fmt.Sprintf("public/getmarkethistory?market=%s&count=%d", strings.ToUpper(market), count), "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &trades)
	return
}

// Market

// BuyLimit is used to place a limited buy order in a specific market.
func (b *bittrex) BuyLimit(market string, quantity, rate float64) (uuid string, err error) {
	r, err := b.client.do("GET", "market/buylimit?market="+market+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64)+"&rate="+strconv.FormatFloat(rate, 'f', 8, 64), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	uuid = u.Id
	return
}

// BuyMarket is used to place a market buy order in a spacific market.
func (b *bittrex) BuyMarket(market string, quantity float64) (uuid string, err error) {
	r, err := b.client.do("GET", "market/buymarket?market="+market+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	uuid = u.Id
	return
}

// SellLimit is used to place a limited sell order in a specific market.
func (b *bittrex) SellLimit(market string, quantity, rate float64) (uuid string, err error) {
	r, err := b.client.do("GET", "market/selllimit?market="+market+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64)+"&rate="+strconv.FormatFloat(rate, 'f', 8, 64), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	uuid = u.Id
	return
}

// SellMarket is used to place a market sell order in a specific market.
func (b *bittrex) SellMarket(market string, quantity float64) (uuid string, err error) {
	r, err := b.client.do("GET", "market/selllimit?market="+market+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	uuid = u.Id
	return
}

// CancelOrder is used to cancel a buy or sell order.
func (b *bittrex) CancelOrder(orderID string) (err error) {
	r, err := b.client.do("GET", "market/cancel?uuid="+orderID, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	err = handleErr(response)
	return
}

// GetOpenOrders returns orders that you currently have opened.
// If market is set to "all", GetOpenOrders return all orders
// If market is set to a specific order, GetOpenOrders return orders for this market
func (b *bittrex) GetOpenOrders(market string) (openOrders []Order, err error) {
	ressource := "market/getopenorders"
	if market != "all" {
		ressource += "?market=" + strings.ToUpper(market)
	}
	r, err := b.client.do("GET", ressource, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &openOrders)
	return
}

// Account

// GetBalances is used to retrieve all balances from your account
func (b *bittrex) GetBalances() (balances map[string]Balance, err error) {
	r, err := b.client.do("GET", "account/getbalances", "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &balances)
	return
}

// Getbalance is used to retrieve the balance from your account for a specific currency.
// currency: a string literal for the currency (ex: LTC)
func (b *bittrex) GetBalance(currency string) (balance Balance, err error) {
	r, err := b.client.do("GET", "account/getbalance?currency="+strings.ToUpper(currency), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &balance)
	return
}

// GetDepositAddress is sed to generate or retrieve an address for a specific currency.
// currency a string literal for the currency (ie. BTC)
func (b *bittrex) GetDepositAddress(currency string) (address Address, err error) {
	r, err := b.client.do("GET", "account/getdepositaddress?currency="+strings.ToUpper(currency), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &address)
	return
}

// Withdraw is used to withdraw funds from your account.
// address string the address where to send the funds.
// currency string literal for the currency (ie. BTC)
// quantity float the quantity of coins to withdraw
func (b *bittrex) Withdraw(address, currency string, quantity float64) (withdrawUuid string, err error) {
	r, err := b.client.do("GET", "account/withdraw?currency="+strings.ToUpper(currency)+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64)+"&address="+address, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	withdrawUuid = u.Id
	return
}

// GetOrderHistory used to retrieve your order history.
// market string literal for the market (ie. BTC-LTC). If set to "all", will return for all market
// count int : 	the number of records to return. Is set to 0, will return max history
func (b *bittrex) GetOrderHistory(market string, count int) (orders []Order, err error) {
	ressource := "account/getorderhistory"
	if count != 0 || market != "all" {
		ressource += "?"
	}
	if count != 0 {
		ressource += fmt.Sprintf("count=%d&", count)
	}
	if market != "all" {
		ressource += "market=" + market
	}
	r, err := b.client.do("GET", ressource, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &orders)
	return
}

// GetWithdrawalHistory is used to retrieve your withdrawal history
// currency string a string literal for the currency (ie. BTC). If set to "all", will return for all currencies
// count int the number of records to return. Is set to 0 will return the max set.
func (b *bittrex) GetWithdrawalHistory(currency string, count int) (withdrawals []Withdrawal, err error) {
	ressource := "account/getwithdrawalhistory"
	if count != 0 || currency != "all" {
		ressource += "?"
	}
	if count != 0 {
		ressource += fmt.Sprintf("count=%d&", count)
	}
	if currency != "all" {
		ressource += "currency=" + currency
	}
	r, err := b.client.do("GET", ressource, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &withdrawals)
	return
}

// GetDepositHistory is used to retrieve your deposit history
// currency string a string literal for the currency (ie. BTC). If set to "all", will return for all currencies
// count int the number of records to return. Is set to 0 will return the max set.
func (b *bittrex) GetDepositHistory(currency string, count int) (deposits []Deposit, err error) {
	ressource := "account/getdeposithistory"
	if count != 0 || currency != "all" {
		ressource += "?"
	}
	if count != 0 {
		ressource += fmt.Sprintf("count=%d&", count)
	}
	if currency != "all" {
		ressource += "currency=" + currency
	}
	r, err := b.client.do("GET", ressource, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &deposits)
	return
}
<commit_msg>Typo<commit_after>// Package Bittrex is an implementation of the Biitrex API (public and private).
package bittrex

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
)

const (
	API_BASE                   = "https://bittrex.com/api/" // Bittrex API endpoint
	API_VERSION                = "v1.1"                     // Bittrex API version
	DEFAULT_HTTPCLIENT_TIMEOUT = 30                         // HTTP client timeout
)

// New return a instanciate bittrex struct
func New(apiKey, apiSecret string) *Bittrex {
	client := NewClient(apiKey, apiSecret)
	return &bittrex{client}
}

// handleErr gets JSON response from Bittrex API en deal with error
func handleErr(r jsonResponse) error {
	if !r.Success {
		return errors.New(r.Message)
	}
	return nil
}

// bittrex represent a bittrex client
type Bittrex struct {
	client *client
}

// GetMarkets is used to get the open and available trading markets at Bittrex along with other meta data.
func (b *Bittrex) GetMarkets() (markets []Market, err error) {
	r, err := b.client.do("GET", "public/getmarkets", "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &markets)
	return
}

// GetTicker is used to get the current ticker values for a market.
func (b *Bittrex) GetTicker(market string) (ticker Ticker, err error) {
	r, err := b.client.do("GET", "public/getticker?market="+strings.ToUpper(market), "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &ticker)
	return
}

// GetMarketSummaries is used to get the last 24 hour summary of all active exchanges
func (b *Bittrex) GetMarketSummaries() (marketSummaries []MarketSummary, err error) {
	r, err := b.client.do("GET", "public/getmarketsummaries", "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &marketSummaries)
	return
}

// GetOrderBook is used to get retrieve the orderbook for a given market
// market: a string literal for the market (ex: BTC-LTC)
// cat: buy, sell or both to identify the type of orderbook to return.
// depth: how deep of an order book to retrieve. Max is 100
func (b *Bittrex) GetOrderBook(market, cat string, depth int) (orderBook OrderBook, err error) {
	if cat != "buy" && cat != "sell" && cat != "both" {
		cat = "both"
	}
	if depth > 100 {
		depth = 100
	}
	if depth < 1 {
		depth = 1
	}
	r, err := b.client.do("GET", fmt.Sprintf("public/getorderbook?market=%s&type=%s&depth=%d", strings.ToUpper(market), cat, depth), "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &orderBook)
	return
}

// GetMarketHistory is used to retrieve the latest trades that have occured for a specific market.
// mark a string literal for the market (ex: BTC-LTC)
// count a number between 1-100 for the number of entries to return
func (b *Bittrex) GetMarketHistory(market string, count int) (trades []Trade, err error) {
	if count > 100 {
		count = 100
	}
	if count < 1 {
		count = 1
	}
	r, err := b.client.do("GET", fmt.Sprintf("public/getmarkethistory?market=%s&count=%d", strings.ToUpper(market), count), "", false)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &trades)
	return
}

// Market

// BuyLimit is used to place a limited buy order in a specific market.
func (b *Bittrex) BuyLimit(market string, quantity, rate float64) (uuid string, err error) {
	r, err := b.client.do("GET", "market/buylimit?market="+market+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64)+"&rate="+strconv.FormatFloat(rate, 'f', 8, 64), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	uuid = u.Id
	return
}

// BuyMarket is used to place a market buy order in a spacific market.
func (b *Bittrex) BuyMarket(market string, quantity float64) (uuid string, err error) {
	r, err := b.client.do("GET", "market/buymarket?market="+market+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	uuid = u.Id
	return
}

// SellLimit is used to place a limited sell order in a specific market.
func (b *Bittrex) SellLimit(market string, quantity, rate float64) (uuid string, err error) {
	r, err := b.client.do("GET", "market/selllimit?market="+market+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64)+"&rate="+strconv.FormatFloat(rate, 'f', 8, 64), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	uuid = u.Id
	return
}

// SellMarket is used to place a market sell order in a specific market.
func (b *Bittrex) SellMarket(market string, quantity float64) (uuid string, err error) {
	r, err := b.client.do("GET", "market/selllimit?market="+market+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	uuid = u.Id
	return
}

// CancelOrder is used to cancel a buy or sell order.
func (b *Bittrex) CancelOrder(orderID string) (err error) {
	r, err := b.client.do("GET", "market/cancel?uuid="+orderID, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	err = handleErr(response)
	return
}

// GetOpenOrders returns orders that you currently have opened.
// If market is set to "all", GetOpenOrders return all orders
// If market is set to a specific order, GetOpenOrders return orders for this market
func (b *Bittrex) GetOpenOrders(market string) (openOrders []Order, err error) {
	ressource := "market/getopenorders"
	if market != "all" {
		ressource += "?market=" + strings.ToUpper(market)
	}
	r, err := b.client.do("GET", ressource, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &openOrders)
	return
}

// Account

// GetBalances is used to retrieve all balances from your account
func (b *Bittrex) GetBalances() (balances map[string]Balance, err error) {
	r, err := b.client.do("GET", "account/getbalances", "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &balances)
	return
}

// Getbalance is used to retrieve the balance from your account for a specific currency.
// currency: a string literal for the currency (ex: LTC)
func (b *Bittrex) GetBalance(currency string) (balance Balance, err error) {
	r, err := b.client.do("GET", "account/getbalance?currency="+strings.ToUpper(currency), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &balance)
	return
}

// GetDepositAddress is sed to generate or retrieve an address for a specific currency.
// currency a string literal for the currency (ie. BTC)
func (b *Bittrex) GetDepositAddress(currency string) (address Address, err error) {
	r, err := b.client.do("GET", "account/getdepositaddress?currency="+strings.ToUpper(currency), "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &address)
	return
}

// Withdraw is used to withdraw funds from your account.
// address string the address where to send the funds.
// currency string literal for the currency (ie. BTC)
// quantity float the quantity of coins to withdraw
func (b *Bittrex) Withdraw(address, currency string, quantity float64) (withdrawUuid string, err error) {
	r, err := b.client.do("GET", "account/withdraw?currency="+strings.ToUpper(currency)+"&quantity="+strconv.FormatFloat(quantity, 'f', 8, 64)+"&address="+address, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	var u Uuid
	err = json.Unmarshal(response.Result, &u)
	withdrawUuid = u.Id
	return
}

// GetOrderHistory used to retrieve your order history.
// market string literal for the market (ie. BTC-LTC). If set to "all", will return for all market
// count int : 	the number of records to return. Is set to 0, will return max history
func (b *Bittrex) GetOrderHistory(market string, count int) (orders []Order, err error) {
	ressource := "account/getorderhistory"
	if count != 0 || market != "all" {
		ressource += "?"
	}
	if count != 0 {
		ressource += fmt.Sprintf("count=%d&", count)
	}
	if market != "all" {
		ressource += "market=" + market
	}
	r, err := b.client.do("GET", ressource, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &orders)
	return
}

// GetWithdrawalHistory is used to retrieve your withdrawal history
// currency string a string literal for the currency (ie. BTC). If set to "all", will return for all currencies
// count int the number of records to return. Is set to 0 will return the max set.
func (b *Bittrex) GetWithdrawalHistory(currency string, count int) (withdrawals []Withdrawal, err error) {
	ressource := "account/getwithdrawalhistory"
	if count != 0 || currency != "all" {
		ressource += "?"
	}
	if count != 0 {
		ressource += fmt.Sprintf("count=%d&", count)
	}
	if currency != "all" {
		ressource += "currency=" + currency
	}
	r, err := b.client.do("GET", ressource, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &withdrawals)
	return
}

// GetDepositHistory is used to retrieve your deposit history
// currency string a string literal for the currency (ie. BTC). If set to "all", will return for all currencies
// count int the number of records to return. Is set to 0 will return the max set.
func (b *Bittrex) GetDepositHistory(currency string, count int) (deposits []Deposit, err error) {
	ressource := "account/getdeposithistory"
	if count != 0 || currency != "all" {
		ressource += "?"
	}
	if count != 0 {
		ressource += fmt.Sprintf("count=%d&", count)
	}
	if currency != "all" {
		ressource += "currency=" + currency
	}
	r, err := b.client.do("GET", ressource, "", true)
	if err != nil {
		return
	}
	var response jsonResponse
	if err = json.Unmarshal(r, &response); err != nil {
		return
	}
	if err = handleErr(response); err != nil {
		return
	}
	err = json.Unmarshal(response.Result, &deposits)
	return
}
<|endoftext|>


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

package image

// Color can convert itself to alpha-premultiplied RGBA, with a possible loss
// of precision. Each value ranges within [0, 0xFFFF], but is represented by a
// uint32 so that multiplying by a blend factor up to 0xFFFF will not overflow.
type Color interface {
	RGBA() (r, g, b, a uint32)
}

// RGBAColor represents a traditional 32-bit alpha-premultiplied color,
// having 8 bits for each of red, green, blue and alpha.
type RGBAColor struct {
	R, G, B, A uint8
}

func (c RGBAColor) RGBA() (r, g, b, a uint32) {
	r = uint32(c.R)
	r |= r << 8
	g = uint32(c.G)
	g |= g << 8
	b = uint32(c.B)
	b |= b << 8
	a = uint32(c.A)
	a |= a << 8
	return
}

// RGBA64Color represents a 64-bit alpha-premultiplied color,
// having 16 bits for each of red, green, blue and alpha.
type RGBA64Color struct {
	R, G, B, A uint16
}

func (c RGBA64Color) RGBA() (r, g, b, a uint32) {
	return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
}

// NRGBAColor represents a non-alpha-premultiplied 32-bit color.
type NRGBAColor struct {
	R, G, B, A uint8
}

func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
	r = uint32(c.R)
	r |= r << 8
	r *= uint32(c.A)
	r /= 0xff
	g = uint32(c.G)
	g |= g << 8
	g *= uint32(c.A)
	g /= 0xff
	b = uint32(c.B)
	b |= b << 8
	b *= uint32(c.A)
	b /= 0xff
	a = uint32(c.A)
	a |= a << 8
	return
}

// NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
// having 16 bits for each of red, green, blue and alpha.
type NRGBA64Color struct {
	R, G, B, A uint16
}

func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
	r = uint32(c.R)
	r *= uint32(c.A)
	r /= 0xffff
	g = uint32(c.G)
	g *= uint32(c.A)
	g /= 0xffff
	b = uint32(c.B)
	b *= uint32(c.A)
	b /= 0xffff
	a = uint32(c.A)
	return
}

// AlphaColor represents an 8-bit alpha.
type AlphaColor struct {
	A uint8
}

func (c AlphaColor) RGBA() (r, g, b, a uint32) {
	a = uint32(c.A)
	a |= a << 8
	return a, a, a, a
}

// Alpha16Color represents a 16-bit alpha.
type Alpha16Color struct {
	A uint16
}

func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
	a = uint32(c.A)
	return a, a, a, a
}

// GrayColor represents an 8-bit grayscale color.
type GrayColor struct {
	Y uint8
}

func (c GrayColor) RGBA() (r, g, b, a uint32) {
	y := uint32(c.Y)
	y |= y << 8
	return y, y, y, 0xffff
}

// Gray16Color represents a 16-bit grayscale color.
type Gray16Color struct {
	Y uint16
}

func (c Gray16Color) RGBA() (r, g, b, a uint32) {
	y := uint32(c.Y)
	return y, y, y, 0xffff
}

// ColorModel can convert foreign Colors, with a possible loss of precision,
// to a Color from its own color model.
type ColorModel interface {
	Convert(c Color) Color
}

// The ColorModelFunc type is an adapter to allow the use of an ordinary
// color conversion function as a ColorModel.  If f is such a function,
// ColorModelFunc(f) is a ColorModel object that invokes f to implement
// the conversion.
type ColorModelFunc func(Color) Color

func (f ColorModelFunc) Convert(c Color) Color {
	return f(c)
}

func toRGBAColor(c Color) Color {
	if _, ok := c.(RGBAColor); ok {
		return c
	}
	r, g, b, a := c.RGBA()
	return RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
}

func toRGBA64Color(c Color) Color {
	if _, ok := c.(RGBA64Color); ok {
		return c
	}
	r, g, b, a := c.RGBA()
	return RGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
}

func toNRGBAColor(c Color) Color {
	if _, ok := c.(NRGBAColor); ok {
		return c
	}
	r, g, b, a := c.RGBA()
	if a == 0xffff {
		return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
	}
	if a == 0 {
		return NRGBAColor{0, 0, 0, 0}
	}
	// Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
	r = (r * 0xffff) / a
	g = (g * 0xffff) / a
	b = (b * 0xffff) / a
	return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
}

func toNRGBA64Color(c Color) Color {
	if _, ok := c.(NRGBA64Color); ok {
		return c
	}
	r, g, b, a := c.RGBA()
	if a == 0xffff {
		return NRGBA64Color{uint16(r), uint16(g), uint16(b), 0xffff}
	}
	if a == 0 {
		return NRGBA64Color{0, 0, 0, 0}
	}
	// Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
	r = (r * 0xffff) / a
	g = (g * 0xffff) / a
	b = (b * 0xffff) / a
	return NRGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
}

func toAlphaColor(c Color) Color {
	if _, ok := c.(AlphaColor); ok {
		return c
	}
	_, _, _, a := c.RGBA()
	return AlphaColor{uint8(a >> 8)}
}

func toAlpha16Color(c Color) Color {
	if _, ok := c.(Alpha16Color); ok {
		return c
	}
	_, _, _, a := c.RGBA()
	return Alpha16Color{uint16(a)}
}

func toGrayColor(c Color) Color {
	if _, ok := c.(GrayColor); ok {
		return c
	}
	r, g, b, _ := c.RGBA()
	y := (299*r + 587*g + 114*b + 500) / 1000
	return GrayColor{uint8(y >> 8)}
}

func toGray16Color(c Color) Color {
	if _, ok := c.(Gray16Color); ok {
		return c
	}
	r, g, b, _ := c.RGBA()
	y := (299*r + 587*g + 114*b + 500) / 1000
	return Gray16Color{uint16(y)}
}

// The ColorModel associated with RGBAColor.
var RGBAColorModel ColorModel = ColorModelFunc(toRGBAColor)

// The ColorModel associated with RGBA64Color.
var RGBA64ColorModel ColorModel = ColorModelFunc(toRGBA64Color)

// The ColorModel associated with NRGBAColor.
var NRGBAColorModel ColorModel = ColorModelFunc(toNRGBAColor)

// The ColorModel associated with NRGBA64Color.
var NRGBA64ColorModel ColorModel = ColorModelFunc(toNRGBA64Color)

// The ColorModel associated with AlphaColor.
var AlphaColorModel ColorModel = ColorModelFunc(toAlphaColor)

// The ColorModel associated with Alpha16Color.
var Alpha16ColorModel ColorModel = ColorModelFunc(toAlpha16Color)

// The ColorModel associated with GrayColor.
var GrayColorModel ColorModel = ColorModelFunc(toGrayColor)

// The ColorModel associated with Gray16Color.
var Gray16ColorModel ColorModel = ColorModelFunc(toGray16Color)
<commit_msg>image: delete obsolete color.go<commit_after><|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"text/template"
	"time"

	"github.com/russross/blackfriday"

	"gopkg.in/fsnotify.v1"
)

var blogTitle = flag.String("title", "blog", "Blog title")
var destinationExt = flag.String("extension", "", "Destination file extension")
var postsPath = flag.String("posts", "posts", "Posts directory, comma separated for multiple directories")
var templatesPath = flag.String("templates", "templates", "Templates directory")
var destinationPath = flag.String("destination", "destination", "Destination directory")
var siteRoot = flag.String("root", "/", "Site root path")
var templatePrint = flag.String("print", "", "Print out a template for a snippet, blog post or a page")
var templateAuthor = flag.String("author", "", "Set a default post author")
var listen = flag.Bool("listen", false, "Listen to changes in post directories and regenerate")

const templateFileName = "template.html"
const rssTemplateFileName = "rsstemplate.html"

func generate() {

	log.Printf("Generating blog: %s", *blogTitle)

	destinationDir, destinationDirErr := os.Open(*destinationPath)

	if destinationDirErr != nil {
		log.Fatal("Destination directory could not be opened: ", destinationDirErr)
	}

	defer destinationDir.Close()

	funcMap := template.FuncMap{
		"longDate":     func(args ...interface{}) string { return args[0].(*time.Time).Format("Monday, _2 January 2006, 15:04") },
		"snippetDate":  func(args ...interface{}) string { return args[0].(*time.Time).Format("Jan _2 2006, 15:04") },
		"shortDate":    func(args ...interface{}) string { return args[0].(*time.Time).Format("Jan _2, 2006") },
		"atomDate":     func(args ...interface{}) string { return args[0].(*time.Time).Format("2006-01-02T15:04:05Z07:00") },
		"Snippet":      func(args ...interface{}) bool { return args[0].(*Article).Type == Snippet },
		"Post":         func(args ...interface{}) bool { return args[0].(*Article).Type == Post },
		"Page":         func(args ...interface{}) bool { return args[0].(*Article).Type == Page },
		"last":         func(index, count int) bool { return index == count-1 },
		"tagIndexName": func(tag string) string { return "tag-" + tag + *destinationExt },
		"path": func(article Article) string {
			return article.FullPath()
		},
	}

	mainTemplate := template.Must(template.New("template.html").Funcs(funcMap).ParseFiles(path.Join(*templatesPath, templateFileName)))
	mainRssTemplate := template.Must(template.New("rsstemplate.html").Funcs(funcMap).ParseFiles(path.Join(*templatesPath, rssTemplateFileName)))

	now := time.Now()

	type PostFile struct {
		Name      string
		Extension string
		Path      string
	}

	sourceFiles := []PostFile{}

	for _, postDir := range strings.Split(*postsPath, ",") {

		walkFunc := func(filepath string, info os.FileInfo, err error) error {
			ext := path.Ext(info.Name())
			name := strings.TrimSuffix(path.Base(info.Name()), ext)

			if info.IsDir() || (ext != ".markdown" && ext != ".md" && ext != ".txt") {
				return nil
			}

			sourceFiles = append(sourceFiles, PostFile{Name: name, Extension: ext, Path: filepath})

			return nil
		}

		filepath.Walk(postDir, walkFunc)
	}

	var articles, indexArticles, feedArticles, snippetArticles Articles

	htmlFlags := 0
	htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES

	var rendererParameters blackfriday.HtmlRendererParameters

	htmlPrefix := *siteRoot
	htmlPrefix = strings.TrimSuffix(htmlPrefix, "/")
	rendererParameters.AbsolutePrefix = htmlPrefix

	log.Println("Using prefix", htmlPrefix)
	renderer := blackfriday.HtmlRendererWithParameters(htmlFlags, "", "", rendererParameters)
	extensions := 0
	extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
	extensions |= blackfriday.EXTENSION_TABLES
	extensions |= blackfriday.EXTENSION_FENCED_CODE
	extensions |= blackfriday.EXTENSION_AUTOLINK
	extensions |= blackfriday.EXTENSION_STRIKETHROUGH
	extensions |= blackfriday.EXTENSION_SPACE_HEADERS
	extensions |= blackfriday.EXTENSION_HEADER_IDS

	for _, sourceFile := range sourceFiles {

		file, fileError := os.Open(sourceFile.Path)

		if fileError != nil {
			log.Printf("Skipping %v due to error: %v", sourceFile.Path, fileError)
			continue
		}

		defer file.Close()

		article, readErr := ReadArticle(bufio.NewReader(file))

		if readErr != nil {
			log.Printf("Skipping file %v due to parse error: %v", sourceFile.Path, readErr)
			continue
		}

		md := blackfriday.Markdown(article.RawContent, renderer, extensions)

		article.Content = string(md)

		if len(article.Description) == 0 {
			article.Description = article.Content
		}

		article.Filename = sourceFile.Name + *destinationExt

		if article.DateModified == nil {
			article.DateModified = new(time.Time)
		}

		article.Identifier = sourceFile.Name

		articles = append(articles, &article)

		if article.Type == Page {
			continue
		}

		if article.Draft {
			continue
		}

		if article.Type == Post {
			feedArticles = append(feedArticles, &article)
		}

		if article.Type == Snippet {
			snippetArticles = append(snippetArticles, &article)
		}

		indexArticles = append(indexArticles, &article)
	}

	tags := map[string]bool{}

	sort.Sort(articles)
	sort.Sort(indexArticles)
	sort.Sort(feedArticles)
	sort.Sort(snippetArticles)

	indexBuffer := bytes.NewBufferString("")
	rssIndexBuffer := bytes.NewBufferString("")
	snippetrssIndexBuffer := bytes.NewBufferString("")

	mainTemplate.Execute(indexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": *siteRoot, "Articles": indexArticles, "CreatedTime": now})
	mainRssTemplate.Execute(rssIndexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": *siteRoot, "File": "index.xml", "Articles": feedArticles, "CreatedTime": &now})
	mainRssTemplate.Execute(snippetrssIndexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": *siteRoot, "File": "snippets.xml", "Articles": snippetArticles, "CreatedTime": &now})

	for _, article := range articles {

		destFileBuffer := bytes.NewBufferString("")

		mainTemplate.Execute(destFileBuffer, map[string]interface{}{
			"BlogTitle": blogTitle,
			"Article":   article,
			"Title":     string(article.Title + " – " + *blogTitle),
			"Home":      false,
			"Root":      *siteRoot,
		})

		for _, tag := range article.Tags {
			tags[tag] = true
		}

		destinationFileName := path.Join(destinationDir.Name(), article.FullPath())

		os.MkdirAll(path.Join(destinationDir.Name(), article.BasePath()), os.ModePerm)

		writeErr := ioutil.WriteFile(destinationFileName, destFileBuffer.Bytes(), os.ModePerm)

		if writeErr != nil {
			log.Printf("Could not write file %v due to error: %v", destinationFileName, writeErr)
		}
	}

	indexFileName := path.Join(destinationDir.Name(), "index.html")
	rssIndexFileName := path.Join(destinationDir.Name(), "index.xml")
	snippetIndexFileName := path.Join(destinationDir.Name(), "snippets.xml")

	ioutil.WriteFile(indexFileName, indexBuffer.Bytes(), os.ModePerm)
	ioutil.WriteFile(rssIndexFileName, rssIndexBuffer.Bytes(), os.ModePerm)
	ioutil.WriteFile(snippetIndexFileName, snippetrssIndexBuffer.Bytes(), os.ModePerm)

	for tag := range tags {

		tagIndexBuffer := bytes.NewBufferString("")
		var tagArticles Articles

		for _, article := range indexArticles {

			if !article.HasTag(tag) {
				continue
			}

			tagArticles = append(tagArticles, article)
		}

		mainTemplate.Execute(tagIndexBuffer, map[string]interface{}{"Articles": tagArticles, "Title": "Tag: " + tag + " – " + *blogTitle, "Home": false, "Root": *siteRoot})

		tagIndexFileName := path.Join(destinationDir.Name(), "tag-"+tag+*destinationExt)
		ioutil.WriteFile(tagIndexFileName, tagIndexBuffer.Bytes(), os.ModePerm)
	}
}

func main() {

	flag.Parse()

	if *templatePrint != "" {
		var article Article
		now := time.Now().Add(15 * time.Minute)
		article.DateModified = &now

		article.Draft = true

		if *templateAuthor != "" {
			article.Author = *templateAuthor
		}

		switch *templatePrint {
		case "page":
			article.Title = "Hello world"
			article.Type = Page
			break
		case "post":
			article.Title = "Blog post"
			article.Type = Post
			break
		case "snippet":
			article.Type = Snippet
			break
		default:
			log.Fatal("post, snippet and page are the only allowed parameters for -print")
		}

		article.Print()

		return
	}

	generate()

	if *listen {
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Fatal("Couldn't watch the post directories")
		}
		defer watcher.Close()

		watcherDone := make(chan bool)
		go func() {
			for {
				select {
				case event := <-watcher.Events:
					if event.Op&fsnotify.Write == fsnotify.Write {
						log.Println("Modified file: ", event.Name)
						generate()
					}
				case err := <-watcher.Errors:
					log.Println("Got error:", err)
				}
			}
		}()

		var watchedDirs []string

		for _, postDir := range strings.Split(*postsPath, ",") {

			walkFunc := func(filepath string, info os.FileInfo, err error) error {
				if !info.IsDir() {
					return nil
				}

				watchedDirs = append(watchedDirs, filepath)

				return nil
			}

			filepath.Walk(postDir, walkFunc)
		}

		watchedDirs = append(watchedDirs, *templatesPath)

		for _, watchedDir := range watchedDirs {
			watcher.Add(watchedDir)
		}

		log.Printf("Listening to changes in directories: %s…", strings.Join(watchedDirs, ", "))

		<-watcherDone
	}
}
<commit_msg>Added actual support for adding short descriptions to articles by not replacing an empty description with article's full content.<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"text/template"
	"time"

	"github.com/russross/blackfriday"

	"gopkg.in/fsnotify.v1"
)

var blogTitle = flag.String("title", "blog", "Blog title")
var destinationExt = flag.String("extension", "", "Destination file extension")
var postsPath = flag.String("posts", "posts", "Posts directory, comma separated for multiple directories")
var templatesPath = flag.String("templates", "templates", "Templates directory")
var destinationPath = flag.String("destination", "destination", "Destination directory")
var siteRoot = flag.String("root", "/", "Site root path")
var templatePrint = flag.String("print", "", "Print out a template for a snippet, blog post or a page")
var templateAuthor = flag.String("author", "", "Set a default post author")
var listen = flag.Bool("listen", false, "Listen to changes in post directories and regenerate")

const templateFileName = "template.html"
const rssTemplateFileName = "rsstemplate.html"

func generate() {

	log.Printf("Generating blog: %s", *blogTitle)

	destinationDir, destinationDirErr := os.Open(*destinationPath)

	if destinationDirErr != nil {
		log.Fatal("Destination directory could not be opened: ", destinationDirErr)
	}

	defer destinationDir.Close()

	funcMap := template.FuncMap{
		"longDate":     func(args ...interface{}) string { return args[0].(*time.Time).Format("Monday, _2 January 2006, 15:04") },
		"snippetDate":  func(args ...interface{}) string { return args[0].(*time.Time).Format("Jan _2 2006, 15:04") },
		"shortDate":    func(args ...interface{}) string { return args[0].(*time.Time).Format("Jan _2, 2006") },
		"atomDate":     func(args ...interface{}) string { return args[0].(*time.Time).Format("2006-01-02T15:04:05Z07:00") },
		"Snippet":      func(args ...interface{}) bool { return args[0].(*Article).Type == Snippet },
		"Post":         func(args ...interface{}) bool { return args[0].(*Article).Type == Post },
		"Page":         func(args ...interface{}) bool { return args[0].(*Article).Type == Page },
		"last":         func(index, count int) bool { return index == count-1 },
		"tagIndexName": func(tag string) string { return "tag-" + tag + *destinationExt },
		"path": func(article Article) string {
			return article.FullPath()
		},
	}

	mainTemplate := template.Must(template.New("template.html").Funcs(funcMap).ParseFiles(path.Join(*templatesPath, templateFileName)))
	mainRssTemplate := template.Must(template.New("rsstemplate.html").Funcs(funcMap).ParseFiles(path.Join(*templatesPath, rssTemplateFileName)))

	now := time.Now()

	type PostFile struct {
		Name      string
		Extension string
		Path      string
	}

	sourceFiles := []PostFile{}

	for _, postDir := range strings.Split(*postsPath, ",") {

		walkFunc := func(filepath string, info os.FileInfo, err error) error {
			ext := path.Ext(info.Name())
			name := strings.TrimSuffix(path.Base(info.Name()), ext)

			if info.IsDir() || (ext != ".markdown" && ext != ".md" && ext != ".txt") {
				return nil
			}

			sourceFiles = append(sourceFiles, PostFile{Name: name, Extension: ext, Path: filepath})

			return nil
		}

		filepath.Walk(postDir, walkFunc)
	}

	var articles, indexArticles, feedArticles, snippetArticles Articles

	htmlFlags := 0
	htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES

	var rendererParameters blackfriday.HtmlRendererParameters

	htmlPrefix := *siteRoot
	htmlPrefix = strings.TrimSuffix(htmlPrefix, "/")
	rendererParameters.AbsolutePrefix = htmlPrefix

	log.Println("Using prefix", htmlPrefix)
	renderer := blackfriday.HtmlRendererWithParameters(htmlFlags, "", "", rendererParameters)
	extensions := 0
	extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
	extensions |= blackfriday.EXTENSION_TABLES
	extensions |= blackfriday.EXTENSION_FENCED_CODE
	extensions |= blackfriday.EXTENSION_AUTOLINK
	extensions |= blackfriday.EXTENSION_STRIKETHROUGH
	extensions |= blackfriday.EXTENSION_SPACE_HEADERS
	extensions |= blackfriday.EXTENSION_HEADER_IDS

	for _, sourceFile := range sourceFiles {

		file, fileError := os.Open(sourceFile.Path)

		if fileError != nil {
			log.Printf("Skipping %v due to error: %v", sourceFile.Path, fileError)
			continue
		}

		defer file.Close()

		article, readErr := ReadArticle(bufio.NewReader(file))

		if readErr != nil {
			log.Printf("Skipping file %v due to parse error: %v", sourceFile.Path, readErr)
			continue
		}

		md := blackfriday.Markdown(article.RawContent, renderer, extensions)

		article.Content = string(md)

		article.Filename = sourceFile.Name + *destinationExt

		if article.DateModified == nil {
			article.DateModified = new(time.Time)
		}

		article.Identifier = sourceFile.Name

		articles = append(articles, &article)

		if article.Type == Page {
			continue
		}

		if article.Draft {
			continue
		}

		if article.Type == Post {
			feedArticles = append(feedArticles, &article)
		}

		if article.Type == Snippet {
			snippetArticles = append(snippetArticles, &article)
		}

		indexArticles = append(indexArticles, &article)
	}

	tags := map[string]bool{}

	sort.Sort(articles)
	sort.Sort(indexArticles)
	sort.Sort(feedArticles)
	sort.Sort(snippetArticles)

	indexBuffer := bytes.NewBufferString("")
	rssIndexBuffer := bytes.NewBufferString("")
	snippetrssIndexBuffer := bytes.NewBufferString("")

	mainTemplate.Execute(indexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": *siteRoot, "Articles": indexArticles, "CreatedTime": now})
	mainRssTemplate.Execute(rssIndexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": *siteRoot, "File": "index.xml", "Articles": feedArticles, "CreatedTime": &now})
	mainRssTemplate.Execute(snippetrssIndexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": *siteRoot, "File": "snippets.xml", "Articles": snippetArticles, "CreatedTime": &now})

	for _, article := range articles {

		destFileBuffer := bytes.NewBufferString("")

		mainTemplate.Execute(destFileBuffer, map[string]interface{}{
			"BlogTitle": blogTitle,
			"Article":   article,
			"Title":     string(article.Title + " – " + *blogTitle),
			"Home":      false,
			"Root":      *siteRoot,
		})

		for _, tag := range article.Tags {
			tags[tag] = true
		}

		destinationFileName := path.Join(destinationDir.Name(), article.FullPath())

		os.MkdirAll(path.Join(destinationDir.Name(), article.BasePath()), os.ModePerm)

		writeErr := ioutil.WriteFile(destinationFileName, destFileBuffer.Bytes(), os.ModePerm)

		if writeErr != nil {
			log.Printf("Could not write file %v due to error: %v", destinationFileName, writeErr)
		}
	}

	indexFileName := path.Join(destinationDir.Name(), "index.html")
	rssIndexFileName := path.Join(destinationDir.Name(), "index.xml")
	snippetIndexFileName := path.Join(destinationDir.Name(), "snippets.xml")

	ioutil.WriteFile(indexFileName, indexBuffer.Bytes(), os.ModePerm)
	ioutil.WriteFile(rssIndexFileName, rssIndexBuffer.Bytes(), os.ModePerm)
	ioutil.WriteFile(snippetIndexFileName, snippetrssIndexBuffer.Bytes(), os.ModePerm)

	for tag := range tags {

		tagIndexBuffer := bytes.NewBufferString("")
		var tagArticles Articles

		for _, article := range indexArticles {

			if !article.HasTag(tag) {
				continue
			}

			tagArticles = append(tagArticles, article)
		}

		mainTemplate.Execute(tagIndexBuffer, map[string]interface{}{"Articles": tagArticles, "Title": "Tag: " + tag + " – " + *blogTitle, "Home": false, "Root": *siteRoot})

		tagIndexFileName := path.Join(destinationDir.Name(), "tag-"+tag+*destinationExt)
		ioutil.WriteFile(tagIndexFileName, tagIndexBuffer.Bytes(), os.ModePerm)
	}
}

func main() {

	flag.Parse()

	if *templatePrint != "" {
		var article Article
		now := time.Now().Add(15 * time.Minute)
		article.DateModified = &now

		article.Draft = true

		if *templateAuthor != "" {
			article.Author = *templateAuthor
		}

		switch *templatePrint {
		case "page":
			article.Title = "Hello world"
			article.Type = Page
			break
		case "post":
			article.Title = "Blog post"
			article.Type = Post
			break
		case "snippet":
			article.Type = Snippet
			break
		default:
			log.Fatal("post, snippet and page are the only allowed parameters for -print")
		}

		article.Print()

		return
	}

	generate()

	if *listen {
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Fatal("Couldn't watch the post directories")
		}
		defer watcher.Close()

		watcherDone := make(chan bool)
		go func() {
			for {
				select {
				case event := <-watcher.Events:
					if event.Op&fsnotify.Write == fsnotify.Write {
						log.Println("Modified file: ", event.Name)
						generate()
					}
				case err := <-watcher.Errors:
					log.Println("Got error:", err)
				}
			}
		}()

		var watchedDirs []string

		for _, postDir := range strings.Split(*postsPath, ",") {

			walkFunc := func(filepath string, info os.FileInfo, err error) error {
				if !info.IsDir() {
					return nil
				}

				watchedDirs = append(watchedDirs, filepath)

				return nil
			}

			filepath.Walk(postDir, walkFunc)
		}

		watchedDirs = append(watchedDirs, *templatesPath)

		for _, watchedDir := range watchedDirs {
			watcher.Add(watchedDir)
		}

		log.Printf("Listening to changes in directories: %s…", strings.Join(watchedDirs, ", "))

		<-watcherDone
	}
}
<|endoftext|>


<commit_before>package projects

import (
	"time"

	"github.com/ion-channel/ionic/aliases"
	"github.com/ion-channel/ionic/tags"
)

//Project is a representation of a project within the Ion Channel system
type Project struct {
	ID             string          `json:"id"`
	Active         bool            `json:"active"`
	Aliases        []aliases.Alias `json:"aliases"`
	Branch         string          `json:"branch"`
	ChatChannel    string          `json:"chat_channel"`
	CreatedAt      time.Time       `json:"created_at"`
	DeployKey      string          `json:"deploy_key"`
	Description    string          `json:"description"`
	KeyFingerprint string          `json:"key_fingerprint"`
	Name           string          `json:"name"`
	POCEmail       string          `json:"poc_email"`
	POCName        string          `json:"poc_name"`
	RulesetID      string          `json:"ruleset_id"`
	Monitor        bool            `json:"should_monitor"`
	Source         string          `json:"source"`
	Tags           []tags.Tag      `json:"tags"`
	TeamID         string          `json:"team_id"`
	Type           string          `json:"type"`
	UpdatedAt      time.Time       `json:"updated_at"`
}
<commit_msg>better ordering of project fields<commit_after>package projects

import (
	"time"

	"github.com/ion-channel/ionic/aliases"
	"github.com/ion-channel/ionic/tags"
)

//Project is a representation of a project within the Ion Channel system
type Project struct {
	ID             string          `json:"id"`
	TeamID         string          `json:"team_id"`
	RulesetID      string          `json:"ruleset_id"`
	Name           string          `json:"name"`
	Type           string          `json:"type"`
	Source         string          `json:"source"`
	Branch         string          `json:"branch"`
	Description    string          `json:"description"`
	Active         bool            `json:"active"`
	ChatChannel    string          `json:"chat_channel"`
	CreatedAt      time.Time       `json:"created_at"`
	UpdatedAt      time.Time       `json:"updated_at"`
	DeployKey      string          `json:"deploy_key"`
	Monitor        bool            `json:"should_monitor"`
	POCName        string          `json:"poc_name"`
	POCEmail       string          `json:"poc_email"`
	Username       string          `json:"username"`
	Password       string          `json:"password"`
	KeyFingerprint string          `json:"key_fingerprint"`
	Aliases        []aliases.Alias `json:"aliases"`
	Tags           []tags.Tag      `json:"tags"`
}
<|endoftext|>