<commit_before>package main

import (
	"os"

	"github.com/spf13/cobra"

	"github.com/apex/apex/wiki"
	"github.com/apex/log"
)

type WikiCmdLocalValues struct {
	topic string
}

const wikiCmdExample = `  Output wiki topics
  $ apex wiki

  Output wiki for a topic
  # apex wiki project.json`

var wikiCmd = &cobra.Command{
	Use:              "wiki [<topic>]",
	Short:            "Output wiki page pulled from the GitHub wiki",
	Example:          wikiCmdExample,
	PersistentPreRun: pv.noopRun,
	PreRun:           wikiCmdPreRun,
	Run:              wikiCmdRun,
}

var wikiCmdLocalValues = WikiCmdLocalValues{}

func wikiCmdPreRun(c *cobra.Command, args []string) {
	lv := &wikiCmdLocalValues

	if len(args) >= 1 {
		lv.topic = args[0]
	}
}

func wikiCmdRun(c *cobra.Command, args []string) {
	lv := &wikiCmdLocalValues

	var err error

	if lv.topic != "" {
		err = wiki.Topic(lv.topic, os.Stdout)
	} else {
		err = wiki.Topics(os.Stdout)
	}

	if err != nil {
		log.Fatalf("error: %s", err)
	}
}
<commit_msg>add wiki multi-arg support. Closes #117<commit_after>package main

import (
	"os"
	"strings"

	"github.com/spf13/cobra"

	"github.com/apex/apex/wiki"
	"github.com/apex/log"
)

type WikiCmdLocalValues struct {
	topic string
}

const wikiCmdExample = `  Output wiki topics
  $ apex wiki

  Output wiki for a topic
  $ apex wiki project.json`

var wikiCmd = &cobra.Command{
	Use:              "wiki [<topic>]",
	Short:            "Output wiki page pulled from the GitHub wiki",
	Example:          wikiCmdExample,
	PersistentPreRun: pv.noopRun,
	PreRun:           wikiCmdPreRun,
	Run:              wikiCmdRun,
}

var wikiCmdLocalValues = WikiCmdLocalValues{}

func wikiCmdPreRun(c *cobra.Command, args []string) {
	lv := &wikiCmdLocalValues

	if len(args) >= 1 {
		lv.topic = strings.Join(args, " ")
	}
}

func wikiCmdRun(c *cobra.Command, args []string) {
	lv := &wikiCmdLocalValues

	var err error

	if lv.topic != "" {
		err = wiki.Topic(lv.topic, os.Stdout)
	} else {
		err = wiki.Topics(os.Stdout)
	}

	if err != nil {
		log.Fatalf("error: %s", err)
	}
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"io"
	"log"
	"math/rand"
	"net/http"
	"time"

	"github.com/mjibson/mog/_third_party/golang.org/x/net/websocket"
	"github.com/mjibson/mog/_third_party/golang.org/x/oauth2"
	"github.com/mjibson/mog/codec"
	"github.com/mjibson/mog/output"
	"github.com/mjibson/mog/protocol"
)

func (srv *Server) audio() {
	var o output.Output
	var t chan interface{}
	var dur time.Duration
	srv.state = stateStop
	var next, stop, tick, play, pause, prev func()
	var timer <-chan time.Time
	waiters := make(map[*websocket.Conn]chan struct{})
	var seek *Seek
	broadcastData := func(wd *waitData) {
		for ws := range waiters {
			go func(ws *websocket.Conn) {
				if err := websocket.JSON.Send(ws, wd); err != nil {
					srv.ch <- cmdDeleteWS(ws)
				}
			}(ws)
		}
	}
	broadcast := func(wt waitType) {
		wd, err := srv.makeWaitData(wt)
		if err != nil {
			log.Println(err)
			return
		}
		broadcastData(wd)
	}
	broadcastErr := func(err error) {
		printErr(err)
		v := struct {
			Time  time.Time
			Error string
		}{
			time.Now().UTC(),
			err.Error(),
		}
		broadcastData(&waitData{
			Type: waitError,
			Data: v,
		})
	}
	newWS := func(c cmdNewWS) {
		ws := (*websocket.Conn)(c.ws)
		waiters[ws] = c.done
		inits := []waitType{
			waitPlaylist,
			waitProtocols,
			waitStatus,
			waitTracks,
		}
		for _, wt := range inits {
			data, err := srv.makeWaitData(wt)
			if err != nil {
				return
			}
			go func() {
				if err := websocket.JSON.Send(ws, data); err != nil {
					srv.ch <- cmdDeleteWS(ws)
					return
				}
			}()
		}
	}
	deleteWS := func(c cmdDeleteWS) {
		ws := (*websocket.Conn)(c)
		ch := waiters[ws]
		if ch == nil {
			return
		}
		close(ch)
		delete(waiters, ws)
	}
	prev = func() {
		log.Println("prev")
		srv.PlaylistIndex--
		if srv.elapsed < time.Second*3 {
			srv.PlaylistIndex--
		}
		if srv.PlaylistIndex < 0 {
			srv.PlaylistIndex = 0
		}
		next()
	}
	pause = func() {
		log.Println("pause")
		switch srv.state {
		case statePause, stateStop:
			log.Println("pause: resume")
			t = make(chan interface{})
			close(t)
			tick()
			srv.state = statePlay
		case statePlay:
			log.Println("pause: pause")
			t = nil
			srv.state = statePause
		}
	}
	next = func() {
		log.Println("next")
		stop()
		play()
	}
	var forceNext = false
	stop = func() {
		log.Println("stop")
		srv.state = stateStop
		t = nil
		if srv.song != nil || forceNext {
			if srv.Random && len(srv.Queue) > 1 {
				n := srv.PlaylistIndex
				for n == srv.PlaylistIndex {
					n = rand.Intn(len(srv.Queue))
				}
				srv.PlaylistIndex = n
			} else {
				srv.PlaylistIndex++
			}
		}
		forceNext = false
		srv.song = nil
		srv.elapsed = 0
	}
	var inst protocol.Instance
	var sid SongID
	sendNext := func() {
		go func() {
			srv.ch <- cmdNext
		}()
	}
	nextOpen := time.After(0)
	tick = func() {
		const expected = 4096
		if false && srv.elapsed > srv.info.Time {
			log.Println("elapsed time completed", srv.elapsed, srv.info.Time)
			stop()
		}
		if srv.song == nil {
			<-nextOpen
			nextOpen = time.After(time.Second / 2)
			defer broadcast(waitStatus)
			if len(srv.Queue) == 0 {
				log.Println("empty queue")
				stop()
				return
			}
			if srv.PlaylistIndex >= len(srv.Queue) {
				if srv.Repeat {
					srv.PlaylistIndex = 0
				} else {
					log.Println("end of queue", srv.PlaylistIndex, len(srv.Queue))
					stop()
					return
				}
			}

			srv.songID = srv.Queue[srv.PlaylistIndex]
			sid = srv.songID
			if info := srv.songs[sid]; info == nil {
				broadcastErr(fmt.Errorf("unknown id: %v", sid))
				forceNext = true
				sendNext()
				return
			} else {
				srv.info = *info
			}
			inst = srv.Protocols[sid.Protocol()][sid.Key()]
			song, err := inst.GetSong(sid.ID())
			if err != nil {
				forceNext = true
				broadcastErr(err)
				sendNext()
				return
			}
			srv.song = song
			sr, ch, err := srv.song.Init()
			if err != nil {
				srv.song.Close()
				broadcastErr(err)
				sendNext()
				return
			}
			o, err = output.Get(sr, ch)
			if err != nil {
				broadcastErr(fmt.Errorf("mog: could not open audio (%v, %v): %v", sr, ch, err))
				sendNext()
				return
			}
			srv.elapsed = 0
			dur = time.Second / (time.Duration(sr * ch))
			seek = NewSeek(srv.info.Time > 0, dur, srv.song.Play)
			log.Println("playing", srv.info.Title, sr, ch, dur, time.Duration(expected)*dur)
			t = make(chan interface{})
			close(t)
			srv.state = statePlay
		}
		next, err := seek.Read(expected)
		if err == nil {
			srv.elapsed = seek.Pos()
			if len(next) > 0 {
				o.Push(next)
			}
			select {
			case <-timer:
				// Check for updated song info.
				if info, err := inst.Info(sid.ID()); err != nil {
					broadcastErr(err)
				} else if srv.info != *info {
					srv.info = *info
					broadcast(waitStatus)
				}
				timer = nil
			default:
			}
			if timer == nil {
				timer = time.After(time.Second)
			}
		}
		if len(next) < expected || err != nil {
			log.Println("end of song", len(next), expected, err)
			if err == io.ErrUnexpectedEOF {
				log.Println("attempting to restart song")
				n := srv.PlaylistIndex
				stop()
				srv.PlaylistIndex = n
				play()
			} else {
				stop()
				play()
			}
		}
	}
	play = func() {
		log.Println("play")
		if srv.PlaylistIndex > len(srv.Queue) {
			srv.PlaylistIndex = 0
		}
		tick()
	}
	playIdx := func(c cmdPlayIdx) {
		stop()
		srv.PlaylistIndex = int(c)
		play()
	}
	refresh := func(c cmdRefresh) {
		for id := range srv.songs {
			if id.Protocol() == c.protocol && id.Key() == c.key {
				delete(srv.songs, id)
			}
		}
		for id, s := range c.songs {
			srv.songs[SongID(codec.NewID(c.protocol, c.key, string(id)))] = s
		}
		broadcast(waitTracks)
		broadcast(waitProtocols)
	}
	protocolRemove := func(c cmdProtocolRemove) {
		delete(c.prots, c.key)
		for id := range srv.songs {
			if id.Protocol() == c.protocol && id.Key() == c.key {
				delete(srv.songs, id)
			}
		}
		broadcast(waitTracks)
		broadcast(waitProtocols)
	}
	queueChange := func(c cmdQueueChange) {
		n, clear, err := srv.playlistChange(srv.Queue, PlaylistChange(c), true)
		if err != nil {
			broadcastErr(err)
			return
		}
		srv.Queue = n
		if clear || len(n) == 0 {
			stop()
			srv.PlaylistIndex = 0
		}
		broadcast(waitPlaylist)
	}
	playlistChange := func(c cmdPlaylistChange) {
		p := srv.Playlists[c.name]
		n, _, err := srv.playlistChange(p, c.plc, false)
		if err != nil {
			broadcastErr(err)
			return
		}
		if len(n) == 0 {
			delete(srv.Playlists, c.name)
		} else {
			srv.Playlists[c.name] = n
		}
		broadcast(waitPlaylist)
	}
	queueSave := func() {
		if srv.savePending {
			return
		}
		srv.savePending = true
		time.AfterFunc(time.Second, func() {
			srv.ch <- cmdDoSave{}
		})
	}
	doSave := func() {
		if err := srv.save(); err != nil {
			broadcastErr(err)
		}
	}
	addOAuth := func(c cmdAddOAuth) {
		prot, err := protocol.ByName(c.name)
		if err != nil {
			c.done <- err
			return
		}
		prots, ok := srv.Protocols[c.name]
		if !ok || prot.OAuth == nil {
			c.done <- fmt.Errorf("bad protocol")
			return
		}
		// TODO: decouple this from the audio thread
		t, err := prot.OAuth.Exchange(oauth2.NoContext, c.r.FormValue("code"))
		if err != nil {
			c.done <- err
			return
		}
		// "Bearer" was added for dropbox. It happens to work also with Google Music's
		// OAuth. This may need to be changed to be protocol-specific in the future.
		t.TokenType = "Bearer"
		instance, err := prot.NewInstance(nil, t)
		if err != nil {
			c.done <- err
			return
		}
		prots[t.AccessToken] = instance
		go srv.protocolRefresh(c.name, instance.Key(), false)
		c.done <- nil
	}
	doSeek := func(c cmdSeek) {
		if seek == nil {
			return
		}
		err := seek.Seek(time.Duration(c))
		if err != nil {
			broadcastErr(err)
		}
	}
	setMinDuration := func(c cmdMinDuration) {
		srv.MinDuration = time.Duration(c)
	}
	ch := make(chan interface{})
	go func() {
		for c := range srv.ch {
			timer := time.AfterFunc(time.Second*10, func() {
				panic("delay timer expired")
			})
			ch <- c
			timer.Stop()
		}
	}()
	for {
		select {
		case <-t:
			tick()
		case c := <-ch:
			save := true
			log.Printf("%T\n", c)
			switch c := c.(type) {
			case controlCmd:
				switch c {
				case cmdPlay:
					save = false
					play()
				case cmdStop:
					save = false
					stop()
				case cmdNext:
					next()
				case cmdPause:
					save = false
					pause()
				case cmdPrev:
					prev()
				case cmdRandom:
					srv.Random = !srv.Random
				case cmdRepeat:
					srv.Repeat = !srv.Repeat
				default:
					panic(c)
				}
			case cmdPlayIdx:
				playIdx(c)
			case cmdRefresh:
				refresh(c)
			case cmdProtocolRemove:
				protocolRemove(c)
			case cmdQueueChange:
				queueChange(c)
			case cmdPlaylistChange:
				playlistChange(c)
			case cmdNewWS:
				save = false
				newWS(c)
			case cmdDeleteWS:
				save = false
				deleteWS(c)
			case cmdDoSave:
				save = false
				doSave()
			case cmdAddOAuth:
				addOAuth(c)
			case cmdSeek:
				save = false
				doSeek(c)
			case cmdMinDuration:
				setMinDuration(c)
			default:
				panic(c)
			}
			broadcast(waitStatus)
			if save {
				queueSave()
			}
		}
	}
}

type controlCmd int

const (
	cmdUnknown controlCmd = iota
	cmdNext
	cmdPause
	cmdPlay
	cmdPrev
	cmdRandom
	cmdRepeat
	cmdStop
)

type cmdSeek time.Duration

type cmdPlayIdx int

type cmdRefresh struct {
	protocol, key string
	songs         protocol.SongList
}

type cmdProtocolRemove struct {
	protocol, key string
	prots         map[string]protocol.Instance
}

type cmdQueueChange PlaylistChange

type cmdPlaylistChange struct {
	plc  PlaylistChange
	name string
}

type cmdDoSave struct{}

type cmdAddOAuth struct {
	name string
	r    *http.Request
	done chan error
}

type cmdMinDuration time.Duration
<commit_msg>Unset song on error<commit_after>package server

import (
	"fmt"
	"io"
	"log"
	"math/rand"
	"net/http"
	"time"

	"github.com/mjibson/mog/_third_party/golang.org/x/net/websocket"
	"github.com/mjibson/mog/_third_party/golang.org/x/oauth2"
	"github.com/mjibson/mog/codec"
	"github.com/mjibson/mog/output"
	"github.com/mjibson/mog/protocol"
)

func (srv *Server) audio() {
	var o output.Output
	var t chan interface{}
	var dur time.Duration
	srv.state = stateStop
	var next, stop, tick, play, pause, prev func()
	var timer <-chan time.Time
	waiters := make(map[*websocket.Conn]chan struct{})
	var seek *Seek
	broadcastData := func(wd *waitData) {
		for ws := range waiters {
			go func(ws *websocket.Conn) {
				if err := websocket.JSON.Send(ws, wd); err != nil {
					srv.ch <- cmdDeleteWS(ws)
				}
			}(ws)
		}
	}
	broadcast := func(wt waitType) {
		wd, err := srv.makeWaitData(wt)
		if err != nil {
			log.Println(err)
			return
		}
		broadcastData(wd)
	}
	broadcastErr := func(err error) {
		printErr(err)
		v := struct {
			Time  time.Time
			Error string
		}{
			time.Now().UTC(),
			err.Error(),
		}
		broadcastData(&waitData{
			Type: waitError,
			Data: v,
		})
	}
	newWS := func(c cmdNewWS) {
		ws := (*websocket.Conn)(c.ws)
		waiters[ws] = c.done
		inits := []waitType{
			waitPlaylist,
			waitProtocols,
			waitStatus,
			waitTracks,
		}
		for _, wt := range inits {
			data, err := srv.makeWaitData(wt)
			if err != nil {
				return
			}
			go func() {
				if err := websocket.JSON.Send(ws, data); err != nil {
					srv.ch <- cmdDeleteWS(ws)
					return
				}
			}()
		}
	}
	deleteWS := func(c cmdDeleteWS) {
		ws := (*websocket.Conn)(c)
		ch := waiters[ws]
		if ch == nil {
			return
		}
		close(ch)
		delete(waiters, ws)
	}
	prev = func() {
		log.Println("prev")
		srv.PlaylistIndex--
		if srv.elapsed < time.Second*3 {
			srv.PlaylistIndex--
		}
		if srv.PlaylistIndex < 0 {
			srv.PlaylistIndex = 0
		}
		next()
	}
	pause = func() {
		log.Println("pause")
		switch srv.state {
		case statePause, stateStop:
			log.Println("pause: resume")
			t = make(chan interface{})
			close(t)
			tick()
			srv.state = statePlay
		case statePlay:
			log.Println("pause: pause")
			t = nil
			srv.state = statePause
		}
	}
	next = func() {
		log.Println("next")
		stop()
		play()
	}
	var forceNext = false
	stop = func() {
		log.Println("stop")
		srv.state = stateStop
		t = nil
		if srv.song != nil || forceNext {
			if srv.Random && len(srv.Queue) > 1 {
				n := srv.PlaylistIndex
				for n == srv.PlaylistIndex {
					n = rand.Intn(len(srv.Queue))
				}
				srv.PlaylistIndex = n
			} else {
				srv.PlaylistIndex++
			}
		}
		forceNext = false
		srv.song = nil
		srv.elapsed = 0
	}
	var inst protocol.Instance
	var sid SongID
	sendNext := func() {
		go func() {
			srv.ch <- cmdNext
		}()
	}
	nextOpen := time.After(0)
	tick = func() {
		const expected = 4096
		if false && srv.elapsed > srv.info.Time {
			log.Println("elapsed time completed", srv.elapsed, srv.info.Time)
			stop()
		}
		if srv.song == nil {
			<-nextOpen
			nextOpen = time.After(time.Second / 2)
			defer broadcast(waitStatus)
			if len(srv.Queue) == 0 {
				log.Println("empty queue")
				stop()
				return
			}
			if srv.PlaylistIndex >= len(srv.Queue) {
				if srv.Repeat {
					srv.PlaylistIndex = 0
				} else {
					log.Println("end of queue", srv.PlaylistIndex, len(srv.Queue))
					stop()
					return
				}
			}

			srv.songID = srv.Queue[srv.PlaylistIndex]
			sid = srv.songID
			if info := srv.songs[sid]; info == nil {
				broadcastErr(fmt.Errorf("unknown id: %v", sid))
				forceNext = true
				sendNext()
				return
			} else {
				srv.info = *info
			}
			inst = srv.Protocols[sid.Protocol()][sid.Key()]
			song, err := inst.GetSong(sid.ID())
			if err != nil {
				forceNext = true
				broadcastErr(err)
				sendNext()
				return
			}
			srv.song = song
			sr, ch, err := srv.song.Init()
			if err != nil {
				srv.song.Close()
				srv.song = nil
				broadcastErr(err)
				sendNext()
				return
			}
			o, err = output.Get(sr, ch)
			if err != nil {
				broadcastErr(fmt.Errorf("mog: could not open audio (%v, %v): %v", sr, ch, err))
				sendNext()
				return
			}
			srv.elapsed = 0
			dur = time.Second / (time.Duration(sr * ch))
			seek = NewSeek(srv.info.Time > 0, dur, srv.song.Play)
			log.Println("playing", srv.info.Title, sr, ch, dur, time.Duration(expected)*dur)
			t = make(chan interface{})
			close(t)
			srv.state = statePlay
		}
		next, err := seek.Read(expected)
		if err == nil {
			srv.elapsed = seek.Pos()
			if len(next) > 0 {
				o.Push(next)
			}
			select {
			case <-timer:
				// Check for updated song info.
				if info, err := inst.Info(sid.ID()); err != nil {
					broadcastErr(err)
				} else if srv.info != *info {
					srv.info = *info
					broadcast(waitStatus)
				}
				timer = nil
			default:
			}
			if timer == nil {
				timer = time.After(time.Second)
			}
		}
		if len(next) < expected || err != nil {
			log.Println("end of song", len(next), expected, err)
			if err == io.ErrUnexpectedEOF {
				log.Println("attempting to restart song")
				n := srv.PlaylistIndex
				stop()
				srv.PlaylistIndex = n
				play()
			} else {
				stop()
				play()
			}
		}
	}
	play = func() {
		log.Println("play")
		if srv.PlaylistIndex > len(srv.Queue) {
			srv.PlaylistIndex = 0
		}
		tick()
	}
	playIdx := func(c cmdPlayIdx) {
		stop()
		srv.PlaylistIndex = int(c)
		play()
	}
	refresh := func(c cmdRefresh) {
		for id := range srv.songs {
			if id.Protocol() == c.protocol && id.Key() == c.key {
				delete(srv.songs, id)
			}
		}
		for id, s := range c.songs {
			srv.songs[SongID(codec.NewID(c.protocol, c.key, string(id)))] = s
		}
		broadcast(waitTracks)
		broadcast(waitProtocols)
	}
	protocolRemove := func(c cmdProtocolRemove) {
		delete(c.prots, c.key)
		for id := range srv.songs {
			if id.Protocol() == c.protocol && id.Key() == c.key {
				delete(srv.songs, id)
			}
		}
		broadcast(waitTracks)
		broadcast(waitProtocols)
	}
	queueChange := func(c cmdQueueChange) {
		n, clear, err := srv.playlistChange(srv.Queue, PlaylistChange(c), true)
		if err != nil {
			broadcastErr(err)
			return
		}
		srv.Queue = n
		if clear || len(n) == 0 {
			stop()
			srv.PlaylistIndex = 0
		}
		broadcast(waitPlaylist)
	}
	playlistChange := func(c cmdPlaylistChange) {
		p := srv.Playlists[c.name]
		n, _, err := srv.playlistChange(p, c.plc, false)
		if err != nil {
			broadcastErr(err)
			return
		}
		if len(n) == 0 {
			delete(srv.Playlists, c.name)
		} else {
			srv.Playlists[c.name] = n
		}
		broadcast(waitPlaylist)
	}
	queueSave := func() {
		if srv.savePending {
			return
		}
		srv.savePending = true
		time.AfterFunc(time.Second, func() {
			srv.ch <- cmdDoSave{}
		})
	}
	doSave := func() {
		if err := srv.save(); err != nil {
			broadcastErr(err)
		}
	}
	addOAuth := func(c cmdAddOAuth) {
		prot, err := protocol.ByName(c.name)
		if err != nil {
			c.done <- err
			return
		}
		prots, ok := srv.Protocols[c.name]
		if !ok || prot.OAuth == nil {
			c.done <- fmt.Errorf("bad protocol")
			return
		}
		// TODO: decouple this from the audio thread
		t, err := prot.OAuth.Exchange(oauth2.NoContext, c.r.FormValue("code"))
		if err != nil {
			c.done <- err
			return
		}
		// "Bearer" was added for dropbox. It happens to work also with Google Music's
		// OAuth. This may need to be changed to be protocol-specific in the future.
		t.TokenType = "Bearer"
		instance, err := prot.NewInstance(nil, t)
		if err != nil {
			c.done <- err
			return
		}
		prots[t.AccessToken] = instance
		go srv.protocolRefresh(c.name, instance.Key(), false)
		c.done <- nil
	}
	doSeek := func(c cmdSeek) {
		if seek == nil {
			return
		}
		err := seek.Seek(time.Duration(c))
		if err != nil {
			broadcastErr(err)
		}
	}
	setMinDuration := func(c cmdMinDuration) {
		srv.MinDuration = time.Duration(c)
	}
	ch := make(chan interface{})
	go func() {
		for c := range srv.ch {
			timer := time.AfterFunc(time.Second*10, func() {
				panic("delay timer expired")
			})
			ch <- c
			timer.Stop()
		}
	}()
	for {
		select {
		case <-t:
			tick()
		case c := <-ch:
			save := true
			log.Printf("%T\n", c)
			switch c := c.(type) {
			case controlCmd:
				switch c {
				case cmdPlay:
					save = false
					play()
				case cmdStop:
					save = false
					stop()
				case cmdNext:
					next()
				case cmdPause:
					save = false
					pause()
				case cmdPrev:
					prev()
				case cmdRandom:
					srv.Random = !srv.Random
				case cmdRepeat:
					srv.Repeat = !srv.Repeat
				default:
					panic(c)
				}
			case cmdPlayIdx:
				playIdx(c)
			case cmdRefresh:
				refresh(c)
			case cmdProtocolRemove:
				protocolRemove(c)
			case cmdQueueChange:
				queueChange(c)
			case cmdPlaylistChange:
				playlistChange(c)
			case cmdNewWS:
				save = false
				newWS(c)
			case cmdDeleteWS:
				save = false
				deleteWS(c)
			case cmdDoSave:
				save = false
				doSave()
			case cmdAddOAuth:
				addOAuth(c)
			case cmdSeek:
				save = false
				doSeek(c)
			case cmdMinDuration:
				setMinDuration(c)
			default:
				panic(c)
			}
			broadcast(waitStatus)
			if save {
				queueSave()
			}
		}
	}
}

type controlCmd int

const (
	cmdUnknown controlCmd = iota
	cmdNext
	cmdPause
	cmdPlay
	cmdPrev
	cmdRandom
	cmdRepeat
	cmdStop
)

type cmdSeek time.Duration

type cmdPlayIdx int

type cmdRefresh struct {
	protocol, key string
	songs         protocol.SongList
}

type cmdProtocolRemove struct {
	protocol, key string
	prots         map[string]protocol.Instance
}

type cmdQueueChange PlaylistChange

type cmdPlaylistChange struct {
	plc  PlaylistChange
	name string
}

type cmdDoSave struct{}

type cmdAddOAuth struct {
	name string
	r    *http.Request
	done chan error
}

type cmdMinDuration time.Duration
<|endoftext|>


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

package server

import (
	"time"
)

// Command is a signal used to control a running gnatsd process.
type Command string

// Valid Command values.
const (
	CommandStop   = Command("stop")
	CommandQuit   = Command("quit")
	CommandReopen = Command("reopen")
	CommandReload = Command("reload")

	// private for now
	commandLDMode = Command("ldm")
)

var (
	// gitCommit injected at build
	gitCommit string
	// trustedKeys is a whitespace separated array of trusted operator's public nkeys.
	trustedKeys string
)

const (
	// VERSION is the current version for the server.
	VERSION = "2.0.0-RC10"

	// PROTO is the currently supported protocol.
	// 0 was the original
	// 1 maintains proto 0, adds echo abilities for CONNECT from the client. Clients
	// should not send echo unless proto in INFO is >= 1.
	PROTO = 1

	// DEFAULT_PORT is the default port for client connections.
	DEFAULT_PORT = 4222

	// RANDOM_PORT is the value for port that, when supplied, will cause the
	// server to listen on a randomly-chosen available port. The resolved port
	// is available via the Addr() method.
	RANDOM_PORT = -1

	// DEFAULT_HOST defaults to all interfaces.
	DEFAULT_HOST = "0.0.0.0"

	// MAX_CONTROL_LINE_SIZE is the maximum allowed protocol control line size.
	// 4k should be plenty since payloads sans connect/info string are separate.
	MAX_CONTROL_LINE_SIZE = 4096

	// MAX_PAYLOAD_SIZE is the maximum allowed payload size. Should be using
	// something different if > 1MB payloads are needed.
	MAX_PAYLOAD_SIZE = (1024 * 1024)

	// MAX_PENDING_SIZE is the maximum outbound pending bytes per client.
	MAX_PENDING_SIZE = (64 * 1024 * 1024)

	// DEFAULT_MAX_CONNECTIONS is the default maximum connections allowed.
	DEFAULT_MAX_CONNECTIONS = (64 * 1024)

	// TLS_TIMEOUT is the TLS wait time.
	TLS_TIMEOUT = 500 * time.Millisecond

	// AUTH_TIMEOUT is the authorization wait time.
	AUTH_TIMEOUT = 2 * TLS_TIMEOUT

	// DEFAULT_PING_INTERVAL is how often pings are sent to clients and routes.
	DEFAULT_PING_INTERVAL = 2 * time.Minute

	// DEFAULT_PING_MAX_OUT is maximum allowed pings outstanding before disconnect.
	DEFAULT_PING_MAX_OUT = 2

	// CR_LF string
	CR_LF = "\r\n"

	// LEN_CR_LF hold onto the computed size.
	LEN_CR_LF = len(CR_LF)

	// DEFAULT_FLUSH_DEADLINE is the write/flush deadlines.
	DEFAULT_FLUSH_DEADLINE = 2 * time.Second

	// DEFAULT_HTTP_PORT is the default monitoring port.
	DEFAULT_HTTP_PORT = 8222

	// ACCEPT_MIN_SLEEP is the minimum acceptable sleep times on temporary errors.
	ACCEPT_MIN_SLEEP = 10 * time.Millisecond

	// ACCEPT_MAX_SLEEP is the maximum acceptable sleep times on temporary errors
	ACCEPT_MAX_SLEEP = 1 * time.Second

	// DEFAULT_ROUTE_CONNECT Route solicitation intervals.
	DEFAULT_ROUTE_CONNECT = 1 * time.Second

	// DEFAULT_ROUTE_RECONNECT Route reconnect intervals.
	DEFAULT_ROUTE_RECONNECT = 1 * time.Second

	// DEFAULT_ROUTE_DIAL Route dial timeout.
	DEFAULT_ROUTE_DIAL = 1 * time.Second

	// DEFAULT_LEAF_NODE_RECONNECT LeafNode reconnect interval.
	DEFAULT_LEAF_NODE_RECONNECT = time.Second

	// PROTO_SNIPPET_SIZE is the default size of proto to print on parse errors.
	PROTO_SNIPPET_SIZE = 32

	// MAX_MSG_ARGS Maximum possible number of arguments from MSG proto.
	MAX_MSG_ARGS = 4

	// MAX_PUB_ARGS Maximum possible number of arguments from PUB proto.
	MAX_PUB_ARGS = 3

	// DEFAULT_MAX_CLOSED_CLIENTS is the maximum number of closed connections we hold onto.
	DEFAULT_MAX_CLOSED_CLIENTS = 10000

	// DEFAULT_MAX_ACCOUNT_AE_RESPONSE_MAPS is for auto-expire response maps for imports.
	DEFAULT_MAX_ACCOUNT_AE_RESPONSE_MAPS = 100000

	// DEFAULT_TTL_AE_RESPONSE_MAP is the default time to expire auto-response map entries.
	DEFAULT_TTL_AE_RESPONSE_MAP = 10 * time.Minute

	// DEFAULT_LAME_DUCK_DURATION is the time in which the server spreads
	// the closing of clients when signaled to go in lame duck mode.
	DEFAULT_LAME_DUCK_DURATION = 2 * time.Minute

	// DEFAULT_LEAFNODE_INFO_WAIT Route dial timeout.
	DEFAULT_LEAFNODE_INFO_WAIT = 1 * time.Second
)
<commit_msg>Bump to RC11 [ci skip]<commit_after>// Copyright 2012-2019 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import (
	"time"
)

// Command is a signal used to control a running gnatsd process.
type Command string

// Valid Command values.
const (
	CommandStop   = Command("stop")
	CommandQuit   = Command("quit")
	CommandReopen = Command("reopen")
	CommandReload = Command("reload")

	// private for now
	commandLDMode = Command("ldm")
)

var (
	// gitCommit injected at build
	gitCommit string
	// trustedKeys is a whitespace separated array of trusted operator's public nkeys.
	trustedKeys string
)

const (
	// VERSION is the current version for the server.
	VERSION = "2.0.0-RC11"

	// PROTO is the currently supported protocol.
	// 0 was the original
	// 1 maintains proto 0, adds echo abilities for CONNECT from the client. Clients
	// should not send echo unless proto in INFO is >= 1.
	PROTO = 1

	// DEFAULT_PORT is the default port for client connections.
	DEFAULT_PORT = 4222

	// RANDOM_PORT is the value for port that, when supplied, will cause the
	// server to listen on a randomly-chosen available port. The resolved port
	// is available via the Addr() method.
	RANDOM_PORT = -1

	// DEFAULT_HOST defaults to all interfaces.
	DEFAULT_HOST = "0.0.0.0"

	// MAX_CONTROL_LINE_SIZE is the maximum allowed protocol control line size.
	// 4k should be plenty since payloads sans connect/info string are separate.
	MAX_CONTROL_LINE_SIZE = 4096

	// MAX_PAYLOAD_SIZE is the maximum allowed payload size. Should be using
	// something different if > 1MB payloads are needed.
	MAX_PAYLOAD_SIZE = (1024 * 1024)

	// MAX_PENDING_SIZE is the maximum outbound pending bytes per client.
	MAX_PENDING_SIZE = (64 * 1024 * 1024)

	// DEFAULT_MAX_CONNECTIONS is the default maximum connections allowed.
	DEFAULT_MAX_CONNECTIONS = (64 * 1024)

	// TLS_TIMEOUT is the TLS wait time.
	TLS_TIMEOUT = 500 * time.Millisecond

	// AUTH_TIMEOUT is the authorization wait time.
	AUTH_TIMEOUT = 2 * TLS_TIMEOUT

	// DEFAULT_PING_INTERVAL is how often pings are sent to clients and routes.
	DEFAULT_PING_INTERVAL = 2 * time.Minute

	// DEFAULT_PING_MAX_OUT is maximum allowed pings outstanding before disconnect.
	DEFAULT_PING_MAX_OUT = 2

	// CR_LF string
	CR_LF = "\r\n"

	// LEN_CR_LF hold onto the computed size.
	LEN_CR_LF = len(CR_LF)

	// DEFAULT_FLUSH_DEADLINE is the write/flush deadlines.
	DEFAULT_FLUSH_DEADLINE = 2 * time.Second

	// DEFAULT_HTTP_PORT is the default monitoring port.
	DEFAULT_HTTP_PORT = 8222

	// ACCEPT_MIN_SLEEP is the minimum acceptable sleep times on temporary errors.
	ACCEPT_MIN_SLEEP = 10 * time.Millisecond

	// ACCEPT_MAX_SLEEP is the maximum acceptable sleep times on temporary errors
	ACCEPT_MAX_SLEEP = 1 * time.Second

	// DEFAULT_ROUTE_CONNECT Route solicitation intervals.
	DEFAULT_ROUTE_CONNECT = 1 * time.Second

	// DEFAULT_ROUTE_RECONNECT Route reconnect intervals.
	DEFAULT_ROUTE_RECONNECT = 1 * time.Second

	// DEFAULT_ROUTE_DIAL Route dial timeout.
	DEFAULT_ROUTE_DIAL = 1 * time.Second

	// DEFAULT_LEAF_NODE_RECONNECT LeafNode reconnect interval.
	DEFAULT_LEAF_NODE_RECONNECT = time.Second

	// PROTO_SNIPPET_SIZE is the default size of proto to print on parse errors.
	PROTO_SNIPPET_SIZE = 32

	// MAX_MSG_ARGS Maximum possible number of arguments from MSG proto.
	MAX_MSG_ARGS = 4

	// MAX_PUB_ARGS Maximum possible number of arguments from PUB proto.
	MAX_PUB_ARGS = 3

	// DEFAULT_MAX_CLOSED_CLIENTS is the maximum number of closed connections we hold onto.
	DEFAULT_MAX_CLOSED_CLIENTS = 10000

	// DEFAULT_MAX_ACCOUNT_AE_RESPONSE_MAPS is for auto-expire response maps for imports.
	DEFAULT_MAX_ACCOUNT_AE_RESPONSE_MAPS = 100000

	// DEFAULT_TTL_AE_RESPONSE_MAP is the default time to expire auto-response map entries.
	DEFAULT_TTL_AE_RESPONSE_MAP = 10 * time.Minute

	// DEFAULT_LAME_DUCK_DURATION is the time in which the server spreads
	// the closing of clients when signaled to go in lame duck mode.
	DEFAULT_LAME_DUCK_DURATION = 2 * time.Minute

	// DEFAULT_LEAFNODE_INFO_WAIT Route dial timeout.
	DEFAULT_LEAFNODE_INFO_WAIT = 1 * time.Second
)
<|endoftext|>


<commit_before>package todolist

import (
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type Parser struct {
	input string
}

func (p Parser) ParseNewTodo() *Todo {
	todo := NewTodo()
	todo.Subject = p.Subject()
	todo.Projects = p.Projects()
	todo.Contexts = p.Contexts()
	if p.hasDue() {
		todo.Due = p.Due(time.Now())
	}
	return todo
}

func (p Parser) parseId() int {
	r := regexp.MustCompile(`(\d+)`)
	matches := r.FindStringSubmatch(p.input)
	if len(matches) == 0 {
		fmt.Println("Could not match id")
		return -1
	}
	id, err := strconv.Atoi(matches[1])
	if err != nil {
		fmt.Println("Invalid id.")
		return -1
	}
	return id
}

func (p Parser) parseSubject() string {
	r := regexp.MustCompile(`(\d+) (.*)`)
	matches := r.FindStringSubmatch(p.input)
	if len(matches) < 3 {
		return ""
	}
	return matches[2]
}

func (p Parser) Parse() (int, string) {

	id := p.parseId()
	subject := p.parseSubject()

	return id, subject
}

func (p Parser) Subject() string {
	if strings.Contains(p.input, " due") {
		index := strings.LastIndex(p.input, " due")
		return p.input[0:index]
	} else {
		return p.input
	}
}

func (p Parser) ExpandProject(input string) string {
	r := regexp.MustCompile(`(\+[\p{L}\d_-]+):`)
	matches := r.FindStringSubmatch(input)
	if len(matches) < 2 {
		return ""
	}

	return matches[1]
}

func (p Parser) Projects() []string {
	r := regexp.MustCompile(`\+[\p{L}\d_-]+`)
	return p.matchWords(p.input, r)
}

func (p Parser) Contexts() []string {
	r := regexp.MustCompile(`\@[\p{L}\d_]+`)
	return p.matchWords(p.input, r)
}

func (p Parser) hasDue() bool {
	r1 := regexp.MustCompile(`due \w+$`)
	r2 := regexp.MustCompile(`due \w+ \d+$`)
	return (r1.MatchString(p.input) || r2.MatchString(p.input))
}

func (p Parser) Due(day time.Time) string {
	r := regexp.MustCompile(`due (.*$)`)
	matches := r.FindStringSubmatch(p.input)

	if len(matches) < 2 {
		return ""
	}

	switch matches[1] {
	case "none":
		return ""
	case "today", "tod":
		return bod(time.Now()).Format("2006-01-02")
	case "tomorrow", "tom":
		return bod(time.Now()).AddDate(0, 0, 1).Format("2006-01-02")
	case "monday", "mon":
		return p.monday(day)
	case "tuesday", "tue":
		return p.tuesday(day)
	case "wednesday", "wed":
		return p.wednesday(day)
	case "thursday", "thu":
		return p.thursday(day)
	case "friday", "fri":
		return p.friday(day)
	case "saturday", "sat":
		return p.saturday(day)
	case "sunday", "sun":
		return p.sunday(day)
	case "last week":
		n := bod(time.Now())
		return getNearestMonday(n).AddDate(0, 0, -7).Format("2006-01-02")
	case "next week":
		n := bod(time.Now())
		return getNearestMonday(n).AddDate(0, 0, 7).Format("2006-01-02")
	}
	return p.parseArbitraryDate(matches[1], time.Now())
}

func (p Parser) parseArbitraryDate(_date string, pivot time.Time) string {
	d1 := p.parseArbitraryDateWithYear(_date, pivot.Year())

	var diff1 time.Duration
	if d1.After(time.Now()) {
		diff1 = d1.Sub(pivot)
	} else {
		diff1 = pivot.Sub(d1)
	}
	d2 := p.parseArbitraryDateWithYear(_date, pivot.Year()+1)
	if d2.Sub(pivot) > diff1 {
		return d1.Format("2006-01-02")
	} else {
		return d2.Format("2006-01-02")
	}
}

func (p Parser) parseArbitraryDateWithYear(_date string, year int) time.Time {
	res := strings.Join([]string{_date, strconv.Itoa(year)}, " ")
	if date, err := time.Parse("Jan 2 2006", res); err == nil {
		return date
	}

	if date, err := time.Parse("2 Jan 2006", res); err == nil {
		return date
	}
	fmt.Printf("Could not parse the date you gave me: %s\n", _date)
	fmt.Println("I'm expecting a date like \"Dec 22\" or \"22 Dec\".")
	fmt.Println("See http://todolist.site/#adding for more info.")
	os.Exit(-1)
	return time.Now()
}

func (p Parser) monday(day time.Time) string {
	mon := getNearestMonday(day)
	return p.thisOrNextWeek(mon, day)
}

func (p Parser) tuesday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 1)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) wednesday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 2)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) thursday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 3)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) friday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 4)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) saturday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 5)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) sunday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 6)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) thisOrNextWeek(day time.Time, pivotDay time.Time) string {
	if day.Before(pivotDay) {
		return day.AddDate(0, 0, 7).Format("2006-01-02")
	} else {
		return day.Format("2006-01-02")
	}
}

func (p Parser) matchWords(input string, r *regexp.Regexp) []string {
	results := r.FindAllString(input, -1)
	ret := []string{}

	for _, val := range results {
		ret = append(ret, val[1:])
	}
	return ret
}
<commit_msg>wip parse datetime other<commit_after>package todolist

import (
	"errors"
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/gammons/todolist/weekdayer"
)

type Parser struct {
	input string
}

func (p Parser) ParseNewTodo() *Todo {
	todo := NewTodo()
	todo.Subject = p.Subject()
	todo.Projects = p.Projects()
	todo.Contexts = p.Contexts()
	if p.hasDue() {
		todo.Due = p.Due(time.Now())
	}
	return todo
}

func (p Parser) parseId() int {
	r := regexp.MustCompile(`(\d+)`)
	matches := r.FindStringSubmatch(p.input)
	if len(matches) == 0 {
		fmt.Println("Could not match id")
		return -1
	}
	id, err := strconv.Atoi(matches[1])
	if err != nil {
		fmt.Println("Invalid id.")
		return -1
	}
	return id
}

func (p Parser) parseSubject() string {
	r := regexp.MustCompile(`(\d+) (.*)`)
	matches := r.FindStringSubmatch(p.input)
	if len(matches) < 3 {
		return ""
	}
	return matches[2]
}

func (p Parser) Parse() (int, string) {

	id := p.parseId()
	subject := p.parseSubject()

	return id, subject
}

func (p Parser) Subject() string {
	if strings.Contains(p.input, " due") {
		index := strings.LastIndex(p.input, " due")
		return p.input[0:index]
	} else {
		return p.input
	}
}

func (p Parser) ExpandProject(input string) string {
	r := regexp.MustCompile(`(\+[\p{L}\d_-]+):`)
	matches := r.FindStringSubmatch(input)
	if len(matches) < 2 {
		return ""
	}

	return matches[1]
}

func (p Parser) Projects() []string {
	r := regexp.MustCompile(`\+[\p{L}\d_-]+`)
	return p.matchWords(p.input, r)
}

func (p Parser) Contexts() []string {
	r := regexp.MustCompile(`\@[\p{L}\d_]+`)
	return p.matchWords(p.input, r)
}

func (p Parser) hasDue() bool {
	r1 := regexp.MustCompile(`due \w+$`)
	r2 := regexp.MustCompile(`due \w+ \d+$`)
	return (r1.MatchString(p.input) || r2.MatchString(p.input))
}

type withoutDate error

func (p Parser) dueDate(pivot time.Time) (*time.Time, error) {
	r := regexp.MustCompile(`/w*due/w+(.*)$`)
	matches := r.FindStringSubmatch(p.input)

	if len(matches) < 2 {
		return nil, withoutDate(errors.New("withoutDate"))
	}

	input := matches[1]

	date, err := weekdayer.English(input, time.Now())
	return &date, nil
}

func (p Parser) Due(day time.Time) string {
	r := regexp.MustCompile(`due (.*)$`)
	matches := r.FindStringSubmatch(p.input)

	if len(matches) < 2 {
		return ""
	}

	switch matches[1] {
	case "none":
		return ""
	case "today", "tod":
		return bod(time.Now()).Format("2006-01-02")
	case "tomorrow", "tom":
		return bod(time.Now()).AddDate(0, 0, 1).Format("2006-01-02")
	case "monday", "mon":
		return p.monday(day)
	case "tuesday", "tue":
		return p.tuesday(day)
	case "wednesday", "wed":
		return p.wednesday(day)
	case "thursday", "thu":
		return p.thursday(day)
	case "friday", "fri":
		return p.friday(day)
	case "saturday", "sat":
		return p.saturday(day)
	case "sunday", "sun":
		return p.sunday(day)
	case "last week":
		n := bod(time.Now())
		return getNearestMonday(n).AddDate(0, 0, -7).Format("2006-01-02")
	case "next week":
		n := bod(time.Now())
		return getNearestMonday(n).AddDate(0, 0, 7).Format("2006-01-02")
	}
	return p.parseArbitraryDate(matches[1], time.Now())
}

func (p Parser) parseArbitraryDate(_date string, pivot time.Time) string {
	d1 := p.parseArbitraryDateWithYear(_date, pivot.Year())

	var diff1 time.Duration
	if d1.After(time.Now()) {
		diff1 = d1.Sub(pivot)
	} else {
		diff1 = pivot.Sub(d1)
	}
	d2 := p.parseArbitraryDateWithYear(_date, pivot.Year()+1)
	if d2.Sub(pivot) > diff1 {
		return d1.Format("2006-01-02")
	} else {
		return d2.Format("2006-01-02")
	}
}

func (p Parser) parseArbitraryDateWithYear(_date string, year int) time.Time {
	res := strings.Join([]string{_date, strconv.Itoa(year)}, " ")
	if date, err := time.Parse("Jan 2 2006", res); err == nil {
		return date
	}

	if date, err := time.Parse("2 Jan 2006", res); err == nil {
		return date
	}
	fmt.Printf("Could not parse the date you gave me: %s\n", _date)
	fmt.Println("I'm expecting a date like \"Dec 22\" or \"22 Dec\".")
	fmt.Println("See http://todolist.site/#adding for more info.")
	os.Exit(-1)
	return time.Now()
}

func (p Parser) monday(day time.Time) string {
	mon := getNearestMonday(day)
	return p.thisOrNextWeek(mon, day)
}

func (p Parser) tuesday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 1)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) wednesday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 2)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) thursday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 3)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) friday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 4)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) saturday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 5)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) sunday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 6)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) thisOrNextWeek(day time.Time, pivotDay time.Time) string {
	if day.Before(pivotDay) {
		return day.AddDate(0, 0, 7).Format("2006-01-02")
	} else {
		return day.Format("2006-01-02")
	}
}

func (p Parser) matchWords(input string, r *regexp.Regexp) []string {
	results := r.FindAllString(input, -1)
	ret := []string{}

	for _, val := range results {
		ret = append(ret, val[1:])
	}
	return ret
}
<|endoftext|>


<commit_before>// bb converts standalone u-root tools to shell builtins.
package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"reflect"
)

func x(a string, b string,) {
}

func main() {
	// src is the input for which we want to inspect the AST.
	src := `
package p
const c = 1.0
var X = f(3.14)*2 + c
func main(s string) {
}
`

	// Create the AST by parsing src.
	fset := token.NewFileSet() // positions are relative to fset
	f, err := parser.ParseFile(fset, "src.go", src, 0)
	if err != nil {
		panic(err)
	}

	// Inspect the AST and print all identifiers and literals.
	ast.Inspect(f, func(n ast.Node) bool {
		var s string
		switch x := n.(type) {
		case *ast.BasicLit:
			s = x.Value
		case *ast.FuncDecl:
			s = fmt.Sprintf("%v", reflect.TypeOf(x.Type.Params.List[0].Type))
			if x.Name.Name == "main" {
				x.Name.Name = "cat"
				x.Type.Params.List = append(x.Type.Params.List, &ast.Field{Names: []*ast.Ident{&ast.Ident{Name:"a"}}, Type: &ast.Ident{Name: "string",}})
			}
		}
		if s != "" {
			fmt.Printf("%s:\t%s\n", fset.Position(n.Pos()), s)
		}
		return true
	})
	var buf bytes.Buffer
	if err := format.Node(&buf, fset, f); err != nil {
		panic(err)
	}
	fmt.Printf("%s", buf.Bytes())

}
<commit_msg>Rewriting all args.<commit_after>// bb converts standalone u-root tools to shell builtins.
package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"reflect"
)

func x(a string, b string,) {
}

func main() {
	// src is the input for which we want to inspect the AST.
	src := `
package p
const c = 1.0
var X = f(3.14)*2 + c
func main(s string) {
}
`

	// Create the AST by parsing src.
	fset := token.NewFileSet() // positions are relative to fset
	f, err := parser.ParseFile(fset, "src.go", src, 0)
	if err != nil {
		panic(err)
	}

	// Inspect the AST and print all identifiers and literals.
	ast.Inspect(f, func(n ast.Node) bool {
		var s string
		switch x := n.(type) {
		case *ast.BasicLit:
			s = x.Value
		case *ast.FuncDecl:
			s = fmt.Sprintf("%v", reflect.TypeOf(x.Type.Params.List[0].Type))
			if x.Name.Name == "main" {
				x.Name.Name = "cat"
				x.Type.Params.List = []*ast.Field{ &ast.Field{Names: []*ast.Ident{&ast.Ident{Name:"a"}}, Type: &ast.Ident{Name: "string",}}}
			}
		}
		if s != "" {
			fmt.Printf("%s:\t%s\n", fset.Position(n.Pos()), s)
		}
		return true
	})
	var buf bytes.Buffer
	if err := format.Node(&buf, fset, f); err != nil {
		panic(err)
	}
	fmt.Printf("%s", buf.Bytes())

}
<|endoftext|>


<commit_before>package todolist

import (
	"errors"
	"fmt"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/gammons/todolist/weekdays"
)

type Parser struct {
	input string
}

func (p Parser) ParseNewTodo() *Todo {
	todo := NewTodo()
	todo.Subject = p.Subject()
	todo.Projects = p.Projects()
	todo.Contexts = p.Contexts()
	if p.hasDue() {
		todo.Due = p.Due(time.Now())
	}
	return todo
}

func (p Parser) parseId() int {
	r := regexp.MustCompile(`(\d+)`)
	matches := r.FindStringSubmatch(p.input)
	if len(matches) == 0 {
		fmt.Println("Could not match id")
		return -1
	}
	id, err := strconv.Atoi(matches[1])
	if err != nil {
		fmt.Println("Invalid id.")
		return -1
	}
	return id
}

func (p Parser) parseSubject() string {
	r := regexp.MustCompile(`(\d+) (.*)`)
	matches := r.FindStringSubmatch(p.input)
	if len(matches) < 3 {
		return ""
	}
	return matches[2]
}

func (p Parser) Parse() (int, string) {

	id := p.parseId()
	subject := p.parseSubject()

	return id, subject
}

func (p Parser) Subject() string {
	if strings.Contains(p.input, " due") {
		index := strings.LastIndex(p.input, " due")
		return p.input[0:index]
	} else {
		return p.input
	}
}

func (p Parser) ExpandProject(input string) string {
	r := regexp.MustCompile(`(\+[\p{L}\d_-]+):`)
	matches := r.FindStringSubmatch(input)
	if len(matches) < 2 {
		return ""
	}

	return matches[1]
}

func (p Parser) Projects() []string {
	r := regexp.MustCompile(`\+[\p{L}\d_-]+`)
	return p.matchWords(p.input, r)
}

func (p Parser) Contexts() []string {
	r := regexp.MustCompile(`\@[\p{L}\d_]+`)
	return p.matchWords(p.input, r)
}

func (p Parser) hasDue() bool {
	r1 := regexp.MustCompile(`due \w+$`)
	r2 := regexp.MustCompile(`due \w+ \d+$`)
	return (r1.MatchString(p.input) || r2.MatchString(p.input))
}

type withoutDate error

func (p Parser) dueDate(pivot time.Time) (*time.Time, error) {
	r := regexp.MustCompile(`/w*due/w+(.*)$`)
	matches := r.FindStringSubmatch(p.input)

	if len(matches) < 2 {
		return nil, withoutDate(errors.New("withoutDate"))
	}

	input := matches[1]

	date, err := weekdays.English(input, time.Now()).Weekday()
	if err != nil {
		log.Println(err)
		return &date, err
	}

	return &date, nil
}

func (p Parser) Due(day time.Time) string {
	r := regexp.MustCompile(`due (.*)$`)
	matches := r.FindStringSubmatch(p.input)

	if len(matches) < 2 {
		return ""
	}

	switch matches[1] {
	case "none":
		return ""
	case "today", "tod":
		bod := bod(day).Format("2006-01-02")
		return bod
	case "tomorrow", "tom":
		tom := day.AddDate(0, 0, 1)
		return bod(tom).Format("2006-01-02")
	case "monday", "mon":
		return p.monday(day)
	case "tuesday", "tue":
		return p.tuesday(day)
	case "wednesday", "wed":
		return p.wednesday(day)
	case "thursday", "thu":
		return p.thursday(day)
	case "friday", "fri":
		return p.friday(day)
	case "saturday", "sat":
		return p.saturday(day)
	case "sunday", "sun":
		return p.sunday(day)
	case "last week":
		n := bod(time.Now())
		return getNearestMonday(n).AddDate(0, 0, -7).Format("2006-01-02")
	case "next week":
		n := bod(time.Now())
		return getNearestMonday(n).AddDate(0, 0, 7).Format("2006-01-02")
	}
	return p.parseArbitraryDate(matches[1], time.Now())
}

func (p Parser) parseArbitraryDate(_date string, pivot time.Time) string {
	d1 := p.parseArbitraryDateWithYear(_date, pivot.Year())

	var diff1 time.Duration
	if d1.After(time.Now()) {
		diff1 = d1.Sub(pivot)
	} else {
		diff1 = pivot.Sub(d1)
	}
	d2 := p.parseArbitraryDateWithYear(_date, pivot.Year()+1)
	if d2.Sub(pivot) > diff1 {
		return d1.Format("2006-01-02")
	} else {
		return d2.Format("2006-01-02")
	}
}

func (p Parser) parseArbitraryDateWithYear(_date string, year int) time.Time {
	res := strings.Join([]string{_date, strconv.Itoa(year)}, " ")
	if date, err := time.Parse("Jan 2 2006", res); err == nil {
		return date
	}

	if date, err := time.Parse("2 Jan 2006", res); err == nil {
		return date
	}
	fmt.Printf("Could not parse the date you gave me: %s\n", _date)
	fmt.Println("I'm expecting a date like \"Dec 22\" or \"22 Dec\".")
	fmt.Println("See http://todolist.site/#adding for more info.")
	os.Exit(-1)
	return time.Now()
}

func (p Parser) monday(day time.Time) string {
	mon := getNearestMonday(day)
	return p.thisOrNextWeek(mon, day)
}

func (p Parser) tuesday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 1)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) wednesday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 2)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) thursday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 3)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) friday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 4)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) saturday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 5)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) sunday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 6)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) thisOrNextWeek(day time.Time, pivotDay time.Time) string {
	if day.Before(pivotDay) {
		return day.AddDate(0, 0, 7).Format("2006-01-02")
	} else {
		return day.Format("2006-01-02")
	}
}

func (p Parser) matchWords(input string, r *regexp.Regexp) []string {
	results := r.FindAllString(input, -1)
	ret := []string{}

	for _, val := range results {
		ret = append(ret, val[1:])
	}
	return ret
}
<commit_msg>simplify regexp for now<commit_after>package todolist

import (
	"errors"
	"fmt"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/gammons/todolist/weekdays"
)

type Parser struct {
	input string
}

func (p Parser) ParseNewTodo() *Todo {
	todo := NewTodo()
	todo.Subject = p.Subject()
	todo.Projects = p.Projects()
	todo.Contexts = p.Contexts()
	if p.hasDue() {
		todo.Due = p.Due(time.Now())
	}
	return todo
}

func (p Parser) parseId() int {
	r := regexp.MustCompile(`(\d+)`)
	matches := r.FindStringSubmatch(p.input)
	if len(matches) == 0 {
		fmt.Println("Could not match id")
		return -1
	}
	id, err := strconv.Atoi(matches[1])
	if err != nil {
		fmt.Println("Invalid id.")
		return -1
	}
	return id
}

func (p Parser) parseSubject() string {
	r := regexp.MustCompile(`(\d+) (.*)`)
	matches := r.FindStringSubmatch(p.input)
	if len(matches) < 3 {
		return ""
	}
	return matches[2]
}

func (p Parser) Parse() (int, string) {

	id := p.parseId()
	subject := p.parseSubject()

	return id, subject
}

func (p Parser) Subject() string {
	if strings.Contains(p.input, " due") {
		index := strings.LastIndex(p.input, " due")
		return p.input[0:index]
	} else {
		return p.input
	}
}

func (p Parser) ExpandProject(input string) string {
	r := regexp.MustCompile(`(\+[\p{L}\d_-]+):`)
	matches := r.FindStringSubmatch(input)
	if len(matches) < 2 {
		return ""
	}

	return matches[1]
}

func (p Parser) Projects() []string {
	r := regexp.MustCompile(`\+[\p{L}\d_-]+`)
	return p.matchWords(p.input, r)
}

func (p Parser) Contexts() []string {
	r := regexp.MustCompile(`\@[\p{L}\d_]+`)
	return p.matchWords(p.input, r)
}

func (p Parser) hasDue() bool {
	r1 := regexp.MustCompile(`due \w+$`)
	r2 := regexp.MustCompile(`due \w+ \d+$`)
	return (r1.MatchString(p.input) || r2.MatchString(p.input))
}

type withoutDate error

func (p Parser) dueDate(pivot time.Time) (*time.Time, error) {
	r := regexp.MustCompile(`due (.*)$`)
	matches := r.FindStringSubmatch(p.input)

	if len(matches) < 2 {
		return nil, withoutDate(errors.New("withoutDate"))
	}

	input := matches[1]

	date, err := weekdays.English(input, time.Now()).Weekday()
	if err != nil {
		log.Println(err)
		return &date, err
	}

	return &date, nil
}

func (p Parser) Due(day time.Time) string {
	r := regexp.MustCompile(`due (.*)$`)
	matches := r.FindStringSubmatch(p.input)

	if len(matches) < 2 {
		return ""
	}

	switch matches[1] {
	case "none":
		return ""
	case "today", "tod":
		bod := bod(day).Format("2006-01-02")
		return bod
	case "tomorrow", "tom":
		tom := day.AddDate(0, 0, 1)
		return bod(tom).Format("2006-01-02")
	case "monday", "mon":
		return p.monday(day)
	case "tuesday", "tue":
		return p.tuesday(day)
	case "wednesday", "wed":
		return p.wednesday(day)
	case "thursday", "thu":
		return p.thursday(day)
	case "friday", "fri":
		return p.friday(day)
	case "saturday", "sat":
		return p.saturday(day)
	case "sunday", "sun":
		return p.sunday(day)
	case "last week":
		n := bod(time.Now())
		return getNearestMonday(n).AddDate(0, 0, -7).Format("2006-01-02")
	case "next week":
		n := bod(time.Now())
		return getNearestMonday(n).AddDate(0, 0, 7).Format("2006-01-02")
	}
	return p.parseArbitraryDate(matches[1], time.Now())
}

func (p Parser) parseArbitraryDate(_date string, pivot time.Time) string {
	d1 := p.parseArbitraryDateWithYear(_date, pivot.Year())

	var diff1 time.Duration
	if d1.After(time.Now()) {
		diff1 = d1.Sub(pivot)
	} else {
		diff1 = pivot.Sub(d1)
	}
	d2 := p.parseArbitraryDateWithYear(_date, pivot.Year()+1)
	if d2.Sub(pivot) > diff1 {
		return d1.Format("2006-01-02")
	} else {
		return d2.Format("2006-01-02")
	}
}

func (p Parser) parseArbitraryDateWithYear(_date string, year int) time.Time {
	res := strings.Join([]string{_date, strconv.Itoa(year)}, " ")
	if date, err := time.Parse("Jan 2 2006", res); err == nil {
		return date
	}

	if date, err := time.Parse("2 Jan 2006", res); err == nil {
		return date
	}
	fmt.Printf("Could not parse the date you gave me: %s\n", _date)
	fmt.Println("I'm expecting a date like \"Dec 22\" or \"22 Dec\".")
	fmt.Println("See http://todolist.site/#adding for more info.")
	os.Exit(-1)
	return time.Now()
}

func (p Parser) monday(day time.Time) string {
	mon := getNearestMonday(day)
	return p.thisOrNextWeek(mon, day)
}

func (p Parser) tuesday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 1)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) wednesday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 2)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) thursday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 3)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) friday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 4)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) saturday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 5)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) sunday(day time.Time) string {
	tue := getNearestMonday(day).AddDate(0, 0, 6)
	return p.thisOrNextWeek(tue, day)
}

func (p Parser) thisOrNextWeek(day time.Time, pivotDay time.Time) string {
	if day.Before(pivotDay) {
		return day.AddDate(0, 0, 7).Format("2006-01-02")
	} else {
		return day.Format("2006-01-02")
	}
}

func (p Parser) matchWords(input string, r *regexp.Regexp) []string {
	results := r.FindAllString(input, -1)
	ret := []string{}

	for _, val := range results {
		ret = append(ret, val[1:])
	}
	return ret
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/cumulodev/nimbusec"
)

func main() {

	apiUrlPtr := flag.String("url", nimbusec.DefaultAPI, "API Url")
	apiKeyPtr := flag.String("key", "abc", "API key for authentication")
	apiSecretPtr := flag.String("secret", "abc", "API secret for authentication")
	filePtr := flag.String("file", "import.csv", "path to import file")
	flag.Parse()

	api, err := nimbusec.NewAPI(*apiUrlPtr, *apiKeyPtr, *apiSecretPtr)
	if err != nil {
		log.Fatal(err)
	}

	/*
	 * READ CSV FILE
	 */
	importfile, err := os.Open(*filePtr)
	if err != nil {
		log.Fatal(err)
	}

	defer importfile.Close()
	reader := csv.NewReader(importfile)
	reader.FieldsPerRecord = -1 // see the Reader struct information below
	rawCSVdata, err := reader.ReadAll()
	if err != nil {
		log.Fatal(err)
	}

	// BUILD MAP WITH NEW DOMAINS
	ref := make(map[string]struct{})

	for _, each := range rawCSVdata {
		url := each[0]
		scheme := each[1]
		bundle := each[2]

		// BUILD REF
		ref[url] = struct{}{}

		// ADD DOMAIN TO SET
		domain := &nimbusec.Domain{
			Name:      url,
			Bundle:    bundle,
			Scheme:    scheme,
			DeepScan:  scheme + "://" + url,
			FastScans: []string{scheme + "://" + url},
		}

		// UPSERT DOMAIN
		fmt.Printf("UPSERT DOMAIN: %+v\n", domain)
		_, err := api.CreateOrUpdateDomain(domain)
		if err != nil {
			log.Fatal(err)
		}

	}

	// READ ALL DOMAINS FROM API
	currDomains, err := api.FindDomains(nimbusec.EmptyFilter)
	if err != nil {
		log.Fatal(err)
	}

	// SYNC
	// DELETE DOMAINS NOT LISTED IN NEW SET
	for _, d := range currDomains {
		if _, ok := ref[d.Name]; !ok {
			fmt.Println("I would now delete Domain " + d.Name)
			//api.DeleteDomain(d,true)

		}
	}
}
<commit_msg>added flag to choose to delete domains and results that are not listed in the import CSV<commit_after>package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/cumulodev/nimbusec"
)

func main() {

	apiUrlPtr := flag.String("url", nimbusec.DefaultAPI, "API Url")
	apiKeyPtr := flag.String("key", "abc", "API key for authentication")
	apiSecretPtr := flag.String("secret", "abc", "API secret for authentication")
	filePtr := flag.String("file", "import.csv", "path to import file")
	shouldDelete := flag.Bool("delete", true, "delete domains from nimbusec if not provided in the CSV")
	flag.Parse()

	api, err := nimbusec.NewAPI(*apiUrlPtr, *apiKeyPtr, *apiSecretPtr)
	if err != nil {
		log.Fatal(err)
	}

	/*
	 * READ CSV FILE
	 */
	importfile, err := os.Open(*filePtr)
	if err != nil {
		log.Fatal(err)
	}

	defer importfile.Close()
	reader := csv.NewReader(importfile)
	reader.FieldsPerRecord = -1 // see the Reader struct information below
	rawCSVdata, err := reader.ReadAll()
	if err != nil {
		log.Fatal(err)
	}

	// BUILD MAP WITH NEW DOMAINS
	ref := make(map[string]struct{})

	for _, each := range rawCSVdata {
		url := each[0]
		scheme := each[1]
		bundle := each[2]

		// BUILD REF
		ref[url] = struct{}{}

		// ADD DOMAIN TO SET
		domain := &nimbusec.Domain{
			Name:      url,
			Bundle:    bundle,
			Scheme:    scheme,
			DeepScan:  scheme + "://" + url,
			FastScans: []string{scheme + "://" + url},
		}

		// UPSERT DOMAIN
		fmt.Printf("UPSERT DOMAIN: %+v\n", domain)
		_, err := api.CreateOrUpdateDomain(domain)
		if err != nil {
			log.Fatal(err)
		}

	}

	// READ ALL DOMAINS FROM API
	currDomains, err := api.FindDomains(nimbusec.EmptyFilter)
	if err != nil {
		log.Fatal(err)
	}

	// SYNC
	// DELETE DOMAINS NOT LISTED IN NEW SET
	if *shouldDelete {
		for _, d := range currDomains {
			if _, ok := ref[d.Name]; !ok {
				api.DeleteDomain(d, true)
			}
		}
	}
}
<|endoftext|>


<commit_before>/* walter: a deployment pipeline template
 * Copyright (C) 2014 Recruit Technologies Co., Ltd. and contributors
 * (see CONTRIBUTORS.md)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package config

import (
	"container/list"
	"fmt"
	"reflect"
	"strings"

	"github.com/recruit-tech/walter/log"
	"github.com/recruit-tech/walter/messengers"
	"github.com/recruit-tech/walter/pipelines"
	"github.com/recruit-tech/walter/services"
	"github.com/recruit-tech/walter/stages"
)

type Parser struct {
	ConfigData   *map[interface{}]interface{}
	EnvVariables *EnvVariables
}

// Parse reads the specified configuration and create the pipeline.Resource.
func (self *Parser) Parse() (*pipelines.Resources, error) {
	// parse service block
	serviceOps, ok := (*self.ConfigData)["service"].(map[interface{}]interface{})
	var repoService services.Service
	var err error
	if ok == true {
		log.Info("found \"service\" block")
		repoService, err = mapService(serviceOps, self.EnvVariables)
		if err != nil {
			return nil, err
		}
	} else {
		log.Info("not found \"service\" block")
		repoService, err = services.InitService("local")
		if err != nil {
			return nil, err
		}
	}

	// parse messenger block
	messengerOps, ok := (*self.ConfigData)["messenger"].(map[interface{}]interface{})
	var messenger messengers.Messenger
	if ok == true {
		log.Info("found messenger block")
		messenger, err = mapMessenger(messengerOps, self.EnvVariables)
		if err != nil {
			return nil, err
		}
	} else {
		log.Info("not found messenger block")
		messenger, err = messengers.InitMessenger("fake")
		if err != nil {
			return nil, err
		}
	}

	// parse cleanup block
	var cleanup *pipelines.Pipeline = &pipelines.Pipeline{}
	cleanupData, ok := (*self.ConfigData)["cleanup"].([]interface{})
	if ok == true {
		log.Info("found cleanup block")
		cleanupList, err := convertYamlMapToStages(cleanupData, self.EnvVariables)
		if err != nil {
			return nil, err
		}
		for stageItem := cleanupList.Front(); stageItem != nil; stageItem = stageItem.Next() {
			cleanup.AddStage(stageItem.Value.(stages.Stage))
		}
	} else {
		log.Info("not found cleanup block in the input file")
	}

	// parse pipeline block
	var pipeline *pipelines.Pipeline = &pipelines.Pipeline{}

	pipelineData, ok := (*self.ConfigData)["pipeline"].([]interface{})
	if ok == false {
		return nil, fmt.Errorf("no pipeline block in the input file")
	}
	stageList, err := convertYamlMapToStages(pipelineData, self.EnvVariables)
	if err != nil {
		return nil, err
	}
	for stageItem := stageList.Front(); stageItem != nil; stageItem = stageItem.Next() {
		pipeline.AddStage(stageItem.Value.(stages.Stage))
	}
	var resources = &pipelines.Resources{Pipeline: pipeline, Cleanup: cleanup, Reporter: messenger, RepoService: repoService}

	return resources, nil
}

func mapMessenger(messengerMap map[interface{}]interface{}, envs *EnvVariables) (messengers.Messenger, error) {
	messengerType := messengerMap["type"].(string)
	log.Info("type of reporter is " + messengerType)
	messenger, err := messengers.InitMessenger(messengerType)
	if err != nil {
		return nil, err
	}
	newMessengerValue := reflect.ValueOf(messenger).Elem()
	newMessengerType := reflect.TypeOf(messenger).Elem()
	for i := 0; i < newMessengerType.NumField(); i++ {
		tagName := newMessengerType.Field(i).Tag.Get("config")
		for messengerOptKey, messengerOptVal := range messengerMap {
			if tagName == messengerOptKey {
				fieldVal := newMessengerValue.Field(i)
				if fieldVal.Type() == reflect.ValueOf("string").Type() {
					fieldVal.SetString(envs.Replace(messengerOptVal.(string)))
				}
			}
		}
	}

	return messenger, nil
}

func mapService(serviceMap map[interface{}]interface{}, envs *EnvVariables) (services.Service, error) {
	serviceType := serviceMap["type"].(string)
	log.Info("type of service is " + serviceType)
	service, err := services.InitService(serviceType)
	if err != nil {
		return nil, err
	}

	newServiceValue := reflect.ValueOf(service).Elem()
	newServiceType := reflect.TypeOf(service).Elem()
	for i := 0; i < newServiceType.NumField(); i++ {
		tagName := newServiceType.Field(i).Tag.Get("config")
		for serviceOptKey, serviceOptVal := range serviceMap {
			if tagName == serviceOptKey {
				fieldVal := newServiceValue.Field(i)
				if fieldVal.Type() == reflect.ValueOf("string").Type() {
					fieldVal.SetString(envs.Replace(serviceOptVal.(string)))
				}
			}
		}
	}
	return service, nil
}

func convertYamlMapToStages(yamlStageList []interface{}, envs *EnvVariables) (*list.List, error) {
	stages := list.New()
	for _, stageDetail := range yamlStageList {
		stage, err := mapStage(stageDetail.(map[interface{}]interface{}), envs)
		if err != nil {
			return nil, err
		}
		stages.PushBack(stage)
	}
	return stages, nil
}

func mapStage(stageMap map[interface{}]interface{}, envs *EnvVariables) (stages.Stage, error) {
	log.Debugf("%v", stageMap["run_after"])

	var stageType string = "command"
	if stageMap["type"] != nil {
		stageType = stageMap["type"].(string)
	} else if stageMap["stage_type"] != nil {
		log.Warn("found property \"stage_type\"")
		log.Warn("property \"stage_type\" is deprecated. please use \"type\" instead.")
		stageType = stageMap["stage_type"].(string)
	}
	stage, err := stages.InitStage(stageType)
	if err != nil {
		return nil, err
	}
	newStageValue := reflect.ValueOf(stage).Elem()
	newStageType := reflect.TypeOf(stage).Elem()

	if stageName := stageMap["name"]; stageName != nil {
		stage.SetStageName(stageMap["name"].(string))
	} else if stageName := stageMap["stage_name"]; stageName != nil {
		log.Warn("found property \"stage_name\"")
		log.Warn("property \"stage_name\" is deprecated. please use \"stage\" instead.")
		stage.SetStageName(stageMap["stage_name"].(string))
	}

	stageOpts := stages.NewStageOpts()

	if reportingFullOutput := stageMap["report_full_output"]; reportingFullOutput != nil {
		stageOpts.ReportingFullOutput = true
	}

	stage.SetStageOpts(*stageOpts)

	for i := 0; i < newStageType.NumField(); i++ {
		tagName := newStageType.Field(i).Tag.Get("config")
		is_replace := newStageType.Field(i).Tag.Get("is_replace")
		for stageOptKey, stageOptVal := range stageMap {
			if tagName == stageOptKey {
				if stageOptVal == nil {
					log.Warnf("stage option \"%s\" is not specified", stageOptKey)
				} else {
					setFieldVal(newStageValue.Field(i), stageOptVal, is_replace, envs)
				}
			}
		}
	}

	parallelStages := stageMap["parallel"]
	if parallelStages == nil {
		if parallelStages = stageMap["run_after"]; parallelStages != nil {
			log.Warn("`run_after' will be obsoleted in near future. Use `parallel' instead.")
		}
	}

	if parallelStages != nil {
		for _, parallelStages := range parallelStages.([]interface{}) {
			childStage, err := mapStage(parallelStages.(map[interface{}]interface{}), envs)
			if err != nil {
				return nil, err
			}
			stage.AddChildStage(childStage)
		}
	}
	return stage, nil
}

func setFieldVal(fieldVal reflect.Value, stageOptVal interface{}, is_replace string, envs *EnvVariables) {
	if fieldVal.Type() == reflect.ValueOf("string").Type() {
		if is_replace == "true" {
			fieldVal.SetString(envs.Replace(stageOptVal.(string)))
		} else {
			fieldVal.SetString(stageOptVal.(string))
		}
	}
}

func getStageTypeModuleName(stageType string) string {
	return strings.ToLower(stageType)
}
<commit_msg>Remove redundant parameters<commit_after>/* walter: a deployment pipeline template
 * Copyright (C) 2014 Recruit Technologies Co., Ltd. and contributors
 * (see CONTRIBUTORS.md)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package config

import (
	"container/list"
	"fmt"
	"reflect"
	"strings"

	"github.com/recruit-tech/walter/log"
	"github.com/recruit-tech/walter/messengers"
	"github.com/recruit-tech/walter/pipelines"
	"github.com/recruit-tech/walter/services"
	"github.com/recruit-tech/walter/stages"
)

type Parser struct {
	ConfigData   *map[interface{}]interface{}
	EnvVariables *EnvVariables
}

// Parse reads the specified configuration and create the pipeline.Resource.
func (self *Parser) Parse() (*pipelines.Resources, error) {
	// parse service block
	serviceOps, ok := (*self.ConfigData)["service"].(map[interface{}]interface{})
	var repoService services.Service
	var err error
	if ok == true {
		log.Info("found \"service\" block")
		repoService, err = self.mapService(serviceOps)
		if err != nil {
			return nil, err
		}
	} else {
		log.Info("not found \"service\" block")
		repoService, err = services.InitService("local")
		if err != nil {
			return nil, err
		}
	}

	// parse messenger block
	messengerOps, ok := (*self.ConfigData)["messenger"].(map[interface{}]interface{})
	var messenger messengers.Messenger
	if ok == true {
		log.Info("found messenger block")
		messenger, err = self.mapMessenger(messengerOps)
		if err != nil {
			return nil, err
		}
	} else {
		log.Info("not found messenger block")
		messenger, err = messengers.InitMessenger("fake")
		if err != nil {
			return nil, err
		}
	}

	// parse cleanup block
	var cleanup *pipelines.Pipeline = &pipelines.Pipeline{}
	cleanupData, ok := (*self.ConfigData)["cleanup"].([]interface{})
	if ok == true {
		log.Info("found cleanup block")
		cleanupList, err := self.convertYamlMapToStages(cleanupData)
		if err != nil {
			return nil, err
		}
		for stageItem := cleanupList.Front(); stageItem != nil; stageItem = stageItem.Next() {
			cleanup.AddStage(stageItem.Value.(stages.Stage))
		}
	} else {
		log.Info("not found cleanup block in the input file")
	}

	// parse pipeline block
	var pipeline *pipelines.Pipeline = &pipelines.Pipeline{}

	pipelineData, ok := (*self.ConfigData)["pipeline"].([]interface{})
	if ok == false {
		return nil, fmt.Errorf("no pipeline block in the input file")
	}
	stageList, err := self.convertYamlMapToStages(pipelineData)
	if err != nil {
		return nil, err
	}
	for stageItem := stageList.Front(); stageItem != nil; stageItem = stageItem.Next() {
		pipeline.AddStage(stageItem.Value.(stages.Stage))
	}
	var resources = &pipelines.Resources{Pipeline: pipeline, Cleanup: cleanup, Reporter: messenger, RepoService: repoService}

	return resources, nil
}

func (self *Parser) mapMessenger(messengerMap map[interface{}]interface{}) (messengers.Messenger, error) {
	messengerType := messengerMap["type"].(string)
	log.Info("type of reporter is " + messengerType)
	messenger, err := messengers.InitMessenger(messengerType)
	if err != nil {
		return nil, err
	}
	newMessengerValue := reflect.ValueOf(messenger).Elem()
	newMessengerType := reflect.TypeOf(messenger).Elem()
	for i := 0; i < newMessengerType.NumField(); i++ {
		tagName := newMessengerType.Field(i).Tag.Get("config")
		for messengerOptKey, messengerOptVal := range messengerMap {
			if tagName == messengerOptKey {
				fieldVal := newMessengerValue.Field(i)
				if fieldVal.Type() == reflect.ValueOf("string").Type() {
					fieldVal.SetString(self.EnvVariables.Replace(messengerOptVal.(string)))
				}
			}
		}
	}

	return messenger, nil
}

func (self *Parser) mapService(serviceMap map[interface{}]interface{}) (services.Service, error) {
	serviceType := serviceMap["type"].(string)
	log.Info("type of service is " + serviceType)
	service, err := services.InitService(serviceType)
	if err != nil {
		return nil, err
	}

	newServiceValue := reflect.ValueOf(service).Elem()
	newServiceType := reflect.TypeOf(service).Elem()
	for i := 0; i < newServiceType.NumField(); i++ {
		tagName := newServiceType.Field(i).Tag.Get("config")
		for serviceOptKey, serviceOptVal := range serviceMap {
			if tagName == serviceOptKey {
				fieldVal := newServiceValue.Field(i)
				if fieldVal.Type() == reflect.ValueOf("string").Type() {
					fieldVal.SetString(self.EnvVariables.Replace(serviceOptVal.(string)))
				}
			}
		}
	}
	return service, nil
}

func (self *Parser) convertYamlMapToStages(yamlStageList []interface{}) (*list.List, error) {
	stages := list.New()
	for _, stageDetail := range yamlStageList {
		stage, err := self.mapStage(stageDetail.(map[interface{}]interface{}))
		if err != nil {
			return nil, err
		}
		stages.PushBack(stage)
	}
	return stages, nil
}

func (self *Parser) mapStage(stageMap map[interface{}]interface{}) (stages.Stage, error) {
	log.Debugf("%v", stageMap["run_after"])

	var stageType string = "command"
	if stageMap["type"] != nil {
		stageType = stageMap["type"].(string)
	} else if stageMap["stage_type"] != nil {
		log.Warn("found property \"stage_type\"")
		log.Warn("property \"stage_type\" is deprecated. please use \"type\" instead.")
		stageType = stageMap["stage_type"].(string)
	}
	stage, err := stages.InitStage(stageType)
	if err != nil {
		return nil, err
	}
	newStageValue := reflect.ValueOf(stage).Elem()
	newStageType := reflect.TypeOf(stage).Elem()

	if stageName := stageMap["name"]; stageName != nil {
		stage.SetStageName(stageMap["name"].(string))
	} else if stageName := stageMap["stage_name"]; stageName != nil {
		log.Warn("found property \"stage_name\"")
		log.Warn("property \"stage_name\" is deprecated. please use \"stage\" instead.")
		stage.SetStageName(stageMap["stage_name"].(string))
	}

	stageOpts := stages.NewStageOpts()

	if reportingFullOutput := stageMap["report_full_output"]; reportingFullOutput != nil {
		stageOpts.ReportingFullOutput = true
	}

	stage.SetStageOpts(*stageOpts)

	for i := 0; i < newStageType.NumField(); i++ {
		tagName := newStageType.Field(i).Tag.Get("config")
		is_replace := newStageType.Field(i).Tag.Get("is_replace")
		for stageOptKey, stageOptVal := range stageMap {
			if tagName == stageOptKey {
				if stageOptVal == nil {
					log.Warnf("stage option \"%s\" is not specified", stageOptKey)
				} else {
					self.setFieldVal(newStageValue.Field(i), stageOptVal, is_replace)
				}
			}
		}
	}

	parallelStages := stageMap["parallel"]
	if parallelStages == nil {
		if parallelStages = stageMap["run_after"]; parallelStages != nil {
			log.Warn("`run_after' will be obsoleted in near future. Use `parallel' instead.")
		}
	}

	if parallelStages != nil {
		for _, parallelStages := range parallelStages.([]interface{}) {
			childStage, err := self.mapStage(parallelStages.(map[interface{}]interface{}))
			if err != nil {
				return nil, err
			}
			stage.AddChildStage(childStage)
		}
	}
	return stage, nil
}

func (self *Parser) setFieldVal(fieldVal reflect.Value, stageOptVal interface{}, is_replace string) {
	if fieldVal.Type() == reflect.ValueOf("string").Type() {
		if is_replace == "true" {
			fieldVal.SetString(self.EnvVariables.Replace(stageOptVal.(string)))
		} else {
			fieldVal.SetString(stageOptVal.(string))
		}
	}
}

func getStageTypeModuleName(stageType string) string {
	return strings.ToLower(stageType)
}
<|endoftext|>


<commit_before>/*
Package log provides Logger
*/
package log

import (
	"net/http"
	"time"

	"github.com/vardius/golog"
	"github.com/vardius/gorouter"
)

// Logger allow to create logger based on env setting
type Logger struct {
	golog.Logger
}

// LogRequest wraps http.Handler with a logger middleware
func (l *Logger) LogRequest(serverName string) gorouter.MiddlewareFunc {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			l.Info(r.Context(), "[%s Request|Start]: %s\n", r.Method, r.URL.String())
			start := time.Now()
			next.ServeHTTP(w, r)
			l.Info(r.Context(), "[%s Request|End] %s %q\n", r.Method, r.URL.String(), time.Since(start))
		}

		return http.HandlerFunc(fn)
	}
}

func getLogLevelByEnv(env string) string {
	logLevel := "info"
	if env == "development" {
		logLevel = "debug"
	}

	return logLevel
}

// New creates new logger based on environment
func New(env string) *Logger {
	var l golog.Logger
	if env == "development" {
		l = golog.New(getLogLevelByEnv(env))
	} else {
		l = golog.NewFileLogger(getLogLevelByEnv(env), "/tmp/prod.log")
	}

	return &Logger{l}
}
<commit_msg>Fix duration print format<commit_after>/*
Package log provides Logger
*/
package log

import (
	"net/http"
	"time"

	"github.com/vardius/golog"
	"github.com/vardius/gorouter"
)

// Logger allow to create logger based on env setting
type Logger struct {
	golog.Logger
}

// LogRequest wraps http.Handler with a logger middleware
func (l *Logger) LogRequest(serverName string) gorouter.MiddlewareFunc {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			l.Info(r.Context(), "[%s Request|Start]: %s\n", r.Method, r.URL.String())
			start := time.Now()
			next.ServeHTTP(w, r)
			l.Info(r.Context(), "[%s Request|End] %s %s\n", r.Method, r.URL.String(), time.Since(start).String())
		}

		return http.HandlerFunc(fn)
	}
}

func getLogLevelByEnv(env string) string {
	logLevel := "info"
	if env == "development" {
		logLevel = "debug"
	}

	return logLevel
}

// New creates new logger based on environment
func New(env string) *Logger {
	var l golog.Logger
	if env == "development" {
		l = golog.New(getLogLevelByEnv(env))
	} else {
		l = golog.NewFileLogger(getLogLevelByEnv(env), "/tmp/prod.log")
	}

	return &Logger{l}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"io"
	"strings"
)

func ReadConfig(r io.Reader) (map[string]string, error) {
	br := bufio.NewReader(r)
	data := make(map[string]string)
	for {
		l, err := br.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				return data, nil
			}
			return nil, err
		}
		if l[0] == '#' {
			continue
		}
		if l[len(l)-1] == '\r' {
			l = l[:len(l)-1]
		}
		parts := strings.SplitN(l, "=", 2)
		if len(parts) != 2 {
			continue
		}
		data[parts[0]] = parts[1]
	}
}

func SaveConfig(w io.Writer, c map[string]string) error {
	toWrite := make([]byte, 0, 1024)
	for k, v := range c {
		toWrite = toWrite[:0]
		toWrite = append(toWrite, k...)
		toWrite = append(toWrite, '=')
		toWrite = append(toWrite, v...)
		toWrite = append(toWrite, '\n')
		_, err := w.Write(toWrite)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Added default server.properties properties<commit_after>package main

import (
	"bufio"
	"io"
	"strings"
)

var defaultSettings = map[string]string{
	"allow-flight":                 "false",
	"allow-nether":                 "true",
	"announce-player-achievements": "true",
	"difficulty":                   "1",
	"enable-query":                 "false",
	"enable-rcon":                  "false",
	"enable-command-block":         "false",
	"force-gamemode":               "false",
	"gamemode":                     "0",
	"generate-structures":          "true",
	"generator-settings":           "",
	"hardcore":                     "false",
	"level-name":                   "world",
	"level-seed":                   "",
	"level-type":                   "DEFAULT",
	"max-build-height":             "256",
	"max-players":                  "20",
	"max-tick-time":                "60000",
	"max-world-size":               "29999984",
	"motd":                         "A MineWebGen Server",
	"network-compression-threshold": "256",
	"online-mode":                   "false",
	"op-permission-level":           "4",
	"player-idle-timeout":           "0",
	"pvp":                  "true",
	"query.port":           "25565",
	"rcon.password":        "",
	"rcon.port":            "25575",
	"resource-pack":        "",
	"resource-pack-hash":   "",
	"server-ip":            "",
	"server-port":          "25565",
	"snooper-enabled":      "false",
	"spawn-animals":        "true",
	"spawn-monsters":       "true",
	"spawn-npcs":           "true",
	"spawn-protection":     "16",
	"use-native-transport": "true",
	"view-distance":        "10",
	"white-list":           "false",
	"verify-names":         "true",
	"admin-slot":           "false",
	"public":               "true",
	"server-name":          "",
	"max-connections":      "3",
	"grow-trees":           "true",
}

func DefaultSettings() map[string]string {
	m := make(map[string]string)
	for k, v := range defaultSettings {
		m[k] = v
	}
	return m
}

func ReadConfig(r io.Reader) (map[string]string, error) {
	br := bufio.NewReader(r)
	data := make(map[string]string)
	for {
		l, err := br.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				return data, nil
			}
			return nil, err
		}
		if l[0] == '#' {
			continue
		}
		if l[len(l)-1] == '\r' {
			l = l[:len(l)-1]
		}
		parts := strings.SplitN(l, "=", 2)
		if len(parts) != 2 {
			continue
		}
		data[parts[0]] = parts[1]
	}
}

func SaveConfig(w io.Writer, c map[string]string) error {
	toWrite := make([]byte, 0, 1024)
	for k, v := range c {
		toWrite = toWrite[:0]
		toWrite = append(toWrite, k...)
		toWrite = append(toWrite, '=')
		toWrite = append(toWrite, v...)
		toWrite = append(toWrite, '\n')
		_, err := w.Write(toWrite)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/dghubble/sling"
	"net/http"
	"strings"
	"io/ioutil"
)

type SpectoLab struct {
	Host   string
	Port   string
	ApiKey string
}

type SpectoLabSimulation struct {
	Version     string `json:"version"`
	Name        string `json:"name"`
	Description string `json:"description"`
}

func (s *SpectoLab) CreateSimulation(simulationName Simulation) (error) {
	simulation := SpectoLabSimulation{Version: simulationName.Version, Name: simulationName.Name, Description: "A description could go here"}

	url := s.buildUrl("/api/v1/simulations")
	request, err := sling.New().Post(url).BodyJSON(simulation).Add("Authorization", s.buildAuthorizationHeaderValue()).Request()

	if err != nil {
		return err
	}

	response, err := http.DefaultClient.Do(request)
	defer response.Body.Close()

	if err != nil {
		return err
	}

	return nil
}

func (s *SpectoLab) UploadSimulation(simulation Simulation, data []byte) (bool, error) {
	err := s.CreateSimulation(simulation)

	if err != nil {
		return false, err
	}

	url := s.buildUrl(fmt.Sprintf("/api/v1/users/%v/simulations/%v/versions/%v/data", simulation.Vendor,  simulation.Name, simulation.Version))

	request, err := sling.New().Put(url).Add("Authorization", s.buildAuthorizationHeaderValue()).Add("Content-Type", "application/json").Body(strings.NewReader(string(data))).Request()

	if err != nil {
		return false, err
	}

	response, err := http.DefaultClient.Do(request)

	if err != nil {
		return false, err
	}

	defer response.Body.Close()

	return response.StatusCode >= 200 && response.StatusCode <= 299, nil
}

func (s *SpectoLab) GetSimulation(simulation Simulation, overrideHost string) []byte {
	var url string
	if len(overrideHost) > 0 {
		url = s.buildUrl(fmt.Sprintf("/api/v1/users/%v/simulations/%v/versions/%v/data?override-host=%v", simulation.Vendor, simulation.Name, simulation.Version, overrideHost))
	} else {
		url = s.buildUrl(fmt.Sprintf("/api/v1/users/%v/simulations/%v/versions/%v/data", simulation.Vendor, simulation.Name, simulation.Version))
	}

	request, _ := sling.New().Get(url).Add("Authorization", s.buildAuthorizationHeaderValue()).Add("Content-Type", "application/json").Request()
	response, _ := http.DefaultClient.Do(request)
	defer response.Body.Close()

	body, _ := ioutil.ReadAll(response.Body)

	return body
}

func (s *SpectoLab) buildUrl(endpoint string) string {
	return fmt.Sprintf("%v%v", s.buildBaseUrl(), endpoint)
}

func (s *SpectoLab) buildBaseUrl() string {
	if len(s.Port) > 0 {
		return fmt.Sprintf("http://%v:%v", s.Host, s.Port)
	} else {
		return fmt.Sprintf("http://%v", s.Host)
	}
}

func (s *SpectoLab) buildAuthorizationHeaderValue() string {
	return fmt.Sprintf("Bearer %v", s.ApiKey)
}<commit_msg>Wasn't returning the error before trying to close the request<commit_after>package main

import (
	"fmt"
	"github.com/dghubble/sling"
	"net/http"
	"strings"
	"io/ioutil"
)

type SpectoLab struct {
	Host   string
	Port   string
	ApiKey string
}

type SpectoLabSimulation struct {
	Version     string `json:"version"`
	Name        string `json:"name"`
	Description string `json:"description"`
}

func (s *SpectoLab) CreateSimulation(simulationName Simulation) (error) {
	simulation := SpectoLabSimulation{Version: simulationName.Version, Name: simulationName.Name, Description: "A description could go here"}

	url := s.buildUrl("/api/v1/simulations")
	request, err := sling.New().Post(url).BodyJSON(simulation).Add("Authorization", s.buildAuthorizationHeaderValue()).Request()
	if err != nil {
		return err
	}

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		return err
	}

	defer response.Body.Close()

	return nil
}

func (s *SpectoLab) UploadSimulation(simulation Simulation, data []byte) (bool, error) {
	err := s.CreateSimulation(simulation)

	if err != nil {
		return false, err
	}

	url := s.buildUrl(fmt.Sprintf("/api/v1/users/%v/simulations/%v/versions/%v/data", simulation.Vendor,  simulation.Name, simulation.Version))

	request, err := sling.New().Put(url).Add("Authorization", s.buildAuthorizationHeaderValue()).Add("Content-Type", "application/json").Body(strings.NewReader(string(data))).Request()

	if err != nil {
		return false, err
	}

	response, err := http.DefaultClient.Do(request)

	if err != nil {
		return false, err
	}

	defer response.Body.Close()

	return response.StatusCode >= 200 && response.StatusCode <= 299, nil
}

func (s *SpectoLab) GetSimulation(simulation Simulation, overrideHost string) []byte {
	var url string
	if len(overrideHost) > 0 {
		url = s.buildUrl(fmt.Sprintf("/api/v1/users/%v/simulations/%v/versions/%v/data?override-host=%v", simulation.Vendor, simulation.Name, simulation.Version, overrideHost))
	} else {
		url = s.buildUrl(fmt.Sprintf("/api/v1/users/%v/simulations/%v/versions/%v/data", simulation.Vendor, simulation.Name, simulation.Version))
	}

	request, _ := sling.New().Get(url).Add("Authorization", s.buildAuthorizationHeaderValue()).Add("Content-Type", "application/json").Request()
	response, _ := http.DefaultClient.Do(request)
	defer response.Body.Close()

	body, _ := ioutil.ReadAll(response.Body)

	return body
}

func (s *SpectoLab) buildUrl(endpoint string) string {
	return fmt.Sprintf("%v%v", s.buildBaseUrl(), endpoint)
}

func (s *SpectoLab) buildBaseUrl() string {
	if len(s.Port) > 0 {
		return fmt.Sprintf("http://%v:%v", s.Host, s.Port)
	} else {
		return fmt.Sprintf("http://%v", s.Host)
	}
}

func (s *SpectoLab) buildAuthorizationHeaderValue() string {
	return fmt.Sprintf("Bearer %v", s.ApiKey)
}<|endoftext|>