<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
	"time"
)

var cmdLs = &Command{
	Run:   runLs,
	Usage: "ls [-l] [app...]",
	Short: "list apps, addons, dynos, and releases",
	Long: `
       hk ls [-l] [-a app] releases [name...]

       hk ls [-l] [-a app] addons [name...]

Command hk ls lists apps, releases, and addons.

Options:

    -l       long listing
    -a=name  app name

Long listing for apps shows the owner, slug size, last release
time (or time the app was created, if it's never been released),
and the app name. Long listing for releases shows the git commit
id, who made the release, time of the release, name of the release
(e.g. v1), and description. Long listing for addons shows the type
of the addon, owner, name of the resource, and the config var it's
attached to. Long listing for dynos shows the name, state, age,
and command.

Examples:

    $ hk ls
    myapp
    myapp2

    $ hk ls -l
    app  me  1234k  Jan 2 12:34  myapp
    app  me  4567k  Jan 2 12:34  myapp2

    $ hk ls dynos
    run.3794
    web.1
    web.2

    $ hk ls -l dynos
    run.3794  up   1m  bash
    web.1     up  15h  "blog /app /tmp/dst"
    web.2     up   8h  "blog /app /tmp/dst"

    $ hk ls rel
    v1
    v2

    $ hk ls -l rel
    3ae20c2  me  Jun 12 18:28  v1  Deploy 3ae20c2
    0fda0ae  me  Jun 13 18:14  v2  Deploy 0fda0ae
    ed39b69  me  Jun 13 18:31  v3  Deploy ed39b69

    $ hk ls -l rel v3
    ed39b69  me  Jun 13 18:31  v3  Deploy ed39b69

    $ hk ls addons
    DATABASE_URL
    REDIS_URL

    $ hk ls -l addons REDIS_URL
    redistogo:nano  me  soaring-ably-1234  REDIS_URL
`,
}

func init() {
	cmdLs.Flag.StringVar(&flagApp, "a", "", "app")
	cmdLs.Flag.BoolVar(&flagLong, "l", false, "long listing")
}

func runLs(cmd *Command, args []string) {
	w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0)
	list(w, cmd, args)
	w.Flush()
}

func list(w io.Writer, cmd *Command, args []string) {
	if len(args) == 0 {
		var apps []*App
		must(Get(&apps, "/apps"))
		sort.Sort(appsByName(apps))
		abbrevEmailApps(apps)
		for _, a := range apps {
			listApp(w, a)
		}
		return
	}
	switch a0 := args[0]; {
	case strings.HasPrefix("releases", a0):
		listRels(w, args[1:])
	case strings.HasPrefix("addons", a0):
		listAddons(w, args[1:])
	case strings.HasPrefix("dynos", a0):
		listDynos(w, args[1:])
	default:
		listApps(w, args)
	}
}

func listApps(w io.Writer, names []string) {
	ch := make(chan error, len(names))
	var apps []*App
	for _, name := range names {
		if name == "" {
			ch <- nil
		} else {
			v, url := new(App), "/apps/"+name
			apps = append(apps, v)
			go func() { ch <- Get(v, url) }()
		}
	}
	for _ = range names {
		if err := <-ch; err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
	sort.Sort(appsByName(apps))
	abbrevEmailApps(apps)
	for _, a := range apps {
		if a.Name != "" {
			listApp(w, a)
		}
	}
}

type appsByName []*App

func (a appsByName) Len() int           { return len(a) }
func (a appsByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a appsByName) Less(i, j int) bool { return a[i].Name < a[j].Name }

func listRels(w io.Writer, names []string) {
	if len(names) == 0 {
		var rels []*Release
		must(Get(&rels, "/apps/"+mustApp()+"/releases"))
		gitDescribe(rels)
		abbrevEmailReleases(rels)
		for _, r := range rels {
			listRelease(w, r)
		}
		return
	}

	app := mustApp()
	ch := make(chan error, len(names))
	var rels []*Release
	for _, name := range names {
		if name == "" {
			ch <- nil
		} else {
			r, url := new(Release), "/apps/"+app+"/releases/"+name
			rels = append(rels, r)
			go func() { ch <- Get(r, url) }()
		}
	}
	for _ = range names {
		if err := <-ch; err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
	sort.Sort(releasesByName(rels))
	gitDescribe(rels)
	abbrevEmailReleases(rels)
	for _, r := range rels {
		if r.Name != "" {
			listRelease(w, r)
		}
	}
}

type DynosByName []*Dyno

func (p DynosByName) Len() int           { return len(p) }
func (p DynosByName) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p DynosByName) Less(i, j int) bool { return p[i].Name < p[j].Name }

func listDynos(w io.Writer, names []string) {
	var dynos []*Dyno
	must(Get(&v2{&dynos}, "/apps/"+mustApp()+"/ps"))
	sort.Sort(DynosByName(dynos))

	if len(names) == 0 {
		for _, d := range dynos {
			listDyno(w, d)
		}
		return
	}

	for _, name := range names {
		for _, d := range dynos {
			if d.Name == name {
				listDyno(w, d)
			}
		}
	}
	return
}

func abbrevEmailReleases(rels []*Release) {
	domains := make(map[string]int)
	for _, r := range rels {
		parts := strings.SplitN(r.User, "@", 2)
		if len(parts) == 2 {
			domains["@"+parts[1]]++
		}
	}
	smax, nmax := "", 0
	for s, n := range domains {
		if n > nmax {
			smax = s
		}
	}
	for _, r := range rels {
		if strings.HasSuffix(r.User, smax) {
			r.User = r.User[:len(r.User)-len(smax)]
		}
	}
}

func abbrevEmailApps(apps []*App) {
	domains := make(map[string]int)
	for _, a := range apps {
		parts := strings.SplitN(a.Owner.Email, "@", 2)
		if len(parts) == 2 {
			domains["@"+parts[1]]++
		}
	}
	smax, nmax := "", 0
	for s, n := range domains {
		if n > nmax {
			smax = s
			nmax = n
		}
	}
	for _, a := range apps {
		if strings.HasSuffix(a.Owner.Email, smax) {
			a.Owner.Email = a.Owner.Email[:len(a.Owner.Email)-len(smax)]
		}
	}
}

func abbrevEmailResources(ms []*mergedAddon) {
	domains := make(map[string]int)
	for _, m := range ms {
		parts := strings.SplitN(m.Owner, "@", 2)
		if len(parts) == 2 {
			domains["@"+parts[1]]++
		}
	}
	smax, nmax := "", 0
	for s, n := range domains {
		if n > nmax {
			smax = s
			nmax = n
		}
	}
	for _, m := range ms {
		if strings.HasSuffix(m.Owner, smax) {
			m.Owner = m.Owner[:len(m.Owner)-len(smax)]
		}
	}
}

type releasesByName []*Release

func (a releasesByName) Len() int           { return len(a) }
func (a releasesByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a releasesByName) Less(i, j int) bool { return a[i].Name < a[j].Name }

func listAddons(w io.Writer, names []string) {
	ms := getMergedAddons(mustApp())
	abbrevEmailResources(ms)
	for i, s := range names {
		names[i] = strings.ToLower(s)
	}
	for _, m := range ms {
		if len(names) == 0 || addonMatch(m, names) {
			listAddon(w, m)
		}
	}
}

func addonMatch(m *mergedAddon, a []string) bool {
	for _, s := range a {
		if s == strings.ToLower(m.Type) {
			return true
		}
		if s == strings.ToLower(m.Name) {
			return true
		}
		if s == strings.ToLower(m.ConfigVar) {
			return true
		}
	}
	return false
}

func listApp(w io.Writer, a *App) {
	if flagLong {
		size := 0
		if a.SlugSize != nil {
			size = *a.SlugSize
		}
		t := a.CreatedAt
		if a.ReleasedAt != nil {
			t = *a.ReleasedAt
		}
		listRec(w,
			"app",
			abbrev(a.Owner.Email, 10),
			fmt.Sprintf("%6dk", (size+501)/(1000)),
			prettyTime{t},
			a.Name,
		)
	} else {
		fmt.Fprintln(w, a.Name)
	}
}

func listRelease(w io.Writer, r *Release) {
	if flagLong {
		listRec(w,
			abbrev(GitRef(r.Commit), 10),
			abbrev(r.User, 10),
			prettyTime{r.CreatedAt.Time},
			r.Name,
			r.Descr,
		)
	} else {
		fmt.Fprintln(w, r.Name)
	}
}

func listDyno(w io.Writer, d *Dyno) {
	if flagLong {
		listRec(w,
			d.Name,
			d.State,
			prettyDuration{d.Age()},
			maybeQuote(d.Command),
		)
	} else {
		fmt.Fprintln(w, d.Name)
	}
}

// quotes s as a json string if it contains any weird chars
// currently weird is anything other than [alnum]_-
func maybeQuote(s string) string {
	for _, r := range s {
		if !('0' <= r && r <= '9' || 'a' <= r && r <= 'z' ||
			'A' <= r && r <= 'Z' || r == '-' || r == '_') {
			return quote(s)
		}
	}
	return s
}

// quotes s as a json string
func quote(s string) string {
	b, _ := json.Marshal(s)
	return string(b)
}

func listAddon(w io.Writer, m *mergedAddon) {
	if flagLong {
		listRec(w,
			m.Type,
			abbrev(m.Owner, 10),
			m.Name,
			m.ConfigVar,
		)
	} else {
		name := m.ConfigVar
		if name == "" {
			name = "(" + m.Type + ")"
		}
		fmt.Fprintln(w, m.String())
	}
}

type prettyTime struct {
	time.Time
}

func (s prettyTime) String() string {
	if time.Now().Sub(s.Time) < 12*30*24*time.Hour {
		return s.Local().Format("Jan _2 15:04")
	}
	return s.Local().Format("Jan _2  2006")
}

type prettyDuration struct {
	time.Duration
}

func (a prettyDuration) String() string {
	switch d := a.Duration; {
	case d > 2*24*time.Hour:
		return a.Unit(24*time.Hour, "d")
	case d > 2*time.Hour:
		return a.Unit(time.Hour, "h")
	case d > 2*time.Minute:
		return a.Unit(time.Minute, "m")
	}
	return a.Unit(time.Second, "s")
}

func (a prettyDuration) Unit(u time.Duration, s string) string {
	return fmt.Sprintf("%2d", roundDur(a.Duration, u)) + s
}

func roundDur(d, k time.Duration) int {
	return int((d + k/2 - 1) / k)
}

func abbrev(s string, n int) string {
	if len(s) > n {
		return s[:n-1] + "…"
	}
	return s
}

func listRec(w io.Writer, a ...interface{}) {
	for i, x := range a {
		fmt.Fprint(w, x)
		if i+1 < len(a) {
			w.Write([]byte{'\t'})
		} else {
			w.Write([]byte{'\n'})
		}
	}
}
<commit_msg>refactor<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
	"time"
)

var cmdLs = &Command{
	Run:   runLs,
	Usage: "ls [-l] [app...]",
	Short: "list apps, addons, dynos, and releases",
	Long: `
       hk ls [-l] [-a app] releases [name...]

       hk ls [-l] [-a app] addons [name...]

Command hk ls lists apps, releases, and addons.

Options:

    -l       long listing
    -a=name  app name

Long listing for apps shows the owner, slug size, last release
time (or time the app was created, if it's never been released),
and the app name. Long listing for releases shows the git commit
id, who made the release, time of the release, name of the release
(e.g. v1), and description. Long listing for addons shows the type
of the addon, owner, name of the resource, and the config var it's
attached to. Long listing for dynos shows the name, state, age,
and command.

Examples:

    $ hk ls
    myapp
    myapp2

    $ hk ls -l
    app  me  1234k  Jan 2 12:34  myapp
    app  me  4567k  Jan 2 12:34  myapp2

    $ hk ls dynos
    run.3794
    web.1
    web.2

    $ hk ls -l dynos
    run.3794  up   1m  bash
    web.1     up  15h  "blog /app /tmp/dst"
    web.2     up   8h  "blog /app /tmp/dst"

    $ hk ls rel
    v1
    v2

    $ hk ls -l rel
    3ae20c2  me  Jun 12 18:28  v1  Deploy 3ae20c2
    0fda0ae  me  Jun 13 18:14  v2  Deploy 0fda0ae
    ed39b69  me  Jun 13 18:31  v3  Deploy ed39b69

    $ hk ls -l rel v3
    ed39b69  me  Jun 13 18:31  v3  Deploy ed39b69

    $ hk ls addons
    DATABASE_URL
    REDIS_URL

    $ hk ls -l addons REDIS_URL
    redistogo:nano  me  soaring-ably-1234  REDIS_URL
`,
}

func init() {
	cmdLs.Flag.StringVar(&flagApp, "a", "", "app")
	cmdLs.Flag.BoolVar(&flagLong, "l", false, "long listing")
}

func runLs(cmd *Command, args []string) {
	w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0)
	list(w, cmd, args)
	w.Flush()
}

func list(w io.Writer, cmd *Command, args []string) {
	if len(args) == 0 {
		var apps []*App
		must(Get(&apps, "/apps"))
		printAppList(w, apps)
		return
	}
	switch a0 := args[0]; {
	case strings.HasPrefix("releases", a0):
		listRels(w, args[1:])
	case strings.HasPrefix("addons", a0):
		listAddons(w, args[1:])
	case strings.HasPrefix("dynos", a0):
		listDynos(w, args[1:])
	default:
		listApps(w, args)
	}
}

func listApps(w io.Writer, names []string) {
	ch := make(chan error, len(names))
	var apps []*App
	for _, name := range names {
		if name == "" {
			ch <- nil
		} else {
			v, url := new(App), "/apps/"+name
			apps = append(apps, v)
			go func() { ch <- Get(v, url) }()
		}
	}
	for _ = range names {
		if err := <-ch; err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
	printAppList(w, apps)
}

func printAppList(w io.Writer, apps []*App) {
	sort.Sort(appsByName(apps))
	abbrevEmailApps(apps)
	for _, a := range apps {
		if a.Name != "" {
			listApp(w, a)
		}
	}
}

type appsByName []*App

func (a appsByName) Len() int           { return len(a) }
func (a appsByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a appsByName) Less(i, j int) bool { return a[i].Name < a[j].Name }

func listRels(w io.Writer, names []string) {
	if len(names) == 0 {
		var rels []*Release
		must(Get(&rels, "/apps/"+mustApp()+"/releases"))
		gitDescribe(rels)
		abbrevEmailReleases(rels)
		for _, r := range rels {
			listRelease(w, r)
		}
		return
	}

	app := mustApp()
	ch := make(chan error, len(names))
	var rels []*Release
	for _, name := range names {
		if name == "" {
			ch <- nil
		} else {
			r, url := new(Release), "/apps/"+app+"/releases/"+name
			rels = append(rels, r)
			go func() { ch <- Get(r, url) }()
		}
	}
	for _ = range names {
		if err := <-ch; err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
	sort.Sort(releasesByName(rels))
	gitDescribe(rels)
	abbrevEmailReleases(rels)
	for _, r := range rels {
		if r.Name != "" {
			listRelease(w, r)
		}
	}
}

type DynosByName []*Dyno

func (p DynosByName) Len() int           { return len(p) }
func (p DynosByName) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p DynosByName) Less(i, j int) bool { return p[i].Name < p[j].Name }

func listDynos(w io.Writer, names []string) {
	var dynos []*Dyno
	must(Get(&v2{&dynos}, "/apps/"+mustApp()+"/ps"))
	sort.Sort(DynosByName(dynos))

	if len(names) == 0 {
		for _, d := range dynos {
			listDyno(w, d)
		}
		return
	}

	for _, name := range names {
		for _, d := range dynos {
			if d.Name == name {
				listDyno(w, d)
			}
		}
	}
	return
}

func abbrevEmailReleases(rels []*Release) {
	domains := make(map[string]int)
	for _, r := range rels {
		parts := strings.SplitN(r.User, "@", 2)
		if len(parts) == 2 {
			domains["@"+parts[1]]++
		}
	}
	smax, nmax := "", 0
	for s, n := range domains {
		if n > nmax {
			smax = s
		}
	}
	for _, r := range rels {
		if strings.HasSuffix(r.User, smax) {
			r.User = r.User[:len(r.User)-len(smax)]
		}
	}
}

func abbrevEmailApps(apps []*App) {
	domains := make(map[string]int)
	for _, a := range apps {
		parts := strings.SplitN(a.Owner.Email, "@", 2)
		if len(parts) == 2 {
			domains["@"+parts[1]]++
		}
	}
	smax, nmax := "", 0
	for s, n := range domains {
		if n > nmax {
			smax = s
			nmax = n
		}
	}
	for _, a := range apps {
		if strings.HasSuffix(a.Owner.Email, smax) {
			a.Owner.Email = a.Owner.Email[:len(a.Owner.Email)-len(smax)]
		}
	}
}

func abbrevEmailResources(ms []*mergedAddon) {
	domains := make(map[string]int)
	for _, m := range ms {
		parts := strings.SplitN(m.Owner, "@", 2)
		if len(parts) == 2 {
			domains["@"+parts[1]]++
		}
	}
	smax, nmax := "", 0
	for s, n := range domains {
		if n > nmax {
			smax = s
			nmax = n
		}
	}
	for _, m := range ms {
		if strings.HasSuffix(m.Owner, smax) {
			m.Owner = m.Owner[:len(m.Owner)-len(smax)]
		}
	}
}

type releasesByName []*Release

func (a releasesByName) Len() int           { return len(a) }
func (a releasesByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a releasesByName) Less(i, j int) bool { return a[i].Name < a[j].Name }

func listAddons(w io.Writer, names []string) {
	ms := getMergedAddons(mustApp())
	abbrevEmailResources(ms)
	for i, s := range names {
		names[i] = strings.ToLower(s)
	}
	for _, m := range ms {
		if len(names) == 0 || addonMatch(m, names) {
			listAddon(w, m)
		}
	}
}

func addonMatch(m *mergedAddon, a []string) bool {
	for _, s := range a {
		if s == strings.ToLower(m.Type) {
			return true
		}
		if s == strings.ToLower(m.Name) {
			return true
		}
		if s == strings.ToLower(m.ConfigVar) {
			return true
		}
	}
	return false
}

func listApp(w io.Writer, a *App) {
	if flagLong {
		size := 0
		if a.SlugSize != nil {
			size = *a.SlugSize
		}
		t := a.CreatedAt
		if a.ReleasedAt != nil {
			t = *a.ReleasedAt
		}
		listRec(w,
			"app",
			abbrev(a.Owner.Email, 10),
			fmt.Sprintf("%6dk", (size+501)/(1000)),
			prettyTime{t},
			a.Name,
		)
	} else {
		fmt.Fprintln(w, a.Name)
	}
}

func listRelease(w io.Writer, r *Release) {
	if flagLong {
		listRec(w,
			abbrev(GitRef(r.Commit), 10),
			abbrev(r.User, 10),
			prettyTime{r.CreatedAt.Time},
			r.Name,
			r.Descr,
		)
	} else {
		fmt.Fprintln(w, r.Name)
	}
}

func listDyno(w io.Writer, d *Dyno) {
	if flagLong {
		listRec(w,
			d.Name,
			d.State,
			prettyDuration{d.Age()},
			maybeQuote(d.Command),
		)
	} else {
		fmt.Fprintln(w, d.Name)
	}
}

// quotes s as a json string if it contains any weird chars
// currently weird is anything other than [alnum]_-
func maybeQuote(s string) string {
	for _, r := range s {
		if !('0' <= r && r <= '9' || 'a' <= r && r <= 'z' ||
			'A' <= r && r <= 'Z' || r == '-' || r == '_') {
			return quote(s)
		}
	}
	return s
}

// quotes s as a json string
func quote(s string) string {
	b, _ := json.Marshal(s)
	return string(b)
}

func listAddon(w io.Writer, m *mergedAddon) {
	if flagLong {
		listRec(w,
			m.Type,
			abbrev(m.Owner, 10),
			m.Name,
			m.ConfigVar,
		)
	} else {
		name := m.ConfigVar
		if name == "" {
			name = "(" + m.Type + ")"
		}
		fmt.Fprintln(w, m.String())
	}
}

type prettyTime struct {
	time.Time
}

func (s prettyTime) String() string {
	if time.Now().Sub(s.Time) < 12*30*24*time.Hour {
		return s.Local().Format("Jan _2 15:04")
	}
	return s.Local().Format("Jan _2  2006")
}

type prettyDuration struct {
	time.Duration
}

func (a prettyDuration) String() string {
	switch d := a.Duration; {
	case d > 2*24*time.Hour:
		return a.Unit(24*time.Hour, "d")
	case d > 2*time.Hour:
		return a.Unit(time.Hour, "h")
	case d > 2*time.Minute:
		return a.Unit(time.Minute, "m")
	}
	return a.Unit(time.Second, "s")
}

func (a prettyDuration) Unit(u time.Duration, s string) string {
	return fmt.Sprintf("%2d", roundDur(a.Duration, u)) + s
}

func roundDur(d, k time.Duration) int {
	return int((d + k/2 - 1) / k)
}

func abbrev(s string, n int) string {
	if len(s) > n {
		return s[:n-1] + "…"
	}
	return s
}

func listRec(w io.Writer, a ...interface{}) {
	for i, x := range a {
		fmt.Fprint(w, x)
		if i+1 < len(a) {
			w.Write([]byte{'\t'})
		} else {
			w.Write([]byte{'\n'})
		}
	}
}
<|endoftext|>


<commit_before>package pb

import (
	"fmt"
	"io"
	"math"
	"strings"
	"sync/atomic"
	"time"
)

var (
	// Default refresh rate - 200ms
	DefaultRefreshRate = time.Millisecond * 200

	BarStart = "["
	BarEnd   = "]"
	Empty    = "_"
	Current  = "="
	CurrentN = ">"
)

// Create new progress bar object
func New(total int) *ProgressBar {
	return &ProgressBar{
		Total:        int64(total),
		RefreshRate:  DefaultRefreshRate,
		ShowPercent:  true,
		ShowCounters: true,
		ShowBar:      true,
		ShowTimeLeft: true,
	}
}

// Create new object and start
func StartNew(total int) (pb *ProgressBar) {
	pb = New(total)
	pb.Start()
	return
}

// Callback for custom output
// For example:
// bar.Callback = func(s string) {
//     mySuperPrint(s)
// }
//
type Callback func(out string)

type ProgressBar struct {
	current int64 // current must be first member of struct (https://code.google.com/p/go/issues/detail?id=5278)

	Total                            int64
	RefreshRate                      time.Duration
	ShowPercent, ShowCounters        bool
	ShowSpeed, ShowTimeLeft, ShowBar bool
	Output                           io.Writer
	Callback                         Callback
	NotPrint                         bool
	Units                            int

	isFinish  bool
	startTime time.Time
}

// Start print
func (pb *ProgressBar) Start() {
	pb.startTime = time.Now()
	if pb.Total == 0 {
		pb.ShowBar = false
		pb.ShowTimeLeft = false
		pb.ShowPercent = false
	}
	go pb.writer()
}

// Increment current value
func (pb *ProgressBar) Increment() int {
	return pb.Add(1)
}

// Set current value
func (pb *ProgressBar) Set(current int) {
	atomic.StoreInt64(&pb.current, int64(current))
}

// Add to current value
func (pb *ProgressBar) Add(add int) int {
	return int(atomic.AddInt64(&pb.current, int64(add)))
}

// End print
func (pb *ProgressBar) Finish() {
	pb.isFinish = true
	pb.write(atomic.LoadInt64(&pb.current))
	if !pb.NotPrint {
		fmt.Println()
	}
}

// End print and write string 'str'
func (pb *ProgressBar) FinishPrint(str string) {
	pb.Finish()
	fmt.Println(str)
}

// implement io.Writer
func (pb *ProgressBar) Write(p []byte) (n int, err error) {
	n = len(p)
	pb.Add(n)
	return
}

// implement io.Reader
func (pb *ProgressBar) Read(p []byte) (n int, err error) {
	n = len(p)
	pb.Add(n)
	return
}

func (pb *ProgressBar) write(current int64) {
	width, _ := terminalWidth()
	var percentBox, countersBox, timeLeftBox, speedBox, barBox, end, out string

	// percents
	if pb.ShowPercent {
		percent := float64(current) / (float64(pb.Total) / float64(100))
		percentBox = fmt.Sprintf(" %#.02f %% ", percent)
	}

	// counters
	if pb.ShowCounters {
		if pb.Total > 0 {
			countersBox = fmt.Sprintf("%s / %s ", Format(current, pb.Units), Format(pb.Total, pb.Units))
		} else {
			countersBox = Format(current, pb.Units) + " "
		}
	}

	// time left
	if pb.ShowTimeLeft && current > 0 {
		fromStart := time.Now().Sub(pb.startTime)
		perEntry := fromStart / time.Duration(current)
		left := time.Duration(pb.Total-current) * perEntry
		left = (left / time.Second) * time.Second
		if left > 0 {
			timeLeftBox = left.String()
		}
	}

	// speed
	if pb.ShowSpeed && current > 0 {
		fromStart := time.Now().Sub(pb.startTime)
		speed := float64(current) / (float64(fromStart) / float64(time.Second))
		speedBox = Format(int64(speed), pb.Units) + "/s "
	}

	// bar
	if pb.ShowBar {
		size := width - len(countersBox+BarStart+BarEnd+percentBox+timeLeftBox+speedBox)
		if size > 0 {
			curCount := int(math.Ceil((float64(current) / float64(pb.Total)) * float64(size)))
			emptCount := size - curCount
			barBox = BarStart
			if emptCount < 0 {
				emptCount = 0
			}
			if curCount > size {
				curCount = size
			}
			if emptCount <= 0 {
				barBox += strings.Repeat(Current, curCount)
			} else if curCount > 0 {
				barBox += strings.Repeat(Current, curCount-1) + CurrentN
			}

			barBox += strings.Repeat(Empty, emptCount) + BarEnd
		}
	}

	// check len
	out = countersBox + barBox + percentBox + speedBox + timeLeftBox
	if len(out) < width {
		end = strings.Repeat(" ", width-len(out))
	}

	out = countersBox + barBox + percentBox + speedBox + timeLeftBox

	// and print!
	switch {
	case pb.Output != nil:
		fmt.Fprint(pb.Output, out+end)
	case pb.Callback != nil:
		pb.Callback(out + end)
	case !pb.NotPrint:
		fmt.Print("\r" + out + end)
	}
}

func (pb *ProgressBar) writer() {
	var c, oc int64
	oc = -1
	for {
		if pb.isFinish {
			break
		}
		c = atomic.LoadInt64(&pb.current)
		if c != oc {
			pb.write(c)
			oc = c
		}
		time.Sleep(pb.RefreshRate)
	}
}

type window struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}
<commit_msg>Move bar format into properties of ProgressBar<commit_after>package pb

import (
	"fmt"
	"io"
	"math"
	"strings"
	"sync/atomic"
	"time"
)

const (
	// Default refresh rate - 200ms
	DEFAULT_REFRESH_RATE = time.Millisecond * 200

	BAR_START = "["
	BAR_END   = "]"
	EMPTY    = "_"
	CURRENT  = "="
	CURRENT_N = ">"
)

// Create new progress bar object
func New(total int) *ProgressBar {
	return &ProgressBar{
		Total:        int64(total),
		RefreshRate:  DEFAULT_REFRESH_RATE,
		ShowPercent:  true,
		ShowCounters: true,
		ShowBar:      true,
		ShowTimeLeft: true,
		BarStart:     BAR_START,
		BarEnd:       BAR_END,
		Empty:        EMPTY,
		Current:      CURRENT,
		CurrentN:     CURRENT_N,
	}
}

// Create new object and start
func StartNew(total int) (pb *ProgressBar) {
	pb = New(total)
	pb.Start()
	return
}

// Callback for custom output
// For example:
// bar.Callback = func(s string) {
//     mySuperPrint(s)
// }
//
type Callback func(out string)

type ProgressBar struct {
	current int64 // current must be first member of struct (https://code.google.com/p/go/issues/detail?id=5278)

	Total                            int64
	RefreshRate                      time.Duration
	ShowPercent, ShowCounters        bool
	ShowSpeed, ShowTimeLeft, ShowBar bool
	Output                           io.Writer
	Callback                         Callback
	NotPrint                         bool
	Units                            int

	isFinish  bool
	startTime time.Time

	BarStart                         string
	BarEnd                           string
	Empty                            string
	Current                          string
	CurrentN                         string
}

// Start print
func (pb *ProgressBar) Start() {
	pb.startTime = time.Now()
	if pb.Total == 0 {
		pb.ShowBar = false
		pb.ShowTimeLeft = false
		pb.ShowPercent = false
	}
	go pb.writer()
}

// Increment current value
func (pb *ProgressBar) Increment() int {
	return pb.Add(1)
}

// Set current value
func (pb *ProgressBar) Set(current int) {
	atomic.StoreInt64(&pb.current, int64(current))
}

// Add to current value
func (pb *ProgressBar) Add(add int) int {
	return int(atomic.AddInt64(&pb.current, int64(add)))
}

func (pb *ProgressBar) Format(BarStart string, Current string, CurrentN string,
	                            Empty string, BarEnd string) {
	pb.BarStart = BarStart
	pb.BarEnd = BarEnd
	pb.Empty = Empty
	pb.Current = Current
	pb.CurrentN = CurrentN
}

// End print
func (pb *ProgressBar) Finish() {
	pb.isFinish = true
	pb.write(atomic.LoadInt64(&pb.current))
	if !pb.NotPrint {
		fmt.Println()
	}
}

// End print and write string 'str'
func (pb *ProgressBar) FinishPrint(str string) {
	pb.Finish()
	fmt.Println(str)
}

// implement io.Writer
func (pb *ProgressBar) Write(p []byte) (n int, err error) {
	n = len(p)
	pb.Add(n)
	return
}

// implement io.Reader
func (pb *ProgressBar) Read(p []byte) (n int, err error) {
	n = len(p)
	pb.Add(n)
	return
}

func (pb *ProgressBar) write(current int64) {
	width, _ := terminalWidth()
	var percentBox, countersBox, timeLeftBox, speedBox, barBox, end, out string

	// percents
	if pb.ShowPercent {
		percent := float64(current) / (float64(pb.Total) / float64(100))
		percentBox = fmt.Sprintf(" %#.02f %% ", percent)
	}

	// counters
	if pb.ShowCounters {
		if pb.Total > 0 {
			countersBox = fmt.Sprintf("%s / %s ", Format(current, pb.Units), Format(pb.Total, pb.Units))
		} else {
			countersBox = Format(current, pb.Units) + " "
		}
	}

	// time left
	if pb.ShowTimeLeft && current > 0 {
		fromStart := time.Now().Sub(pb.startTime)
		perEntry := fromStart / time.Duration(current)
		left := time.Duration(pb.Total-current) * perEntry
		left = (left / time.Second) * time.Second
		if left > 0 {
			timeLeftBox = left.String()
		}
	}

	// speed
	if pb.ShowSpeed && current > 0 {
		fromStart := time.Now().Sub(pb.startTime)
		speed := float64(current) / (float64(fromStart) / float64(time.Second))
		speedBox = Format(int64(speed), pb.Units) + "/s "
	}

	// bar
	if pb.ShowBar {
		size := width - len(countersBox+pb.BarStart+pb.BarEnd+percentBox+timeLeftBox+speedBox)
		if size > 0 {
			curCount := int(math.Ceil((float64(current) / float64(pb.Total)) * float64(size)))
			emptCount := size - curCount
			barBox = pb.BarStart
			if emptCount < 0 {
				emptCount = 0
			}
			if curCount > size {
				curCount = size
			}
			if emptCount <= 0 {
				barBox += strings.Repeat(pb.Current, curCount)
			} else if curCount > 0 {
				barBox += strings.Repeat(pb.Current, curCount-1) + pb.CurrentN
			}

			barBox += strings.Repeat(pb.Empty, emptCount) + pb.BarEnd
		}
	}

	// check len
	out = countersBox + barBox + percentBox + speedBox + timeLeftBox
	if len(out) < width {
		end = strings.Repeat(" ", width-len(out))
	}

	out = countersBox + barBox + percentBox + speedBox + timeLeftBox

	// and print!
	switch {
	case pb.Output != nil:
		fmt.Fprint(pb.Output, out+end)
	case pb.Callback != nil:
		pb.Callback(out + end)
	case !pb.NotPrint:
		fmt.Print("\r" + out + end)
	}
}

func (pb *ProgressBar) writer() {
	var c, oc int64
	oc = -1
	for {
		if pb.isFinish {
			break
		}
		c = atomic.LoadInt64(&pb.current)
		if c != oc {
			pb.write(c)
			oc = c
		}
		time.Sleep(pb.RefreshRate)
	}
}

type window struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/coopernurse/gorp"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/jcelliott/lumber"
)

var handler http.Handler
var log lumber.Logger

func handleUnexpectedError(err error, w http.ResponseWriter) bool {
	if err != nil {
		http.Error(w, err.Error(), 500)
		return true
	}
	return false
}

type Application struct {
	electionDatabase ElectionDB
	handler          http.Handler
}

func (app *Application) configureORM(dbmap *gorp.DbMap) {
	log.Info("Configuring ORM...")
	dbmap.AddTableWithName(Election{}, "elections").SetKeys(true, "Id").ColMap("Name").SetUnique(true)

	err := dbmap.CreateTablesIfNotExists()
	checkErr(err, "Create tables failed")
	log.Info("Tables successfully created.")

	app.electionDatabase = GorpElectionDB{dbmap}
	log.Info("ORM configured.")
}

func (app *Application) configureRouting() {
	log.Info("Configuring routing...")
	router := mux.NewRouter()
	router.HandleFunc("/elections", app.ListElections).Methods("GET")
	router.HandleFunc("/elections", app.AddElection).Methods("POST")
	router.HandleFunc("/elections/{id}", app.GetElection).Methods("GET")
	app.handler = handlers.CombinedLoggingHandler(os.Stdout, router)
	log.Info("Routing configured.")
}

func CreateApplication(dbmap *gorp.DbMap) Application {
	log.Info("Creating application...")
	app := Application{}
	app.configureORM(dbmap)
	app.configureRouting()
	log.Info("Application created.")
	return app
}

func (app Application) AddElection(w http.ResponseWriter, r *http.Request) {
	requestBytes := make([]byte, r.ContentLength)
	_, err := r.Body.Read(requestBytes)
	if handleUnexpectedError(err, w) {
		return
	}
	election := Election{}
	json.Unmarshal(requestBytes, &election)
	if len(election.Name) == 0 {
		http.Error(w, "Empty name forbidden.", 400)
		return
	}
	err = app.electionDatabase.Add(election)
	if err != nil {
		if strings.Contains(err.Error(), "UNIQUE constraint failed") {
			http.Error(w, "Name taken.", 400)
			return
		}
		handleUnexpectedError(err, w)
		return
	}
}

func (app Application) GetElection(w http.ResponseWriter, r *http.Request) {
	idString := mux.Vars(r)["id"]
	id, err := strconv.Atoi(idString)
	if err == strconv.ErrSyntax {
		http.Error(w, "Invalid ID", 400)
		return
	}
	election, err := app.electionDatabase.Get(id)
	if err == sql.ErrNoRows {
		http.Error(w, "Not found", 404)
		return
	} else if handleUnexpectedError(err, w) {
		return
	}
	output, err := json.Marshal(election)
	if handleUnexpectedError(err, w) {
		return
	}
	w.Write(output)
}

func (app Application) ListElections(w http.ResponseWriter, r *http.Request) {
	elections, err := app.electionDatabase.List()
	if handleUnexpectedError(err, w) {
		return
	}
	output, err := json.Marshal(elections)
	if handleUnexpectedError(err, w) {
		return
	}
	w.Write(output)
}

func init() {
	log = lumber.NewConsoleLogger(lumber.INFO)
	log.Info("Starting up...")
	dbmap := initDb()
	application := CreateApplication(dbmap)
	handler = application.handler
}

func main() {
	log.Info("Listening and serving on port 8123...")
	err := http.ListenAndServe(":8123", handler)
	if err != nil {
		log.Fatal(err.Error())
		os.Exit(1)
	}
	log.Warn("Exiting...")
}
<commit_msg>Print out stack trace on 500.<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"net/http"
	"os"
	"runtime/debug"
	"strconv"
	"strings"

	"github.com/coopernurse/gorp"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/jcelliott/lumber"
)

var handler http.Handler
var log lumber.Logger

func handleUnexpectedError(err error, w http.ResponseWriter) bool {
	if err != nil {
		debug.PrintStack()
		log.Error(err.Error())
		http.Error(w, "Server error", 500)
		return true
	}
	return false
}

type Application struct {
	electionDatabase ElectionDB
	handler          http.Handler
}

func (app *Application) configureORM(dbmap *gorp.DbMap) {
	log.Info("Configuring ORM...")
	dbmap.AddTableWithName(Election{}, "elections").SetKeys(true, "Id").ColMap("Name").SetUnique(true)

	err := dbmap.CreateTablesIfNotExists()
	checkErr(err, "Create tables failed")
	log.Info("Tables successfully created.")

	app.electionDatabase = GorpElectionDB{dbmap}
	log.Info("ORM configured.")
}

func (app *Application) configureRouting() {
	log.Info("Configuring routing...")
	router := mux.NewRouter()
	router.HandleFunc("/elections", app.ListElections).Methods("GET")
	router.HandleFunc("/elections", app.AddElection).Methods("POST")
	router.HandleFunc("/elections/{id}", app.GetElection).Methods("GET")
	app.handler = handlers.CombinedLoggingHandler(os.Stdout, router)
	log.Info("Routing configured.")
}

func CreateApplication(dbmap *gorp.DbMap) Application {
	log.Info("Creating application...")
	app := Application{}
	app.configureORM(dbmap)
	app.configureRouting()
	log.Info("Application created.")
	return app
}

func (app Application) AddElection(w http.ResponseWriter, r *http.Request) {
	requestBytes := make([]byte, r.ContentLength)
	_, err := r.Body.Read(requestBytes)
	if handleUnexpectedError(err, w) {
		return
	}
	election := Election{}
	json.Unmarshal(requestBytes, &election)
	if len(election.Name) == 0 {
		http.Error(w, "Empty name forbidden.", 400)
		return
	}
	err = app.electionDatabase.Add(election)
	if err != nil {
		if strings.Contains(err.Error(), "UNIQUE constraint failed") {
			http.Error(w, "Name taken.", 400)
			return
		}
		handleUnexpectedError(err, w)
		return
	}
}

func (app Application) GetElection(w http.ResponseWriter, r *http.Request) {
	idString := mux.Vars(r)["id"]
	id, err := strconv.Atoi(idString)
	if err == strconv.ErrSyntax {
		http.Error(w, "Invalid ID", 400)
		return
	}
	election, err := app.electionDatabase.Get(id)
	if err == sql.ErrNoRows {
		http.Error(w, "Not found", 404)
		return
	} else if handleUnexpectedError(err, w) {
		return
	}
	output, err := json.Marshal(election)
	if handleUnexpectedError(err, w) {
		return
	}
	w.Write(output)
}

func (app Application) ListElections(w http.ResponseWriter, r *http.Request) {
	elections, err := app.electionDatabase.List()
	if handleUnexpectedError(err, w) {
		return
	}
	output, err := json.Marshal(elections)
	if handleUnexpectedError(err, w) {
		return
	}
	w.Write(output)
}

func init() {
	log = lumber.NewConsoleLogger(lumber.INFO)
	log.Info("Starting up...")
	dbmap := initDb()
	application := CreateApplication(dbmap)
	handler = application.handler
}

func main() {
	log.Info("Listening and serving on port 8123...")
	err := http.ListenAndServe(":8123", handler)
	if err != nil {
		log.Fatal(err.Error())
		os.Exit(1)
	}
	log.Warn("Exiting...")
}
<|endoftext|>


<commit_before>// +build linux

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

var psCommand = cli.Command{
	Name:      "ps",
	Usage:     "ps displays the processes running inside a container",
	ArgsUsage: `<container-id> [ps options]`,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "format, f",
			Value: "table",
			Usage: `select one of: ` + formatOptions,
		},
	},
	Action: func(context *cli.Context) error {
		if err := checkArgs(context, 1, minArgs); err != nil {
			return err
		}
		rootlessCg, err := shouldUseRootlessCgroupManager(context)
		if err != nil {
			return err
		}
		if rootlessCg {
			logrus.Warn("runc ps may fail if you don't have the full access to cgroups")
		}

		container, err := getContainer(context)
		if err != nil {
			return err
		}

		pids, err := container.Processes()
		if err != nil {
			return err
		}

		switch context.String("format") {
		case "table":
		case "json":
			return json.NewEncoder(os.Stdout).Encode(pids)
		default:
			return errors.New("invalid format option")
		}

		// [1:] is to remove command name, ex:
		// context.Args(): [containet_id ps_arg1 ps_arg2 ...]
		// psArgs:         [ps_arg1 ps_arg2 ...]
		//
		psArgs := context.Args()[1:]
		if len(psArgs) == 0 {
			psArgs = []string{"-ef"}
		}

		cmd := exec.Command("ps", psArgs...)
		output, err := cmd.CombinedOutput()
		if err != nil {
			return fmt.Errorf("%s: %s", err, output)
		}

		lines := strings.Split(string(output), "\n")
		pidIndex, err := getPidIndex(lines[0])
		if err != nil {
			return err
		}

		fmt.Println(lines[0])
		for _, line := range lines[1:] {
			if len(line) == 0 {
				continue
			}
			fields := strings.Fields(line)
			p, err := strconv.Atoi(fields[pidIndex])
			if err != nil {
				return fmt.Errorf("unexpected pid '%s': %s", fields[pidIndex], err)
			}

			for _, pid := range pids {
				if pid == p {
					fmt.Println(line)
					break
				}
			}
		}
		return nil
	},
	SkipArgReorder: true,
}

func getPidIndex(title string) (int, error) {
	titles := strings.Fields(title)

	pidIndex := -1
	for i, name := range titles {
		if name == "PID" {
			return i, nil
		}
	}

	return pidIndex, errors.New("couldn't find PID field in ps output")
}
<commit_msg>fix small typo<commit_after>// +build linux

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

var psCommand = cli.Command{
	Name:      "ps",
	Usage:     "ps displays the processes running inside a container",
	ArgsUsage: `<container-id> [ps options]`,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "format, f",
			Value: "table",
			Usage: `select one of: ` + formatOptions,
		},
	},
	Action: func(context *cli.Context) error {
		if err := checkArgs(context, 1, minArgs); err != nil {
			return err
		}
		rootlessCg, err := shouldUseRootlessCgroupManager(context)
		if err != nil {
			return err
		}
		if rootlessCg {
			logrus.Warn("runc ps may fail if you don't have the full access to cgroups")
		}

		container, err := getContainer(context)
		if err != nil {
			return err
		}

		pids, err := container.Processes()
		if err != nil {
			return err
		}

		switch context.String("format") {
		case "table":
		case "json":
			return json.NewEncoder(os.Stdout).Encode(pids)
		default:
			return errors.New("invalid format option")
		}

		// [1:] is to remove command name, ex:
		// context.Args(): [container_id ps_arg1 ps_arg2 ...]
		// psArgs:         [ps_arg1 ps_arg2 ...]
		//
		psArgs := context.Args()[1:]
		if len(psArgs) == 0 {
			psArgs = []string{"-ef"}
		}

		cmd := exec.Command("ps", psArgs...)
		output, err := cmd.CombinedOutput()
		if err != nil {
			return fmt.Errorf("%s: %s", err, output)
		}

		lines := strings.Split(string(output), "\n")
		pidIndex, err := getPidIndex(lines[0])
		if err != nil {
			return err
		}

		fmt.Println(lines[0])
		for _, line := range lines[1:] {
			if len(line) == 0 {
				continue
			}
			fields := strings.Fields(line)
			p, err := strconv.Atoi(fields[pidIndex])
			if err != nil {
				return fmt.Errorf("unexpected pid '%s': %s", fields[pidIndex], err)
			}

			for _, pid := range pids {
				if pid == p {
					fmt.Println(line)
					break
				}
			}
		}
		return nil
	},
	SkipArgReorder: true,
}

func getPidIndex(title string) (int, error) {
	titles := strings.Fields(title)

	pidIndex := -1
	for i, name := range titles {
		if name == "PID" {
			return i, nil
		}
	}

	return pidIndex, errors.New("couldn't find PID field in ps output")
}
<|endoftext|>


<commit_before>package sp

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
)

const (
	apiURL = "http://ws.spotify.com"
)

type Spotify struct{}

// The API returns strings for some things that one would expect
// to be numbers (for example, popularity))
// FloatString takes a string and converts it to a float64.
type FloatString string

func (f *FloatString) UnmarshalJSON(i interface{}) float64 {
	s := i.(string)
	n, err := strconv.ParseFloat(s, 64)
	if err != nil {
		log.Fatal(err)
	}
	return n
}

// Same as FloatString, but for integers.
type IntString string

func (f *IntString) UnmarshalJSON(i interface{}) int64 {
	s := i.(string)
	n, err := strconv.ParseInt(s, 10, 0)
	if err != nil {
		log.Fatal(err)
	}
	return n
}

type ExternalId struct {
	Type string
	Id   IntString
}

type Artist struct {
	Href       string
	Name       string
	Popularity FloatString `json:"popularity,omitempty"`
}

type Album struct {
	Name         string
	Released     string       `json:"released,omitempty"`
	Popularity   FloatString  `json:"popularity,omitempty"`
	ExternalIds  []ExternalId `json:"external-ids"`
	Length       float64      `json:"length,omitempty"`
	Href         string
	Artists      []Artist `json:"artists,omitempty"`
	Availability struct {
		Territories string
	}
}

type Info struct {
	NumResults int `json:"num_results"`
	Limit      int
	Offset     int
	Query      string
	Type       string
	Page       int
}

type SearchAlbumsResponse struct {
	Info   Info
	Albums []Album
}

type SearchArtistsResponse struct {
	Info    Info
	Artists []Artist
}

type Track struct {
	Album        Album
	Name         string
	ExternalIds  []ExternalId `json:"external-ids"`
	Popularity   FloatString
	Explicit     bool `json:"explicit,omitempty"`
	Length       float64
	Href         string
	Artists      []Artist
	TrackNumber  IntString `json:"track-number"`
	Availability struct {
		Territories string
	} `json:"availability,omitempty"`
}

type SearchTracksResponse struct {
	Info   Info
	Tracks []Track
}

type LookupArtistResponse struct {
	Info struct {
		Type string
	}
	Artist Artist
}

type LookupTrackResponse struct {
	Info struct {
		Type string
	}
	Track Track
}

func (r *Spotify) getRequest(params map[string]string, endpoint string) ([]byte, error) {
	v := url.Values{}
	for key, val := range params {
		v.Set(key, val)
	}
	u := apiURL + endpoint + "?" + v.Encode()
	resp, err := http.Get(u)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return body, nil
}

func (r *Spotify) SearchAlbums(q string) (SearchAlbumsResponse, error) {
	p := map[string]string{"q": q}
	e := "/search/1/album.json"
	resp, err := r.getRequest(p, e)
	var s SearchAlbumsResponse
	if err != nil {
		return s, err
	}
	err = json.Unmarshal(resp, &s)
	if err != nil {
		return s, err
	}
	return s, nil
}

func (r *Spotify) SearchArtists(q string) (SearchArtistsResponse, error) {
	p := map[string]string{"q": q}
	e := "/search/1/artist.json"
	resp, err := r.getRequest(p, e)
	var s SearchArtistsResponse
	if err != nil {
		return s, err
	}
	err = json.Unmarshal(resp, &s)
	if err != nil {
		return s, err
	}
	return s, nil
}

func (r *Spotify) SearchTracks(q string) (SearchTracksResponse, error) {
	p := map[string]string{"q": q}
	e := "/search/1/track.json"
	resp, err := r.getRequest(p, e)
	var s SearchTracksResponse
	if err != nil {
		return s, err
	}
	err = json.Unmarshal(resp, &s)
	if err != nil {
		return s, err
	}
	return s, nil
}

func (r *Spotify) LookupArtist(uri string) (LookupArtistResponse, error) {
	p := map[string]string{"uri": uri}
	e := "/lookup/1/.json"
	resp, err := r.getRequest(p, e)
	var l LookupArtistResponse
	if err != nil {
		return l, err
	}
	err = json.Unmarshal(resp, &l)
	if err != nil {
		return l, err
	}
	return l, nil
}

func (r *Spotify) LookupAlbum(uri string) (LookupArtistResponse, error) {
	p := map[string]string{"uri": uri}
	e := "/lookup/1/.json"
	resp, err := r.getRequest(p, e)
	var l LookupArtistResponse
	if err != nil {
		return l, err
	}
	err = json.Unmarshal(resp, &l)
	if err != nil {
		return l, err
	}
	return l, nil
}

func (r *Spotify) LookupTrack(uri string) (LookupTrackResponse, error) {
	p := map[string]string{"uri": uri}
	e := "/lookup/1/.json"
	resp, err := r.getRequest(p, e)
	var l LookupTrackResponse
	if err != nil {
		return l, err
	}
	err = json.Unmarshal(resp, &l)
	if err != nil {
		return l, err
	}
	return l, nil
}
<commit_msg>add LookupAlbumResponse<commit_after>package sp

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
)

const (
	apiURL = "http://ws.spotify.com"
)

type Spotify struct{}

// The API returns strings for some things that one would expect
// to be numbers (for example, popularity))
// FloatString takes a string and converts it to a float64.
type FloatString string

func (f *FloatString) UnmarshalJSON(i interface{}) float64 {
	s := i.(string)
	n, err := strconv.ParseFloat(s, 64)
	if err != nil {
		log.Fatal(err)
	}
	return n
}

// Same as FloatString, but for integers.
type IntString string

func (f *IntString) UnmarshalJSON(i interface{}) int64 {
	s := i.(string)
	n, err := strconv.ParseInt(s, 10, 0)
	if err != nil {
		log.Fatal(err)
	}
	return n
}

type ExternalId struct {
	Type string
	Id   IntString
}

type Artist struct {
	Href       string
	Name       string
	Popularity FloatString `json:"popularity,omitempty"`
}

type Album struct {
	Name         string
	Released     string       `json:"released,omitempty"`
	Popularity   FloatString  `json:"popularity,omitempty"`
	ExternalIds  []ExternalId `json:"external-ids"`
	Length       float64      `json:"length,omitempty"`
	Href         string
	Artists      []Artist `json:"artists,omitempty"`
	Availability struct {
		Territories string
	}
}

type Info struct {
	NumResults int `json:"num_results"`
	Limit      int
	Offset     int
	Query      string
	Type       string
	Page       int
}

type SearchAlbumsResponse struct {
	Info   Info
	Albums []Album
}

type SearchArtistsResponse struct {
	Info    Info
	Artists []Artist
}

type Track struct {
	Album        Album
	Name         string
	ExternalIds  []ExternalId `json:"external-ids"`
	Popularity   FloatString
	Explicit     bool `json:"explicit,omitempty"`
	Length       float64
	Href         string
	Artists      []Artist
	TrackNumber  IntString `json:"track-number"`
	Availability struct {
		Territories string
	} `json:"availability,omitempty"`
}

type SearchTracksResponse struct {
	Info   Info
	Tracks []Track
}

type LookupArtistResponse struct {
	Info struct {
		Type string
	}
	Artist Artist
}

type LookupTrackResponse struct {
	Info struct {
		Type string
	}
	Track Track
}

type LookupAlbumResponse struct {
	Info struct {
		Type string
	}
	Album struct {
		ArtistId    string `json:"artist-id"`
		Name        string
		Artist      string
		ExternalIds []struct {
			Type string
			Id   string
		} `json:"external-ids"`
		Released string
		Tracks   []struct {
			Available bool
			Href      string
			Artists   []struct {
				Href string
				Name string
			}
			Name string
		}
	}
}

func (r *Spotify) getRequest(params map[string]string, endpoint string) ([]byte, error) {
	v := url.Values{}
	for key, val := range params {
		v.Set(key, val)
	}
	u := apiURL + endpoint + "?" + v.Encode()
	resp, err := http.Get(u)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return body, nil
}

func (r *Spotify) SearchAlbums(q string) (SearchAlbumsResponse, error) {
	p := map[string]string{"q": q}
	e := "/search/1/album.json"
	resp, err := r.getRequest(p, e)
	var s SearchAlbumsResponse
	if err != nil {
		return s, err
	}
	err = json.Unmarshal(resp, &s)
	if err != nil {
		return s, err
	}
	return s, nil
}

func (r *Spotify) SearchArtists(q string) (SearchArtistsResponse, error) {
	p := map[string]string{"q": q}
	e := "/search/1/artist.json"
	resp, err := r.getRequest(p, e)
	var s SearchArtistsResponse
	if err != nil {
		return s, err
	}
	err = json.Unmarshal(resp, &s)
	if err != nil {
		return s, err
	}
	return s, nil
}

func (r *Spotify) SearchTracks(q string) (SearchTracksResponse, error) {
	p := map[string]string{"q": q}
	e := "/search/1/track.json"
	resp, err := r.getRequest(p, e)
	var s SearchTracksResponse
	if err != nil {
		return s, err
	}
	err = json.Unmarshal(resp, &s)
	if err != nil {
		return s, err
	}
	return s, nil
}

func (r *Spotify) LookupArtist(uri string) (LookupArtistResponse, error) {
	p := map[string]string{"uri": uri}
	e := "/lookup/1/.json"
	resp, err := r.getRequest(p, e)
	var l LookupArtistResponse
	if err != nil {
		return l, err
	}
	err = json.Unmarshal(resp, &l)
	if err != nil {
		return l, err
	}
	return l, nil
}

func (r *Spotify) LookupAlbum(uri string) (LookupAlbumResponse, error) {
	p := map[string]string{"uri": uri}
	e := "/lookup/1/.json"
	resp, err := r.getRequest(p, e)
	var l LookupAlbumResponse
	if err != nil {
		return l, err
	}
	err = json.Unmarshal(resp, &l)
	if err != nil {
		return l, err
	}
	return l, nil
}

func (r *Spotify) LookupTrack(uri string) (LookupTrackResponse, error) {
	p := map[string]string{"uri": uri}
	e := "/lookup/1/.json"
	resp, err := r.getRequest(p, e)
	var l LookupTrackResponse
	if err != nil {
		return l, err
	}
	err = json.Unmarshal(resp, &l)
	if err != nil {
		return l, err
	}
	return l, nil
}
<|endoftext|>


<commit_before>package firebase

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

const (
	serverTimestampValue = `{".sv":"timestamp"}`
)

// ServerTimestamp provides a json.Marshal'able (and Unmarshal'able) type for
// use with Firebase.
type ServerTimestamp time.Time

// MarshalJSON satisfies the json.Marshaler interface.
func (st ServerTimestamp) MarshalJSON() ([]byte, error) {
	t := time.Time(st)

	// special firebase value
	if t.IsZero() {
		return []byte(serverTimestampValue), nil
	}

	return []byte(strconv.FormatInt(t.UnixNano()/int64(time.Millisecond), 10)), nil
}

// UnmarshalJSON satisfies the json.Unmarshaler interface.
func (st *ServerTimestamp) UnmarshalJSON(buf []byte) error {
	// special firebase value
	if string(buf) == serverTimestampValue {
		*st = ServerTimestamp(time.Now())
		return nil
	}

	i, err := strconv.ParseInt(string(buf), 10, 64)
	if err != nil {
		return err
	}

	*st = ServerTimestamp(time.Unix(0, i*int64(time.Millisecond)))
	return nil
}

// Time returns the ServerTimestamp as time.Time.
func (st ServerTimestamp) Time() time.Time {
	return time.Time(st)
}

// String satisfies the stringer interface.
func (st ServerTimestamp) String() string {
	return time.Time(st).String()
}

// Time provides a json.Marshal'able (and Unmarshal'able) type for that is
// compatible with Firebase server timestamps.
//
// The JSON representation of time is a JSON number of milliseconds since the
// Unix epoch.
type Time time.Time

// MarshalJSON satisfies the json.Marshaler interface.
func (t Time) MarshalJSON() ([]byte, error) {
	z := time.Time(t)

	return []byte(strconv.FormatInt(z.UnixNano()/int64(time.Millisecond), 10)), nil
}

// UnmarshalJSON satisfies the json.Unmarshaler interface.
func (t *Time) UnmarshalJSON(buf []byte) error {
	i, err := strconv.ParseInt(string(buf), 10, 64)
	if err != nil {
		return err
	}

	*t = Time(time.Unix(0, i*int64(time.Millisecond)))
	return nil
}

// Time returns the Time as time.Time.
func (t Time) Time() time.Time {
	return time.Time(t)
}

// String satisfies the stringer interface.
func (t Time) String() string {
	return time.Time(t).String()
}

// Error is a general Firebase error.
type Error struct {
	Err string `json:"error"`
}

// Error satisifies the error interface.
func (e *Error) Error() string {
	return "firebase: " + e.Err
}

// checkServerError looks at a http.Response and determines if it encountered
// an error, and marshals the error into a Error if it did.
func checkServerError(res *http.Response) error {
	// some kind of server error
	if res.StatusCode < 200 || res.StatusCode > 299 {
		buf, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return &Error{
				Err: fmt.Sprintf("unable to read server error: %v", err),
			}
		}
		if len(buf) < 1 {
			return &Error{
				Err: fmt.Sprintf("empty server error: %s (%d)", res.Status, res.StatusCode),
			}
		}

		var e Error
		err = json.Unmarshal(buf, &e)
		if err != nil {
			return &Error{
				Err: fmt.Sprintf("unknown server error: %s (%d)", string(buf), res.StatusCode),
			}
		}

		return &e
	}

	return nil
}
<commit_msg>Fixing issue with parsing null to time types<commit_after>package firebase

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

const (
	serverTimestampValue = `{".sv":"timestamp"}`
)

// ServerTimestamp provides a json.Marshal'able (and Unmarshal'able) type for
// use with Firebase.
type ServerTimestamp time.Time

// MarshalJSON satisfies the json.Marshaler interface.
func (st ServerTimestamp) MarshalJSON() ([]byte, error) {
	t := time.Time(st)

	// special firebase value
	if t.IsZero() {
		return []byte(serverTimestampValue), nil
	}

	return []byte(strconv.FormatInt(t.UnixNano()/int64(time.Millisecond), 10)), nil
}

// UnmarshalJSON satisfies the json.Unmarshaler interface.
func (st *ServerTimestamp) UnmarshalJSON(buf []byte) error {
	// special firebase value
	v := string(buf)
	switch v {
	case serverTimestampValue:
		*st = ServerTimestamp(time.Now())
		return nil

	case "null":
		*st = ServerTimestamp{}
		return nil
	}

	i, err := strconv.ParseInt(v, 10, 64)
	if err != nil {
		return err
	}

	*st = ServerTimestamp(time.Unix(0, i*int64(time.Millisecond)))
	return nil
}

// Time returns the ServerTimestamp as time.Time.
func (st ServerTimestamp) Time() time.Time {
	return time.Time(st)
}

// String satisfies the stringer interface.
func (st ServerTimestamp) String() string {
	return time.Time(st).String()
}

// Time provides a json.Marshal'able (and Unmarshal'able) type for that is
// compatible with Firebase server timestamps.
//
// The JSON representation of time is a JSON number of milliseconds since the
// Unix epoch.
type Time time.Time

// MarshalJSON satisfies the json.Marshaler interface.
func (t Time) MarshalJSON() ([]byte, error) {
	z := time.Time(t)

	return []byte(strconv.FormatInt(z.UnixNano()/int64(time.Millisecond), 10)), nil
}

// UnmarshalJSON satisfies the json.Unmarshaler interface.
func (t *Time) UnmarshalJSON(buf []byte) error {
	v := string(buf)
	if v == "null" {
		*t = Time{}
		return nil
	}

	i, err := strconv.ParseInt(v, 10, 64)
	if err != nil {
		return err
	}

	*t = Time(time.Unix(0, i*int64(time.Millisecond)))
	return nil
}

// Time returns the Time as time.Time.
func (t Time) Time() time.Time {
	return time.Time(t)
}

// String satisfies the stringer interface.
func (t Time) String() string {
	return time.Time(t).String()
}

// Error is a general Firebase error.
type Error struct {
	Err string `json:"error"`
}

// Error satisifies the error interface.
func (e *Error) Error() string {
	return "firebase: " + e.Err
}

// checkServerError looks at a http.Response and determines if it encountered
// an error, and marshals the error into a Error if it did.
func checkServerError(res *http.Response) error {
	// some kind of server error
	if res.StatusCode < 200 || res.StatusCode > 299 {
		buf, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return &Error{
				Err: fmt.Sprintf("unable to read server error: %v", err),
			}
		}
		if len(buf) < 1 {
			return &Error{
				Err: fmt.Sprintf("empty server error: %s (%d)", res.Status, res.StatusCode),
			}
		}

		var e Error
		err = json.Unmarshal(buf, &e)
		if err != nil {
			return &Error{
				Err: fmt.Sprintf("unknown server error: %s (%d)", string(buf), res.StatusCode),
			}
		}

		return &e
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcutil

import (
	"bytes"
	"io"

	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
)

// TxIndexUnknown is the value returned for a transaction index that is unknown.
// This is typically because the transaction has not been inserted into a block
// yet.
const TxIndexUnknown = -1

// Tx defines a bitcoin transaction that provides easier and more efficient
// manipulation of raw transactions.  It also memoizes the hash for the
// transaction on its first access so subsequent accesses don't have to repeat
// the relatively expensive hashing operations.
type Tx struct {
	msgTx   *wire.MsgTx     // Underlying MsgTx
	txHash  *chainhash.Hash // Cached transaction hash
	txIndex int             // Position within a block or TxIndexUnknown
}

// MsgTx returns the underlying wire.MsgTx for the transaction.
func (t *Tx) MsgTx() *wire.MsgTx {
	// Return the cached transaction.
	return t.msgTx
}

// Hash returns the hash of the transaction.  This is equivalent to
// calling TxHash on the underlying wire.MsgTx, however it caches the
// result so subsequent calls are more efficient.
func (t *Tx) Hash() *chainhash.Hash {
	// Return the cached hash if it has already been generated.
	if t.txHash != nil {
		return t.txHash
	}

	// Cache the hash and return it.
	hash := t.msgTx.TxHash()
	t.txHash = &hash
	return &hash
}

// Index returns the saved index of the transaction within a block.  This value
// will be TxIndexUnknown if it hasn't already explicitly been set.
func (t *Tx) Index() int {
	return t.txIndex
}

// SetIndex sets the index of the transaction in within a block.
func (t *Tx) SetIndex(index int) {
	t.txIndex = index
}

// NewTx returns a new instance of a bitcoin transaction given an underlying
// wire.MsgTx.  See Tx.
func NewTx(msgTx *wire.MsgTx) *Tx {
	return &Tx{
		msgTx:   msgTx,
		txIndex: TxIndexUnknown,
	}
}

// NewTxFromBytes returns a new instance of a bitcoin transaction given the
// serialized bytes.  See Tx.
func NewTxFromBytes(serializedTx []byte) (*Tx, error) {
	br := bytes.NewReader(serializedTx)
	return NewTxFromReader(br)
}

// NewTxFromReader returns a new instance of a bitcoin transaction given a
// Reader to deserialize the transaction.  See Tx.
func NewTxFromReader(r io.Reader) (*Tx, error) {
	// Deserialize the bytes into a MsgTx.
	var msgTx wire.MsgTx
	err := msgTx.Deserialize(r)
	if err != nil {
		return nil, err
	}

	t := Tx{
		msgTx:   &msgTx,
		txIndex: TxIndexUnknown,
	}
	return &t, nil
}
<commit_msg>add new WitnessHash method to Tx<commit_after>// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcutil

import (
	"bytes"
	"io"

	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
)

// TxIndexUnknown is the value returned for a transaction index that is unknown.
// This is typically because the transaction has not been inserted into a block
// yet.
const TxIndexUnknown = -1

// Tx defines a bitcoin transaction that provides easier and more efficient
// manipulation of raw transactions.  It also memoizes the hash for the
// transaction on its first access so subsequent accesses don't have to repeat
// the relatively expensive hashing operations.
type Tx struct {
	msgTx         *wire.MsgTx     // Underlying MsgTx
	txHash        *chainhash.Hash // Cached transaction hash
	txHashWitness *chainhash.Hash // Cached transaction witness hash
	txIndex       int             // Position within a block or TxIndexUnknown
}

// MsgTx returns the underlying wire.MsgTx for the transaction.
func (t *Tx) MsgTx() *wire.MsgTx {
	// Return the cached transaction.
	return t.msgTx
}

// Hash returns the hash of the transaction.  This is equivalent to
// calling TxHash on the underlying wire.MsgTx, however it caches the
// result so subsequent calls are more efficient.
func (t *Tx) Hash() *chainhash.Hash {
	// Return the cached hash if it has already been generated.
	if t.txHash != nil {
		return t.txHash
	}

	// Cache the hash and return it.
	hash := t.msgTx.TxHash()
	t.txHash = &hash
	return &hash
}

// WitnessHash returns the witness hash (wtxid) of the transaction.  This is
// equivalent to calling WitnessHash on the underlying wire.MsgTx, however it
// caches the result so subsequent calls are more efficient.
func (t *Tx) WitnessHash() *chainhash.Hash {
	// Return the cached hash if it has already been generated.
	if t.txHashWitness != nil {
		return t.txHashWitness
	}

	// Cache the hash and return it.
	hash := t.msgTx.WitnessHash()
	t.txHashWitness = &hash
	return &hash
}

// Index returns the saved index of the transaction within a block.  This value
// will be TxIndexUnknown if it hasn't already explicitly been set.
func (t *Tx) Index() int {
	return t.txIndex
}

// SetIndex sets the index of the transaction in within a block.
func (t *Tx) SetIndex(index int) {
	t.txIndex = index
}

// NewTx returns a new instance of a bitcoin transaction given an underlying
// wire.MsgTx.  See Tx.
func NewTx(msgTx *wire.MsgTx) *Tx {
	return &Tx{
		msgTx:   msgTx,
		txIndex: TxIndexUnknown,
	}
}

// NewTxFromBytes returns a new instance of a bitcoin transaction given the
// serialized bytes.  See Tx.
func NewTxFromBytes(serializedTx []byte) (*Tx, error) {
	br := bytes.NewReader(serializedTx)
	return NewTxFromReader(br)
}

// NewTxFromReader returns a new instance of a bitcoin transaction given a
// Reader to deserialize the transaction.  See Tx.
func NewTxFromReader(r io.Reader) (*Tx, error) {
	// Deserialize the bytes into a MsgTx.
	var msgTx wire.MsgTx
	err := msgTx.Deserialize(r)
	if err != nil {
		return nil, err
	}

	t := Tx{
		msgTx:   &msgTx,
		txIndex: TxIndexUnknown,
	}
	return &t, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"

	"github.com/nsf/termbox-go"
)

const (
	headerRows = 1

	pidColumnTitle = "PID"
	pidColumnWidth = 5 // 32768 is the max pid on my system

	userColumnTitle = "USER"
	userColumnWidth = 8

	cpuColumnTitle = "%CPU"
	cpuColumnWidth = 5

	timeColumnTitle = "TIME+"
	timeColumnWidth = 9

	commandColumnTitle = "COMMAND"

	titleFG     = termbox.ColorBlack
	titleBG     = termbox.ColorGreen
	titleSortBG = termbox.ColorCyan
)

type UI struct {
	pm *ProcessMonitor

	x int
	y int

	fg termbox.Attribute
	bg termbox.Attribute

	start    int
	selected int

	width  int
	height int
}

func NewUI(pm *ProcessMonitor) *UI {
	ui := &UI{
		pm: pm,
	}
	ui.updateTerminalSize()
	return ui
}

func (ui *UI) Draw() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	ui.drawHeader()
	for i, process := range ui.visibleProcesses() {
		ui.drawProcess(i, process)
	}
	termbox.Flush()
}

func (ui *UI) drawHeader() {
	ui.y, ui.x = 0, 0
	ui.fg, ui.bg = titleFG, titleBG

	ui.bg = bgForTitle("pid")
	ui.writeColumn(pidColumnTitle, pidColumnWidth, true)

	ui.bg = bgForTitle("user")
	ui.writeColumn(userColumnTitle, userColumnWidth, false)

	ui.bg = bgForTitle("cpu")
	ui.writeColumn(cpuColumnTitle, cpuColumnWidth, true)

	ui.bg = bgForTitle("time")
	ui.writeColumn(timeColumnTitle, timeColumnWidth, true)

	ui.bg = bgForTitle("command")
	ui.writeColumn(commandColumnTitle, len(commandColumnTitle), false)

	ui.bg = titleBG
	ui.writeLastColumn("")

	ui.y++
}

func (ui *UI) drawProcess(i int, process *Process) {
	ui.x = 0
	ui.fg, ui.bg = termbox.ColorDefault, termbox.ColorDefault
	if i == ui.selected {
		ui.fg, ui.bg = termbox.ColorBlack, termbox.ColorCyan
	}

	// PID
	pidColumn := strconv.FormatUint(process.PID, 10)
	ui.writeColumn(pidColumn, pidColumnWidth, true)

	// User
	maxUserLen := len(process.User.Username)
	if maxUserLen > userColumnWidth {
		maxUserLen = userColumnWidth
	}
	userColumn := process.User.Username[0:maxUserLen]
	ui.writeColumn(userColumn, userColumnWidth, false)

	// CPU Percentage
	totalUsage := float64(ui.pm.CPUTimeDiff)
	userUsage := 100 * float64(process.UtimeDiff) / totalUsage
	systemUsage := 100 * float64(process.StimeDiff) / totalUsage
	cpuColumn := fmt.Sprintf("%.1f", (userUsage+systemUsage)*float64(ui.pm.NumCPUs))
	ui.writeColumn(cpuColumn, cpuColumnWidth, true)

	// Time
	hertz := uint64(100)
	// TODO: this has only been tested on my Ubuntu 14.04 system that has
	// a CLK_TCK of 100. Test on other configurations. (getconf CLK_TCK)
	totalJiffies := process.Utime + process.Stime
	totalSeconds := totalJiffies / hertz

	minutes := totalSeconds / 60
	seconds := totalSeconds % 60
	hundredths := totalJiffies % hertz

	// FIXME: this won't be pretty when minutes gets big, maybe format hours?
	timeColumn := fmt.Sprintf("%d:%02d:%02d", minutes, seconds, hundredths)
	ui.writeColumn(timeColumn, timeColumnWidth, true)

	// Command
	commandColumn := process.Name
	if verboseFlag {
		commandColumn = process.Command
	}
	ui.writeLastColumn(commandColumn)

	ui.y++
}

func (ui *UI) HandleResize() {
	ui.updateTerminalSize()
}

func (ui *UI) HandleDown() {
	if ui.shouldScrollDown() {
		ui.scrollDown()
		return
	}

	if !ui.bottomSelected() {
		ui.down()
	}
}

func (ui *UI) HandleUp() {
	if ui.shouldScrollUp() {
		ui.scrollUp()
		return
	}

	if !ui.topSelected() {
		ui.up()
	}
}

func (ui *UI) down() {
	ui.selected++
}

func (ui *UI) up() {
	ui.selected--
}

func (ui *UI) scrollDown() {
	ui.start++
}

func (ui *UI) scrollUp() {
	ui.start--
}

func (ui *UI) shouldScrollDown() bool {
	return ui.bottomSelected() && ui.moreProcessesDown()
}

func (ui *UI) shouldScrollUp() bool {
	return ui.topSelected() && ui.moreProcessesUp()
}

func (ui *UI) bottomSelected() bool {
	bottom := len(ui.pm.List) - 1
	if len(ui.pm.List) > ui.numProcessesOnScreen() {
		// Not all processes fit on the same screen
		bottom = ui.numProcessesOnScreen() - 1
	}
	return ui.selected == bottom
}

func (ui *UI) topSelected() bool {
	return ui.selected == 0
}

func (ui *UI) moreProcessesDown() bool {
	return len(ui.pm.List)-ui.start > ui.numProcessesOnScreen()
}

func (ui *UI) moreProcessesUp() bool {
	return ui.start > 0
}

func (ui *UI) numProcessesOnScreen() int {
	return ui.height - headerRows
}

func (ui *UI) updateTerminalSize() {
	ui.width, ui.height = termbox.Size()
}

func (ui *UI) visibleProcesses() []*Process {
	// Maybe all processes will fit on the same screen
	end := len(ui.pm.List)

	// Maybe they won't
	if end > ui.numProcessesOnScreen() {
		end = ui.start + ui.numProcessesOnScreen()

		// Maybe we need to scroll up because some process(es) died
		if end > len(ui.pm.List) {
			diff := end - len(ui.pm.List)
			ui.start -= diff
			end -= diff
		}
	}

	// When bottom process is selected and a process dies, update selected
	// to the new bottom process.
	if ui.selected >= end {
		ui.selected = end - 1
	}

	return ui.pm.List[ui.start:end]
}

func (ui *UI) writeColumn(s string, columnWidth int, rightAlign bool) {
	if rightAlign {
		for i := 0; i < columnWidth-len(s); i++ {
			ui.setCell(' ')
		}
	}

	for _, ch := range s {
		ui.setCell(ch)
	}

	if !rightAlign {
		for i := 0; i < columnWidth-len(s); i++ {
			ui.setCell(' ')
		}
	}

	ui.setCell(' ')
}

func (ui *UI) writeLastColumn(s string) {
	for _, ch := range s {
		ui.setCell(ch)
	}

	for ui.x < ui.width {
		ui.setCell(' ')
	}
}

func (ui *UI) setCell(ch rune) {
	termbox.SetCell(ui.x, ui.y, ch, ui.fg, ui.bg)
	ui.x++
}

func bgForTitle(column string) termbox.Attribute {
	if column == sortFlag {
		return titleSortBG
	}
	return titleBG
}
<commit_msg>Unicode support<commit_after>package main

import (
	"fmt"
	"strconv"

	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
)

const (
	headerRows = 1

	pidColumnTitle = "PID"
	pidColumnWidth = 5 // 32768 is the max pid on my system

	userColumnTitle = "USER"
	userColumnWidth = 8

	cpuColumnTitle = "%CPU"
	cpuColumnWidth = 5

	timeColumnTitle = "TIME+"
	timeColumnWidth = 9

	commandColumnTitle = "COMMAND"

	titleFG     = termbox.ColorBlack
	titleBG     = termbox.ColorGreen
	titleSortBG = termbox.ColorCyan
)

type UI struct {
	pm *ProcessMonitor

	x int
	y int

	fg termbox.Attribute
	bg termbox.Attribute

	start    int
	selected int

	width  int
	height int
}

func NewUI(pm *ProcessMonitor) *UI {
	ui := &UI{
		pm: pm,
	}
	ui.updateTerminalSize()
	return ui
}

func (ui *UI) Draw() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	ui.drawHeader()
	for i, process := range ui.visibleProcesses() {
		ui.drawProcess(i, process)
	}
	termbox.Flush()
}

func (ui *UI) drawHeader() {
	ui.y, ui.x = 0, 0
	ui.fg, ui.bg = titleFG, titleBG

	ui.bg = bgForTitle("pid")
	ui.writeColumn(pidColumnTitle, pidColumnWidth, true)

	ui.bg = bgForTitle("user")
	ui.writeColumn(userColumnTitle, userColumnWidth, false)

	ui.bg = bgForTitle("cpu")
	ui.writeColumn(cpuColumnTitle, cpuColumnWidth, true)

	ui.bg = bgForTitle("time")
	ui.writeColumn(timeColumnTitle, timeColumnWidth, true)

	ui.bg = bgForTitle("command")
	ui.writeColumn(commandColumnTitle, len(commandColumnTitle), false)

	ui.bg = titleBG
	ui.writeLastColumn("")

	ui.y++
}

func (ui *UI) drawProcess(i int, process *Process) {
	ui.x = 0
	ui.fg, ui.bg = termbox.ColorDefault, termbox.ColorDefault
	if i == ui.selected {
		ui.fg, ui.bg = termbox.ColorBlack, termbox.ColorCyan
	}

	// PID
	pidColumn := strconv.FormatUint(process.PID, 10)
	ui.writeColumn(pidColumn, pidColumnWidth, true)

	// User
	userColumn := runewidth.Truncate(process.User.Username, userColumnWidth, "+")
	ui.writeColumn(userColumn, userColumnWidth, false)

	// CPU Percentage
	totalUsage := float64(ui.pm.CPUTimeDiff)
	userUsage := 100 * float64(process.UtimeDiff) / totalUsage
	systemUsage := 100 * float64(process.StimeDiff) / totalUsage
	cpuColumn := fmt.Sprintf("%.1f", (userUsage+systemUsage)*float64(ui.pm.NumCPUs))
	ui.writeColumn(cpuColumn, cpuColumnWidth, true)

	// Time
	hertz := uint64(100)
	// TODO: this has only been tested on my Ubuntu 14.04 system that has
	// a CLK_TCK of 100. Test on other configurations. (getconf CLK_TCK)
	totalJiffies := process.Utime + process.Stime
	totalSeconds := totalJiffies / hertz

	minutes := totalSeconds / 60
	seconds := totalSeconds % 60
	hundredths := totalJiffies % hertz

	// FIXME: this won't be pretty when minutes gets big, maybe format hours?
	timeColumn := fmt.Sprintf("%d:%02d:%02d", minutes, seconds, hundredths)
	ui.writeColumn(timeColumn, timeColumnWidth, true)

	// Command
	commandColumn := process.Name
	if verboseFlag {
		commandColumn = process.Command
	}
	ui.writeLastColumn(commandColumn)

	ui.y++
}

func (ui *UI) HandleResize() {
	ui.updateTerminalSize()
}

func (ui *UI) HandleDown() {
	if ui.shouldScrollDown() {
		ui.scrollDown()
		return
	}

	if !ui.bottomSelected() {
		ui.down()
	}
}

func (ui *UI) HandleUp() {
	if ui.shouldScrollUp() {
		ui.scrollUp()
		return
	}

	if !ui.topSelected() {
		ui.up()
	}
}

func (ui *UI) down() {
	ui.selected++
}

func (ui *UI) up() {
	ui.selected--
}

func (ui *UI) scrollDown() {
	ui.start++
}

func (ui *UI) scrollUp() {
	ui.start--
}

func (ui *UI) shouldScrollDown() bool {
	return ui.bottomSelected() && ui.moreProcessesDown()
}

func (ui *UI) shouldScrollUp() bool {
	return ui.topSelected() && ui.moreProcessesUp()
}

func (ui *UI) bottomSelected() bool {
	bottom := len(ui.pm.List) - 1
	if len(ui.pm.List) > ui.numProcessesOnScreen() {
		// Not all processes fit on the same screen
		bottom = ui.numProcessesOnScreen() - 1
	}
	return ui.selected == bottom
}

func (ui *UI) topSelected() bool {
	return ui.selected == 0
}

func (ui *UI) moreProcessesDown() bool {
	return len(ui.pm.List)-ui.start > ui.numProcessesOnScreen()
}

func (ui *UI) moreProcessesUp() bool {
	return ui.start > 0
}

func (ui *UI) numProcessesOnScreen() int {
	return ui.height - headerRows
}

func (ui *UI) updateTerminalSize() {
	ui.width, ui.height = termbox.Size()
}

func (ui *UI) visibleProcesses() []*Process {
	// Maybe all processes will fit on the same screen
	end := len(ui.pm.List)

	// Maybe they won't
	if end > ui.numProcessesOnScreen() {
		end = ui.start + ui.numProcessesOnScreen()

		// Maybe we need to scroll up because some process(es) died
		if end > len(ui.pm.List) {
			diff := end - len(ui.pm.List)
			ui.start -= diff
			end -= diff
		}
	}

	// When bottom process is selected and a process dies, update selected
	// to the new bottom process.
	if ui.selected >= end {
		ui.selected = end - 1
	}

	return ui.pm.List[ui.start:end]
}

func (ui *UI) writeColumn(s string, columnWidth int, rightAlign bool) {
	sWidth := runewidth.StringWidth(s)
	if rightAlign {
		for i := 0; i < columnWidth-sWidth; i++ {
			ui.setCell(' ')
		}
	}

	for _, ch := range s {
		ui.setCell(ch)
	}

	if !rightAlign {
		for i := 0; i < columnWidth-sWidth; i++ {
			ui.setCell(' ')
		}
	}

	ui.setCell(' ')
}

func (ui *UI) writeLastColumn(s string) {
	for _, ch := range s {
		ui.setCell(ch)
	}

	for ui.x < ui.width {
		ui.setCell(' ')
	}
}

func (ui *UI) setCell(ch rune) {
	termbox.SetCell(ui.x, ui.y, ch, ui.fg, ui.bg)
	ui.x += runewidth.RuneWidth(ch)
}

func bgForTitle(column string) termbox.Attribute {
	if column == sortFlag {
		return titleSortBG
	}
	return titleBG
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"path"

	"github.com/nelsam/gxui"
	"github.com/nelsam/gxui/themes/dark"
)

var (
	dr gxui.Driver
)

func uiMain(dri gxui.Driver) {
	dr = dri
	catAdap := &StrList{}
	catAdap.SetStrings(cats)
	appAdap := &prtapAdap{}
	th := dark.CreateTheme(dr)
	win := th.CreateWindow(500, 500, "LinuxPA")
	top := th.CreateLinearLayout()
	top.SetDirection(gxui.BottomToTop)
	top.SetHorizontalAlignment(gxui.AlignRight)
	spl := th.CreateSplitterLayout()
	spl.SetOrientation(gxui.Horizontal)
	catlist := th.CreateList()
	catlist.SetAdapter(catAdap)
	catlist.OnItemClicked(func(_ gxui.MouseEvent, it gxui.AdapterItem) {
		str := it.(string)
		appAdap.SetApps(appMaster[str])
	})
	applist := th.CreateList()
	applist.SetAdapter(appAdap)
	spl.AddChild(catlist)
	spl.AddChild(applist)
	but := th.CreateLinearLayout()
	but.SetDirection(gxui.RightToLeft)
	launch := th.CreateButton()
	launch.SetText("Launch!")
	launch.OnClick(func(gxui.MouseEvent) {
		if appAdap.ItemIndex(applist.Selected()) != -1 {
			app := applist.Selected().(prtap)
			dir, fi := path.Split(app.ex)
			var cmd *exec.Cmd
			if commEnbl {
				cmd = exec.Command("/bin/sh", "-c", ". "+common+" || exit 1;cd \""+dir+"\"; \"./"+fi+"\"")
			} else {
				cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"")
			}
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Start()
		}
	})
	but.AddChild(launch)
	top.AddChild(but)
	top.AddChild(spl)
	win.AddChild(top)
	win.OnClose(func() {
		dr.Terminate()
	})
}
<commit_msg>Stderr output<commit_after>package main

import (
	"os"
	"os/exec"
	"path"

	"github.com/nelsam/gxui"
	"github.com/nelsam/gxui/themes/dark"
)

var (
	dr gxui.Driver
)

func uiMain(dri gxui.Driver) {
	dr = dri
	catAdap := &StrList{}
	catAdap.SetStrings(cats)
	appAdap := &prtapAdap{}
	th := dark.CreateTheme(dr)
	win := th.CreateWindow(500, 500, "LinuxPA")
	top := th.CreateLinearLayout()
	top.SetDirection(gxui.BottomToTop)
	top.SetHorizontalAlignment(gxui.AlignRight)
	spl := th.CreateSplitterLayout()
	spl.SetOrientation(gxui.Horizontal)
	catlist := th.CreateList()
	catlist.SetAdapter(catAdap)
	catlist.OnItemClicked(func(_ gxui.MouseEvent, it gxui.AdapterItem) {
		str := it.(string)
		appAdap.SetApps(appMaster[str])
	})
	applist := th.CreateList()
	applist.SetAdapter(appAdap)
	spl.AddChild(catlist)
	spl.AddChild(applist)
	but := th.CreateLinearLayout()
	but.SetDirection(gxui.RightToLeft)
	launch := th.CreateButton()
	launch.SetText("Launch!")
	launch.OnClick(func(gxui.MouseEvent) {
		if appAdap.ItemIndex(applist.Selected()) != -1 {
			app := applist.Selected().(prtap)
			dir, fi := path.Split(app.ex)
			var cmd *exec.Cmd
			if commEnbl {
				cmd = exec.Command("/bin/sh", "-c", ". "+common+" || exit 1;cd \""+dir+"\"; \"./"+fi+"\"")
			} else {
				cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"")
			}
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			go cmd.Run()
		}
	})
	but.AddChild(launch)
	top.AddChild(but)
	top.AddChild(spl)
	win.AddChild(top)
	win.OnClose(func() {
		dr.Terminate()
	})
}
<|endoftext|>


<commit_before>/*
Problem 1 - Multiples of 3 and 5
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.
*/

package main

import "fmt"

func main() {
  sum := 0

  for i := 0; i < 1000; i++ {
    if (i % 3 == 0)  || (i % 5 == 0) {
      sum += i
    }
  }

  fmt.Println(sum)
}<commit_msg>Formatted 1.go.<commit_after>/*
Problem 1 - Multiples of 3 and 5
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9.
The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.
*/

package main

import "fmt"

func main() {
  sum := 0

  for i := 0; i < 1000; i++ {
    if (i % 3 == 0)  || (i % 5 == 0) {
      sum += i
    }
  }

  fmt.Println(sum)
}
<|endoftext|>


<commit_before>package h2spec

import (
	"fmt"
	"github.com/bradfitz/http2"
)

func HeaderCompressionAndDecompressionTestGroup(ctx *Context) *TestGroup {
	tg := NewTestGroup("4.3", "Header Compression and Decompression")

	tg.AddTestCase(NewTestCase(
		"Sends invalid header block fragment",
		"The endpoint MUST terminate the connection with a connection error of type COMPRESSION_ERROR.",
		func(ctx *Context) (expected []Result, actual Result) {
			http2Conn := CreateHttp2Conn(ctx, true)
			defer http2Conn.conn.Close()

			fmt.Fprintf(http2Conn.conn, "\x00\x00\x14\x01\x05\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")

			actualCodes := []http2.ErrCode{http2.ErrCodeCompression}
			return TestConnectionError(ctx, http2Conn, actualCodes)
		},
	))

	return tg
}
<commit_msg>Send only first byte of literal<commit_after>package h2spec

import (
	"fmt"
	"github.com/bradfitz/http2"
)

func HeaderCompressionAndDecompressionTestGroup(ctx *Context) *TestGroup {
	tg := NewTestGroup("4.3", "Header Compression and Decompression")

	tg.AddTestCase(NewTestCase(
		"Sends invalid header block fragment",
		"The endpoint MUST terminate the connection with a connection error of type COMPRESSION_ERROR.",
		func(ctx *Context) (expected []Result, actual Result) {
			http2Conn := CreateHttp2Conn(ctx, true)
			defer http2Conn.conn.Close()

			// Literal Header Field with Incremental Indexing without Length and String segment
			fmt.Fprintf(http2Conn.conn, "\x00\x00\x01\x01\x05\x00\x00\x00\x01\x40")

			actualCodes := []http2.ErrCode{http2.ErrCodeCompression}
			return TestConnectionError(ctx, http2Conn, actualCodes)
		},
	))

	return tg
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

var settings struct {
	DailyTarget int
	Database    string
}

func init() {
	flag.IntVar(&settings.DailyTarget, "target", 900, "The number of words to write daily")
	flag.StringVar(&settings.Database, "db", "diary.db", "The name of the database file")
}

func main() {
	flag.Parse()

	db, err := sql.Open("sqlite3", settings.Database)
	if err != nil {
		panic(err)
	}

	_, err = db.Exec("CREATE TABLE IF NOT EXISTS entries (date TEXT PRIMARY KEY, text TEXT, words INTEGER)")
	if err != nil {
		panic(err)
	}

	if flag.NArg() >= 1 {
		cmd := flag.Arg(0)
		if cmd == "import" {
			importEntry(db)
			return
		}
	}

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		now := time.Now()
		days := daysOfMonth(now)
		annotatedDays, err := annotateDays(db, days)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}

		text := ""
		words := 0
		rows, err := db.Query("SELECT text, words FROM entries WHERE date = ?", now.Format("2006-01-02"))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
		defer rows.Close()

		if rows.Next() {
			err = rows.Scan(&text, &words)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %s\n", err)
			}
		}

		err = indexTmpl.Execute(w, map[string]interface{}{
			"Title": fmt.Sprintf("%d words", settings.DailyTarget),

			"Now":  now,
			"Days": annotatedDays,

			"Text":  text,
			"Words": words,
		})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
	})

	http.HandleFunc("/save", func(w http.ResponseWriter, req *http.Request) {
		var entry map[string]string
		dec := json.NewDecoder(req.Body)
		err := dec.Decode(&entry)
		if err != nil {
			respondWithError(w, http.StatusBadRequest, err)
			return
		}

		text, ok := entry["text"]
		if !ok {
			respondWithError(w, http.StatusBadRequest, fmt.Errorf("Missing field 'text'"))
			return
		}

		now := time.Now()
		err = saveEntry(db, now, text)
		if err != nil {
			respondWithError(w, http.StatusInternalServerError, fmt.Errorf("%s", http.StatusText(http.StatusInternalServerError)))
			return
		}

		enc := json.NewEncoder(w)
		err = enc.Encode(map[string]string{"message": "saved post", "time": now.Format(time.RFC3339)})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
	})

	http.ListenAndServe("localhost:12345", nil)
}

func respondWithError(w http.ResponseWriter, status int, err error) {
	res := map[string]string{"error": err.Error()}
	out, err := json.Marshal(res)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "{\"error\": %q}", http.StatusText(http.StatusInternalServerError))
		return
	}
	w.WriteHeader(status)
	w.Write(out)
}

func saveEntry(db *sql.DB, date time.Time, text string) error {
	_, err := db.Exec("INSERT OR REPLACE INTO entries VALUES (?, ?, ?)", date.Format("2006-01-02"), text, countWords(text))
	return err
}

func importEntry(db *sql.DB) {
	if flag.NArg() < 2 {
		fmt.Fprintf(os.Stderr, "Usage: %s import <date>\n", os.Args[0])
		os.Exit(1)
	}

	rawDate := flag.Arg(1)
	date, err := time.Parse("2006-01-02", rawDate)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: invalid date '%s': %s\n", rawDate, err)
		os.Exit(1)
	}

	f := os.Stdin
	if flag.NArg() >= 3 {
		f, err = os.Open(flag.Arg(2))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
			os.Exit(1)
		}
	}
	defer f.Close()

	text, err := ioutil.ReadAll(f)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: reading %s: %s\n", f.Name(), err)
		os.Exit(1)
	}

	err = saveEntry(db, date, string(text))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: saving entry: %s\n", err)
		os.Exit(1)
	}
}

var indexTmpl = template.Must(template.New("index").Parse(`<!doctype html>

		<meta charset="utf-8" />
		<title>{{ .Title }}</title>

{{ .Title }}

			{{ $now := .Now }}
			{{ range $day := .Days -}}

{{ $day.Date.Day }}

			{{ end }}

{{ .Now.Format "Monday, January 2, 2006" }}

				<textarea id="editor">{{ .Text }}</textarea>

					0 words

				Made with <3 by strange adventures.  —  /about

`))

var wordSeperator = regexp.MustCompile(`\s+`)

func countWords(text string) int {
	ws := wordSeperator.Split(text, -1)
	c := 0
	for _, w := range ws {
		if w != "" {
			c += 1
		}
	}
	return c
}

func daysOfMonth(t time.Time) []time.Time {
	s := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
	e := s.AddDate(0, 1, 0)
	ts := make([]time.Time, 0, 31)
	for s.Before(e) {
		ts = append(ts, s)
		s = s.AddDate(0, 0, 1)
	}
	return ts
}

type Day struct {
	Date  time.Time
	Words int
}

func (d Day) Classes(now time.Time) string {
	var classes string
	if d.Date.Before(now) {
		classes = "past"
	} else {
		classes = "future"
	}

	if d.Words >= 1 {
		classes += " written"
	}

	if d.Words >= settings.DailyTarget {
		classes += " yay"
	}

	return classes
}

func annotateDays(db *sql.DB, days []time.Time) ([]Day, error) {
	rows, err := db.Query("SELECT date, words FROM entries WHERE date >= ? AND date <= ?", days[0].Format("2006-01-02"), days[len(days)-1].Format("2006-01-02"))
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var day string
	var words int
	if rows.Next() {
		err = rows.Scan(&day, &words)
		if err != nil {
			return nil, err
		}
	}

	annotatedDays := make([]Day, len(days))
	for i, t := range days {
		d := Day{Date: t, Words: 0}

		if t.Format("2006-01-02") == day {
			d.Words = words

			if rows.Next() {
				err = rows.Scan(&day, &words)
				if err != nil {
					return nil, err
				}
			}
		}

		annotatedDays[i] = d
	}

	return annotatedDays, nil
}
<commit_msg>Highlight days with all the words<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

var settings struct {
	DailyTarget int
	Database    string
}

func init() {
	flag.IntVar(&settings.DailyTarget, "target", 900, "The number of words to write daily")
	flag.StringVar(&settings.Database, "db", "diary.db", "The name of the database file")
}

func main() {
	flag.Parse()

	db, err := sql.Open("sqlite3", settings.Database)
	if err != nil {
		panic(err)
	}

	_, err = db.Exec("CREATE TABLE IF NOT EXISTS entries (date TEXT PRIMARY KEY, text TEXT, words INTEGER)")
	if err != nil {
		panic(err)
	}

	if flag.NArg() >= 1 {
		cmd := flag.Arg(0)
		if cmd == "import" {
			importEntry(db)
			return
		}
	}

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		now := time.Now()
		days := daysOfMonth(now)
		annotatedDays, err := annotateDays(db, days)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}

		text := ""
		words := 0
		rows, err := db.Query("SELECT text, words FROM entries WHERE date = ?", now.Format("2006-01-02"))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
		defer rows.Close()

		if rows.Next() {
			err = rows.Scan(&text, &words)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %s\n", err)
			}
		}

		err = indexTmpl.Execute(w, map[string]interface{}{
			"Title": fmt.Sprintf("%d words", settings.DailyTarget),

			"Now":  now,
			"Days": annotatedDays,

			"Text":  text,
			"Words": words,
		})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
	})

	http.HandleFunc("/save", func(w http.ResponseWriter, req *http.Request) {
		var entry map[string]string
		dec := json.NewDecoder(req.Body)
		err := dec.Decode(&entry)
		if err != nil {
			respondWithError(w, http.StatusBadRequest, err)
			return
		}

		text, ok := entry["text"]
		if !ok {
			respondWithError(w, http.StatusBadRequest, fmt.Errorf("Missing field 'text'"))
			return
		}

		now := time.Now()
		err = saveEntry(db, now, text)
		if err != nil {
			respondWithError(w, http.StatusInternalServerError, fmt.Errorf("%s", http.StatusText(http.StatusInternalServerError)))
			return
		}

		enc := json.NewEncoder(w)
		err = enc.Encode(map[string]string{"message": "saved post", "time": now.Format(time.RFC3339)})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
	})

	http.ListenAndServe("localhost:12345", nil)
}

func respondWithError(w http.ResponseWriter, status int, err error) {
	res := map[string]string{"error": err.Error()}
	out, err := json.Marshal(res)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "{\"error\": %q}", http.StatusText(http.StatusInternalServerError))
		return
	}
	w.WriteHeader(status)
	w.Write(out)
}

func saveEntry(db *sql.DB, date time.Time, text string) error {
	_, err := db.Exec("INSERT OR REPLACE INTO entries VALUES (?, ?, ?)", date.Format("2006-01-02"), text, countWords(text))
	return err
}

func importEntry(db *sql.DB) {
	if flag.NArg() < 2 {
		fmt.Fprintf(os.Stderr, "Usage: %s import <date>\n", os.Args[0])
		os.Exit(1)
	}

	rawDate := flag.Arg(1)
	date, err := time.Parse("2006-01-02", rawDate)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: invalid date '%s': %s\n", rawDate, err)
		os.Exit(1)
	}

	f := os.Stdin
	if flag.NArg() >= 3 {
		f, err = os.Open(flag.Arg(2))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
			os.Exit(1)
		}
	}
	defer f.Close()

	text, err := ioutil.ReadAll(f)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: reading %s: %s\n", f.Name(), err)
		os.Exit(1)
	}

	err = saveEntry(db, date, string(text))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: saving entry: %s\n", err)
		os.Exit(1)
	}
}

var indexTmpl = template.Must(template.New("index").Parse(`<!doctype html>

		<meta charset="utf-8" />
		<title>{{ .Title }}</title>

{{ .Title }}

			{{ $now := .Now }}
			{{ range $day := .Days -}}

{{ $day.Date.Day }}

			{{ end }}

{{ .Now.Format "Monday, January 2, 2006" }}

				<textarea id="editor">{{ .Text }}</textarea>

					0 words

				Made with <3 by strange adventures.  —  /about

`))

var wordSeperator = regexp.MustCompile(`\s+`)

func countWords(text string) int {
	ws := wordSeperator.Split(text, -1)
	c := 0
	for _, w := range ws {
		if w != "" {
			c += 1
		}
	}
	return c
}

func daysOfMonth(t time.Time) []time.Time {
	s := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
	e := s.AddDate(0, 1, 0)
	ts := make([]time.Time, 0, 31)
	for s.Before(e) {
		ts = append(ts, s)
		s = s.AddDate(0, 0, 1)
	}
	return ts
}

type Day struct {
	Date  time.Time
	Words int
}

func (d Day) Classes(now time.Time) string {
	var classes string
	if d.Date.Before(now) {
		classes = "past"
	} else {
		classes = "future"
	}

	if d.Words >= 1 {
		classes += " written"
	}

	if d.Words >= settings.DailyTarget {
		classes += " yay"
	}

	return classes
}

func annotateDays(db *sql.DB, days []time.Time) ([]Day, error) {
	rows, err := db.Query("SELECT date, words FROM entries WHERE date >= ? AND date <= ?", days[0].Format("2006-01-02"), days[len(days)-1].Format("2006-01-02"))
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var day string
	var words int
	if rows.Next() {
		err = rows.Scan(&day, &words)
		if err != nil {
			return nil, err
		}
	}

	annotatedDays := make([]Day, len(days))
	for i, t := range days {
		d := Day{Date: t, Words: 0}

		if t.Format("2006-01-02") == day {
			d.Words = words

			if rows.Next() {
				err = rows.Scan(&day, &words)
				if err != nil {
					return nil, err
				}
			}
		}

		annotatedDays[i] = d
	}

	return annotatedDays, nil
}
<|endoftext|>