<commit_before>package main

import (
	"log"
	"os"
	"time"
	"bufio"
	"io"
	"net/http"
	"strings"
	"sync"
	"os/exec"
	"strconv"
	"github.com/vaxx99/play/stream"
	"github.com/gotk3/gotk3/gtk"
	"github.com/gotk3/gotk3/pango"
	"github.com/gotk3/gotk3/gdk"
)

type Labels struct {
	Count, Station, Bitrate, Genre, Timer, Title *gtk.Label
}

func main() {
	gtk.Init(nil)

	check := func(m string, e error) {
		if e != nil {
			log.Println(m, e)
		}
	}

	win, e := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
	check("", e)
	win.SetSkipTaskbarHint(true)

	//Linux screen resolution
	out, _ := exec.Command("xdpyinfo").Output()
	dpi := string(out)
	dpi = dpi[strings.Index(dpi, "dimensions:")+len("dimensions:") : strings.Index(dpi, "pixels")]
	a := strings.Split(dpi, "x")
	W, e := strconv.Atoi(strings.TrimSpace(a[0]))
	H, e := strconv.Atoi(strings.TrimSpace(a[1]))
	check("Resolution:", e)
	if e != nil {
		W, H = 1024, 768
	}

	win.Connect("destroy", func() {
		gtk.MainQuit()
	})

	win.Connect("key-press-event",func(win *gtk.Window,ev *gdk.Event){
		keyEvent := &gdk.EventKey{ev}
		if keyEvent.KeyVal() == gdk.KEY_Escape{
			gtk.MainQuit()
		}

	})

	provider, _ := gtk.CssProviderNew()
	provider.LoadFromData(`@define-color base #333;@define-color fore #ccc;@define-color diff #555;*{background-color: @base;border:0;}.container{color: @fore;border:1px solid @base;}.plus{color: @fore;border:0;font-size:20px;}.station{color:@fore;border:0;font-size:10px;}.bitrate{color:#ccc;border:0;font-size:10px;}.timer{color:#ccc;border:0;font-size:10px;padding-right:4px;}.title{color:#cff;border:0;font-size:10px;}.genre{color:#fcc;border:0;font-size:10px;}`)
	win.SetTitle("xPlay")
	win.SetIconFromFile("fsto.png")
	win.SetDefaultSize(300, 12)
	win.SetResizable(false)
	win.SetKeepAbove(true)

	cont, _ := gtk.GridNew()
	cont.SetRowHomogeneous(true)
	cont.SetColumnSpacing(4)
	cont.SetSizeRequest(300, 12)
	cont.SetVExpand(false)

	plus, _ := gtk.LabelNew("")
	station, _ := gtk.LabelNew("")
	bitrate, _ := gtk.LabelNew("")
	genre, _ := gtk.LabelNew("")
	title, _ := gtk.LabelNew("")
	timer, _ := gtk.LabelNew("00:00")

	var labs = &Labels{plus, station, bitrate, genre, timer, title}

	ebox, _ := gtk.EventBoxNew()
	ubox, _ := gtk.EventBoxNew()
	cbox, _ := gtk.EventBoxNew()
	bbox, _ := gtk.EventBoxNew()

	Style(provider, &cont.Widget, "container")
	Style(provider, &station.Widget, "station")
	Style(provider, &bitrate.Widget, "bitrate")
	Style(provider, &genre.Widget, "genre")
	Style(provider, &title.Widget, "title")
	Style(provider, &timer.Widget, "timer")
	Style(provider, &plus.Widget, "plus")

	plus.SetSizeRequest(20, 12)
	station.SetSizeRequest(230, 12)
	station.SetXAlign(0)
	bitrate.SetSizeRequest(20, 12)
	bitrate.SetXAlign(-1)
	timer.SetSizeRequest(20, 12)
	timer.SetXAlign(-1)
	title.SetSizeRequest(230, 12)
	title.SetXAlign(0)

	station.SetMaxWidthChars(10)
	station.SetEllipsize(pango.ELLIPSIZE_END)
	station.SetJustify(gtk.JUSTIFY_LEFT)

	title.SetLines(2)
	title.SetMaxWidthChars(10)
	title.SetLineWrap(true)
	//title.SetEllipsize(pango.ELLIPSIZE_END)
	title.SetJustify(gtk.JUSTIFY_CENTER)
	title.SetVisible(false)

	bitrate.SetMaxWidthChars(10)
	bitrate.SetEllipsize(pango.ELLIPSIZE_END)
	bitrate.SetJustify(gtk.JUSTIFY_RIGHT)
	timer.SetJustify(gtk.JUSTIFY_RIGHT)

	ebox.Add(timer)
	ubox.Add(station)
	cbox.Add(plus)
	bbox.Add(bitrate)

	cont.Attach(cbox, 0, 0, 1, 1)
	cont.Attach(ubox, 1, 0, 1, 1)
	cont.Attach(title, 1, 0, 1, 1)
	cont.Attach(bbox, 2, 0, 1, 1)
	cont.Attach(ebox, 3, 0, 1, 1)

	var ch = make(chan struct{})
	var run = 0
	var play = stream.NewPlayer()
	var tmp = stream.Streams{}

	proxy := os.Getenv("http_proxy")

	if proxy == "" {
		tmp = append(tmp, stream.Stream{Crnt: 0, Next: 0, SName: "Radio Swiss Jazz", SUrl: "http://stream.srg-ssr.ch/m/rsj/aacp_96"})
	} else {
		os.Setenv("http_proxy", proxy)
		tmp = stream.Plist()
	}
	cplay := tmp[0]

	labs.Count.SetMarkup("•")
	labs.Station.SetText(cplay.SName)

	ubox.Connect("event", func() {
		if labs.Station.GetVisible() == false {
			labs.Station.SetVisible(true)
			labs.Title.SetVisible(false)
		} else {
			labs.Station.SetVisible(false)
			labs.Title.SetVisible(true)
		}
	})

	ebox.Connect("button-press-event", func() {
		hb := &http.Response{}
		ha := 0
		titl := &Titles{Lab: labs}
		timr := &Timer{time.Now(), labs}
		var wg sync.WaitGroup
		if run == 0 {
			run = 1
			uri, prx := cplay.SUrl, cplay.SProxy
			hb, ha = stream.TryOne(uri, prx)
			if ha == 0 {
				hb, ha = stream.TryTwo(uri, prx)
			}
			labs.Station.SetText(cplay.SName)
			if hb.StatusCode == 200 && ha > 0 {
				data := &Data{hb.Body, ha}
				titl.Now = &timr.Now
				cplay.SBitr = hb.Header.Get("icy-br")
				titl.Tch = data.Update(&wg, ch)
				labs.Station.SetVisible(false)
				labs.Title.SetVisible(true)
				wg.Add(1)
				go titl.Update(&wg, ch)
				labs.Count.SetMarkup("•")
				labs.Bitrate.SetMarkup("" + cplay.SBitr + "k")
				wg.Add(1)
				go timr.Update(&wg, ch)
				play.Player(cplay.SUrl)
			} else {
				run = 0
				labs.Title.SetVisible(false)
			}
		} else {
			run = 0
			labs.Clear()
			labs.Count.SetMarkup("•")
			play.Player("")
			ch <- struct{}{}
			ch <- struct{}{}
			labs.Title.SetVisible(false)
			labs.Station.SetVisible(true)
			wg.Wait()
		}
	})

	cbox.Connect("button-press-event", func() {
		cplay = tmp[cplay.Next]
		labs.Clear()
		labs.Station.SetText(cplay.SName)
		labs.Count.SetMarkup("•")
	})

	ubox.Connect("button-press-event", func() {
		if proxy != "" {
			tmp = stream.Plist()
			labs.Clear()
			labs.Station.SetText(cplay.SName)
			labs.Count.SetMarkup("•")
			cplay = tmp[0]
		}
	})

	//bbox.Connect("event", func() {
	//	bitrate.SetMarkup("move")
	//})

	bbox.Connect("button-press-event", func() {
		x, y := win.GetPosition()
		w, h := win.GetSize()

		if win.GetDecorated() == true {
			win.SetDecorated(false)
			if x < W/2 {
				x = 0
			}
			if y < H/2 {
				y = 0
			}
			if x > W/2 {
				x = W - w
			}
			if y > H/2 {
				y = H
			}
			win.Move(x, y)
		} else {
			win.Move(W/2-w/2, H/2-h/2)
			win.SetDecorated(true)
		}
	})
	win.Add(cont)
	win.ShowAll()
	gtk.Main()
}

func Style(p *gtk.CssProvider, w *gtk.Widget, cn string) error {
	ctx, err := w.GetStyleContext()
	if err != nil {
		return err
	}
	ctx.AddProvider(p, 600)
	ctx.AddClass(cn)
	return nil
}

type Timer struct {
	Now time.Time
	Lab *Labels
}

func (t *Timer) Update(wg *sync.WaitGroup, ch chan struct{}) {
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
			dur := time.Since(t.Now)
			tm, _ := time.Parse("0405", "0000")
			tt := tm.Add(dur)
			t.Lab.Timer.SetMarkup("" + tt.Format("04:05") + "")
		case <-ch:
			t.Lab.Timer.SetText("00:00")
			wg.Done()
			return
		}
	}
}

type Titles struct {
	Tch <-chan string
	Lab *Labels
	Now *time.Time
}

type Data struct {
	rdr  io.Reader
	skip int
}

func (t *Titles) Update(wg *sync.WaitGroup, ch chan struct{}) {
	select {
	default:
		for meta := range t.Tch {
			*t.Now = time.Now()
			xtx:=toUtf8([]byte(meta))
			if len(xtx)>0{
				xtx=strings.TrimLeft(xtx,"'")
				xtx=strings.TrimRight(xtx,"'")
				if strings.Contains(xtx,"&"){
					xtx = strings.Replace(xtx, "&", "&", -1)
				}
			}
			t.Lab.Title.SetMarkup(""+xtx+"")
		}
	case <-ch:
		wg.Done()
		return
	}
}

func toUtf8(iso8859_1_buf []byte) string {
	buf := make([]rune, len(iso8859_1_buf))
	for i, b := range iso8859_1_buf {
		buf[i] = rune(b)
	}
	return string(buf)
}

func (L *Labels) Clear() {
	L.Bitrate.SetText("")
	L.Title.SetText("")
}

func (d *Data) Update(wg *sync.WaitGroup, ch chan struct{}) <-chan string {
	dh := make(chan string)
	wg.Add(1)
	go func() {
		bufrdr := bufio.NewReaderSize(d.rdr, d.skip)
		for {
			skipbytes := make([]byte, d.skip)
			_, err := io.ReadFull(bufrdr, skipbytes)
			if err != nil {
				log.Printf("Failed: %v\n", err)
				close(dh)
				return
			}
			c, err := bufrdr.ReadByte()
			if err != nil {
				log.Panic(err)
			}
			if c > 0 {
				meta, err := stream.ParseIcy(bufrdr, c)
				if err != nil {
					log.Panic(err)
				}
				dh <- meta
			}
			select {
			default:
			case <-ch:
				wg.Done()
				close(dh)
				return
			}
		}
	}()
	return dh
}

<commit_msg>Green & Yellow<commit_after>package main

import (
	"log"
	"os"
	"time"
	"bufio"
	"io"
	"net/http"
	"strings"
	"sync"
	"os/exec"
	"strconv"
	"github.com/vaxx99/play/stream"
	"github.com/gotk3/gotk3/gtk"
	"github.com/gotk3/gotk3/pango"
	"github.com/gotk3/gotk3/gdk"
)

type Labels struct {
	Count, Station, Bitrate, Genre, Timer, Title *gtk.Label
}

func main() {
	gtk.Init(nil)

	check := func(m string, e error) {
		if e != nil {
			log.Println(m, e)
		}
	}

	win, e := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
	check("", e)
	win.SetSkipTaskbarHint(true)

	//Linux screen resolution
	out, _ := exec.Command("xdpyinfo").Output()
	dpi := string(out)
	dpi = dpi[strings.Index(dpi, "dimensions:")+len("dimensions:") : strings.Index(dpi, "pixels")]
	a := strings.Split(dpi, "x")
	W, e := strconv.Atoi(strings.TrimSpace(a[0]))
	H, e := strconv.Atoi(strings.TrimSpace(a[1]))
	check("Resolution:", e)
	if e != nil {
		W, H = 1024, 768
	}

	//win.SetSizeRequest(300, 12)
	win.Connect("destroy", func() {
		gtk.MainQuit()
	})

	win.Connect("key-press-event",func(win *gtk.Window,ev *gdk.Event){
		keyEvent := &gdk.EventKey{ev}
		if keyEvent.KeyVal() == gdk.KEY_Escape{
			gtk.MainQuit()
		}

	})

	provider, _ := gtk.CssProviderNew()
	provider.LoadFromData(`@define-color base #333;@define-color fore #ccc;@define-color diff #555;*{background-color: @base;border:0;}.container{color: @fore;border:1px solid @base;}.plus{color: @fore;border:0;font-size:20px;}.station{color:@fore;border:0;font-size:10px;}.bitrate{color:#ccc;border:0;font-size:10px;}.timer{color:#ccc;border:0;font-size:10px;padding-right:4px;}.title{color:#cff;border:0;font-size:10px;}.genre{color:#fcc;border:0;font-size:10px;}`)
	win.SetTitle("xPlay")
	win.SetIconFromFile("fsto.png")
	win.SetDefaultSize(300, 12)
	win.SetResizable(false)
	win.SetKeepAbove(true)

	cont, _ := gtk.GridNew()
	cont.SetRowHomogeneous(true)
	cont.SetColumnSpacing(4)
	cont.SetSizeRequest(300, 12)
	cont.SetVExpand(false)

	plus, _ := gtk.LabelNew("")
	station, _ := gtk.LabelNew("")
	bitrate, _ := gtk.LabelNew("")
	genre, _ := gtk.LabelNew("")
	title, _ := gtk.LabelNew("")
	timer, _ := gtk.LabelNew("00:00")

	var labs = &Labels{plus, station, bitrate, genre, timer, title}

	ebox, _ := gtk.EventBoxNew()
	ubox, _ := gtk.EventBoxNew()
	cbox, _ := gtk.EventBoxNew()
	bbox, _ := gtk.EventBoxNew()

	Style(provider, &cont.Widget, "container")
	Style(provider, &station.Widget, "station")
	Style(provider, &bitrate.Widget, "bitrate")
	Style(provider, &genre.Widget, "genre")
	Style(provider, &title.Widget, "title")
	Style(provider, &timer.Widget, "timer")
	Style(provider, &plus.Widget, "plus")

	plus.SetSizeRequest(20, 12)
	station.SetSizeRequest(230, 12)
	station.SetXAlign(0)
	bitrate.SetSizeRequest(20, 12)
	bitrate.SetXAlign(-1)
	timer.SetSizeRequest(20, 12)
	timer.SetXAlign(-1)
	title.SetSizeRequest(230, 12)
	title.SetXAlign(0)

	station.SetMaxWidthChars(10)
	station.SetEllipsize(pango.ELLIPSIZE_END)
	station.SetJustify(gtk.JUSTIFY_LEFT)

	title.SetLines(2)
	title.SetMaxWidthChars(10)
	title.SetLineWrap(true)
	//title.SetEllipsize(pango.ELLIPSIZE_END)
	title.SetJustify(gtk.JUSTIFY_CENTER)
	title.SetVisible(false)

	bitrate.SetMaxWidthChars(10)
	bitrate.SetEllipsize(pango.ELLIPSIZE_END)
	bitrate.SetJustify(gtk.JUSTIFY_RIGHT)
	timer.SetJustify(gtk.JUSTIFY_RIGHT)

	ebox.Add(timer)
	ubox.Add(station)
	cbox.Add(plus)
	bbox.Add(bitrate)

	cont.Attach(cbox, 0, 0, 1, 1)
	cont.Attach(ubox, 1, 0, 1, 1)
	cont.Attach(title, 1, 0, 1, 1)
	cont.Attach(bbox, 2, 0, 1, 1)
	cont.Attach(ebox, 3, 0, 1, 1)

	var ch = make(chan struct{})
	var run = 0
	var play = stream.NewPlayer()
	var tmp = stream.Streams{}

	proxy := os.Getenv("http_proxy")

	if proxy == "" {
		tmp = append(tmp, stream.Stream{Crnt: 0, Next: 0, SName: "Radio Swiss Jazz", SUrl: "http://stream.srg-ssr.ch/m/rsj/aacp_96"})
	} else {
		os.Setenv("http_proxy", proxy)
		tmp = stream.Plist()
	}
	cplay := tmp[0]

	labs.Count.SetMarkup("•")
	labs.Station.SetText(cplay.SName)

	ubox.Connect("event", func() {
		if labs.Station.GetVisible() == false {
			labs.Station.SetVisible(true)
			labs.Title.SetVisible(false)
		} else {
			labs.Station.SetVisible(false)
			labs.Title.SetVisible(true)
		}
	})

	ebox.Connect("button-press-event", func() {
		hb := &http.Response{}
		ha := 0
		titl := &Titles{Lab: labs}
		timr := &Timer{time.Now(), labs}
		var wg sync.WaitGroup
		if run == 0 {
			run = 1
			uri, prx := cplay.SUrl, cplay.SProxy
			hb, ha = stream.TryOne(uri, prx)
			if ha == 0 {
				hb, ha = stream.TryTwo(uri, prx)
			}
			labs.Station.SetText(cplay.SName)
			if hb.StatusCode == 200 && ha > 0 {
				data := &Data{hb.Body, ha}
				titl.Now = &timr.Now
				cplay.SBitr = hb.Header.Get("icy-br")
				titl.Tch = data.Update(&wg, ch)
				labs.Station.SetVisible(false)
				labs.Title.SetVisible(true)
				wg.Add(1)
				go titl.Update(&wg, ch)
				labs.Count.SetMarkup("•")
				labs.Bitrate.SetMarkup("" + cplay.SBitr + "k")
				wg.Add(1)
				go timr.Update(&wg, ch)
				play.Player(cplay.SUrl)
			} else {
				run = 0
				labs.Title.SetVisible(false)
			}
		} else {
			run = 0
			labs.Clear()
			labs.Count.SetMarkup("•")
			play.Player("")
			ch <- struct{}{}
			ch <- struct{}{}
			labs.Title.SetVisible(false)
			labs.Station.SetVisible(true)
			wg.Wait()
		}
	})

	cbox.Connect("button-press-event", func() {
		cplay = tmp[cplay.Next]
		labs.Clear()
		labs.Station.SetText(cplay.SName)
		labs.Count.SetMarkup("•")
	})

	ubox.Connect("button-press-event", func() {
		if proxy != "" {
			tmp = stream.Plist()
			labs.Clear()
			labs.Station.SetText(cplay.SName)
			labs.Count.SetMarkup("•")
			cplay = tmp[0]
		}
	})

	//bbox.Connect("event", func() {
	//	bitrate.SetMarkup("move")
	//})

	bbox.Connect("button-press-event", func() {
		x, y := win.GetPosition()
		w, h := win.GetSize()

		if win.GetDecorated() == true {
			win.SetDecorated(false)
			if x < W/2 {
				x = 0
			}
			if y < H/2 {
				y = 0
			}
			if x > W/2 {
				x = W - w
			}
			if y > H/2 {
				y = H
			}
			win.Move(x, y)
		} else {
			win.Move(W/2-w/2, H/2-h/2)
			win.SetDecorated(true)
		}
	})
	win.Add(cont)
	win.ShowAll()
	gtk.Main()
}

func Style(p *gtk.CssProvider, w *gtk.Widget, cn string) error {
	ctx, err := w.GetStyleContext()
	if err != nil {
		return err
	}
	ctx.AddProvider(p, 600)
	ctx.AddClass(cn)
	return nil
}

type Timer struct {
	Now time.Time
	Lab *Labels
}

func (t *Timer) Update(wg *sync.WaitGroup, ch chan struct{}) {
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
			dur := time.Since(t.Now)
			tm, _ := time.Parse("0405", "0000")
			tt := tm.Add(dur)
			t.Lab.Timer.SetMarkup("" + tt.Format("04:05") + "")
			ss:=dur.Seconds()
			if int(ss)%2==0{
				t.Lab.Count.SetMarkup("•")
			}else{
				t.Lab.Count.SetMarkup("•")
			}
		case <-ch:
			t.Lab.Count.SetMarkup("•")
			t.Lab.Timer.SetText("00:00")
			wg.Done()
			return
		}
	}
}

type Titles struct {
	Tch <-chan string
	Lab *Labels
	Now *time.Time
}

type Data struct {
	rdr  io.Reader
	skip int
}

func (t *Titles) Update(wg *sync.WaitGroup, ch chan struct{}) {
	select {
	default:
		for meta := range t.Tch {
			*t.Now = time.Now()
			xtx:=toUtf8([]byte(meta))
			if len(xtx)>0{
				xtx=strings.TrimLeft(xtx,"'")
				xtx=strings.TrimRight(xtx,"'")
				if strings.Contains(xtx,"&"){
					xtx = strings.Replace(xtx, "&", "&", -1)
				}
			}
			t.Lab.Title.SetMarkup(""+xtx+"")
		}
	case <-ch:
		wg.Done()
		return
	}
}

func toUtf8(iso8859_1_buf []byte) string {
	buf := make([]rune, len(iso8859_1_buf))
	for i, b := range iso8859_1_buf {
		buf[i] = rune(b)
	}
	return string(buf)
}

func (L *Labels) Clear() {
	L.Bitrate.SetText("")
	L.Title.SetText("")
}

func (d *Data) Update(wg *sync.WaitGroup, ch chan struct{}) <-chan string {
	dh := make(chan string)
	wg.Add(1)
	go func() {
		bufrdr := bufio.NewReaderSize(d.rdr, d.skip)
		for {
			skipbytes := make([]byte, d.skip)
			_, err := io.ReadFull(bufrdr, skipbytes)
			if err != nil {
				log.Printf("Failed: %v\n", err)
				close(dh)
				return
			}
			c, err := bufrdr.ReadByte()
			if err != nil {
				log.Panic(err)
			}
			if c > 0 {
				meta, err := stream.ParseIcy(bufrdr, c)
				if err != nil {
					log.Panic(err)
				}
				dh <- meta
			}
			select {
			default:
			case <-ch:
				wg.Done()
				close(dh)
				return
			}
		}
	}()
	return dh
}

<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"time"
	"bufio"
	"io"
	"net/http"
	"strings"
	"sync"
	"os/exec"
	"strconv"
	"github.com/vaxx99/play/stream"
	"github.com/gotk3/gotk3/gtk"
	"github.com/gotk3/gotk3/pango"
	"github.com/gotk3/gotk3/gdk"
)

type Labels struct {
	Count, Station, Bitrate, Genre, Timer, Title *gtk.Label
}

func main() {
	gtk.Init(nil)

	check := func(m string, e error) {
		if e != nil {
			log.Println(m, e)
		}
	}

	win, e := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
	check("", e)
	win.SetSkipTaskbarHint(true)

	//Linux screen resolution
	out, _ := exec.Command("xdpyinfo").Output()
	dpi := string(out)
	dpi = dpi[strings.Index(dpi, "dimensions:")+len("dimensions:") : strings.Index(dpi, "pixels")]
	a := strings.Split(dpi, "x")
	W, e := strconv.Atoi(strings.TrimSpace(a[0]))
	H, e := strconv.Atoi(strings.TrimSpace(a[1]))
	check("Resolution:", e)
	if e != nil {
		W, H = 1024, 768
	}

	//win.SetSizeRequest(300, 12)
	win.Connect("destroy", func() {
		gtk.MainQuit()
	})

	win.Connect("key-press-event",func(win *gtk.Window,ev *gdk.Event){
		keyEvent := &gdk.EventKey{ev}
		if keyEvent.KeyVal() == gdk.KEY_Escape{
			gtk.MainQuit()
		}

	})

	provider, _ := gtk.CssProviderNew()
	provider.LoadFromData(`@define-color base #333;@define-color fore #ccc;@define-color diff #555;*{background-color: @base;border:0;}.container{color: @fore;border:1px solid @base;}.plus{color: @fore;border:0;font-size:20px;}.station{color:@fore;border:0;font-size:10px;}.bitrate{color:#ccc;border:0;font-size:10px;}.timer{color:#ccc;border:0;font-size:10px;padding-right:4px;}.title{color:#cff;border:0;font-size:10px;}.genre{color:#fcc;border:0;font-size:10px;}`)
	win.SetTitle("xPlay")
	win.SetIconFromFile("fsto.png")
	win.SetDefaultSize(300, 12)
	win.SetResizable(false)
	win.SetKeepAbove(true)

	cont, _ := gtk.GridNew()
	cont.SetRowHomogeneous(true)
	cont.SetColumnSpacing(4)
	cont.SetSizeRequest(300, 12)
	cont.SetVExpand(false)

	plus, _ := gtk.LabelNew("")
	station, _ := gtk.LabelNew("")
	bitrate, _ := gtk.LabelNew("")
	genre, _ := gtk.LabelNew("")
	title, _ := gtk.LabelNew("")
	timer, _ := gtk.LabelNew("00:00")

	var labs = &Labels{plus, station, bitrate, genre, timer, title}

	ebox, _ := gtk.EventBoxNew()
	ubox, _ := gtk.EventBoxNew()
	cbox, _ := gtk.EventBoxNew()
	bbox, _ := gtk.EventBoxNew()

	Style(provider, &cont.Widget, "container")
	Style(provider, &station.Widget, "station")
	Style(provider, &bitrate.Widget, "bitrate")
	Style(provider, &genre.Widget, "genre")
	Style(provider, &title.Widget, "title")
	Style(provider, &timer.Widget, "timer")
	Style(provider, &plus.Widget, "plus")

	plus.SetSizeRequest(20, 12)
	station.SetSizeRequest(230, 12)
	station.SetXAlign(0)
	bitrate.SetSizeRequest(20, 12)
	bitrate.SetXAlign(-1)
	timer.SetSizeRequest(20, 12)
	timer.SetXAlign(-1)
	title.SetSizeRequest(230, 12)
	title.SetXAlign(0)

	station.SetMaxWidthChars(10)
	station.SetEllipsize(pango.ELLIPSIZE_END)
	station.SetJustify(gtk.JUSTIFY_LEFT)

	title.SetLines(2)
	title.SetMaxWidthChars(10)
	title.SetLineWrap(true)
	//title.SetEllipsize(pango.ELLIPSIZE_END)
	title.SetJustify(gtk.JUSTIFY_CENTER)
	title.SetVisible(false)

	bitrate.SetMaxWidthChars(10)
	bitrate.SetEllipsize(pango.ELLIPSIZE_END)
	bitrate.SetJustify(gtk.JUSTIFY_RIGHT)
	timer.SetJustify(gtk.JUSTIFY_RIGHT)

	ebox.Add(timer)
	ubox.Add(station)
	cbox.Add(plus)
	bbox.Add(bitrate)

	cont.Attach(cbox, 0, 0, 1, 1)
	cont.Attach(ubox, 1, 0, 1, 1)
	cont.Attach(title, 1, 0, 1, 1)
	cont.Attach(bbox, 2, 0, 1, 1)
	cont.Attach(ebox, 3, 0, 1, 1)

	var ch = make(chan struct{})
	var run = 0
	var play = stream.NewPlayer()
	var tmp = stream.Streams{}

	proxy := os.Getenv("http_proxy")

	if proxy == "" {
		tmp = append(tmp, stream.Stream{Crnt: 0, Next: 0, SName: "Radio Swiss Jazz", SUrl: "http://stream.srg-ssr.ch/m/rsj/aacp_96"})
	} else {
		os.Setenv("http_proxy", proxy)
		tmp = stream.Plist()
	}
	cplay := tmp[0]

	labs.Count.SetMarkup("•")
	labs.Station.SetText(cplay.SName)

	ubox.Connect("event", func() {
		if labs.Station.GetVisible() == false {
			labs.Station.SetVisible(true)
			labs.Title.SetVisible(false)
		} else {
			labs.Station.SetVisible(false)
			labs.Title.SetVisible(true)
		}
	})

	ebox.Connect("button-press-event", func() {
		hb := &http.Response{}
		ha := 0
		titl := &Titles{Lab: labs}
		timr := &Timer{time.Now(), labs}
		var wg sync.WaitGroup
		if run == 0 {
			run = 1
			uri, prx := cplay.SUrl, cplay.SProxy
			hb, ha = stream.TryOne(uri, prx)
			if ha == 0 {
				hb, ha = stream.TryTwo(uri, prx)
			}
			labs.Station.SetText(cplay.SName)
			if hb.StatusCode == 200 && ha > 0 {
				data := &Data{hb.Body, ha}
				titl.Now = &timr.Now
				cplay.SBitr = hb.Header.Get("icy-br")
				titl.Tch = data.Update(&wg, ch)
				labs.Station.SetVisible(false)
				labs.Title.SetVisible(true)
				wg.Add(1)
				go titl.Update(&wg, ch)
				labs.Count.SetMarkup("•")
				labs.Bitrate.SetMarkup("" + cplay.SBitr + "k")
				wg.Add(1)
				go timr.Update(&wg, ch)
				play.Player(cplay.SUrl)
			} else {
				run = 0
				labs.Title.SetVisible(false)
			}
		} else {
			run = 0
			labs.Clear()
			labs.Count.SetMarkup("•")
			play.Player("")
			ch <- struct{}{}
			ch <- struct{}{}
			labs.Title.SetVisible(false)
			labs.Station.SetVisible(true)
			wg.Wait()
		}
	})

	cbox.Connect("button-press-event", func() {
		cplay = tmp[cplay.Next]
		labs.Clear()
		labs.Station.SetText(cplay.SName)
		labs.Count.SetMarkup("•")
	})

	ubox.Connect("button-press-event", func() {
		if proxy != "" {
			tmp = stream.Plist()
			labs.Clear()
			labs.Station.SetText(cplay.SName)
			labs.Count.SetMarkup("•")
			cplay = tmp[0]
		}
	})

	//bbox.Connect("event", func() {
	//	bitrate.SetMarkup("move")
	//})

	bbox.Connect("button-press-event", func() {
		x, y := win.GetPosition()
		w, h := win.GetSize()

		if win.GetDecorated() == true {
			win.SetDecorated(false)
			if x < W/2 {
				x = 0
			}
			if y < H/2 {
				y = 0
			}
			if x > W/2 {
				x = W - w
			}
			if y > H/2 {
				y = H
			}
			win.Move(x, y)
		} else {
			win.Move(W/2-w/2, H/2-h/2)
			win.SetDecorated(true)
		}
	})
	win.Add(cont)
	win.ShowAll()
	gtk.Main()
}

func Style(p *gtk.CssProvider, w *gtk.Widget, cn string) error {
	ctx, err := w.GetStyleContext()
	if err != nil {
		return err
	}
	ctx.AddProvider(p, 600)
	ctx.AddClass(cn)
	return nil
}

type Timer struct {
	Now time.Time
	Lab *Labels
}

func (t *Timer) Update(wg *sync.WaitGroup, ch chan struct{}) {
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
			dur := time.Since(t.Now)
			tm, _ := time.Parse("0405", "0000")
			tt := tm.Add(dur)
			t.Lab.Timer.SetMarkup("" + tt.Format("04:05") + "")
		case <-ch:
			t.Lab.Timer.SetText("00:00")
			wg.Done()
			return
		}
	}
}

type Titles struct {
	Tch <-chan string
	Lab *Labels
	Now *time.Time
}

type Data struct {
	rdr  io.Reader
	skip int
}

func (t *Titles) Update(wg *sync.WaitGroup, ch chan struct{}) {
	select {
	default:
		for meta := range t.Tch {
			*t.Now = time.Now()
			xtx:=toUtf8([]byte(meta))
			if len(xtx)>0{
				xtx=strings.TrimLeft(xtx,"'")
				xtx=strings.TrimRight(xtx,"'")
				if strings.Contains(xtx,"&"){
					xtx = strings.Replace(xtx, "&", "&", -1)
				}
			}
			t.Lab.Title.SetMarkup(""+xtx+"")
		}
	case <-ch:
		wg.Done()
		return
	}
}

func toUtf8(iso8859_1_buf []byte) string {
	buf := make([]rune, len(iso8859_1_buf))
	for i, b := range iso8859_1_buf {
		buf[i] = rune(b)
	}
	return string(buf)
}

func (L *Labels) Clear() {
	L.Bitrate.SetText("")
	L.Title.SetText("")
}

func (d *Data) Update(wg *sync.WaitGroup, ch chan struct{}) <-chan string {
	dh := make(chan string)
	wg.Add(1)
	go func() {
		bufrdr := bufio.NewReaderSize(d.rdr, d.skip)
		for {
			skipbytes := make([]byte, d.skip)
			_, err := io.ReadFull(bufrdr, skipbytes)
			if err != nil {
				log.Printf("Failed: %v\n", err)
				close(dh)
				return
			}
			c, err := bufrdr.ReadByte()
			if err != nil {
				log.Panic(err)
			}
			if c > 0 {
				meta, err := stream.ParseIcy(bufrdr, c)
				if err != nil {
					log.Panic(err)
				}
				dh <- meta
			}
			select {
			default:
			case <-ch:
				wg.Done()
				close(dh)
				return
			}
		}
	}()
	return dh
}

<commit_msg>UTF-8, &, Esc<commit_after>package main

import (
	"log"
	"os"
	"time"
	"bufio"
	"io"
	"net/http"
	"strings"
	"sync"
	"os/exec"
	"strconv"
	"github.com/vaxx99/play/stream"
	"github.com/gotk3/gotk3/gtk"
	"github.com/gotk3/gotk3/pango"
	"github.com/gotk3/gotk3/gdk"
)

type Labels struct {
	Count, Station, Bitrate, Genre, Timer, Title *gtk.Label
}

func main() {
	gtk.Init(nil)

	check := func(m string, e error) {
		if e != nil {
			log.Println(m, e)
		}
	}

	win, e := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
	check("", e)
	win.SetSkipTaskbarHint(true)

	//Linux screen resolution
	out, _ := exec.Command("xdpyinfo").Output()
	dpi := string(out)
	dpi = dpi[strings.Index(dpi, "dimensions:")+len("dimensions:") : strings.Index(dpi, "pixels")]
	a := strings.Split(dpi, "x")
	W, e := strconv.Atoi(strings.TrimSpace(a[0]))
	H, e := strconv.Atoi(strings.TrimSpace(a[1]))
	check("Resolution:", e)
	if e != nil {
		W, H = 1024, 768
	}

	win.Connect("destroy", func() {
		gtk.MainQuit()
	})

	win.Connect("key-press-event",func(win *gtk.Window,ev *gdk.Event){
		keyEvent := &gdk.EventKey{ev}
		if keyEvent.KeyVal() == gdk.KEY_Escape{
			gtk.MainQuit()
		}

	})

	provider, _ := gtk.CssProviderNew()
	provider.LoadFromData(`@define-color base #333;@define-color fore #ccc;@define-color diff #555;*{background-color: @base;border:0;}.container{color: @fore;border:1px solid @base;}.plus{color: @fore;border:0;font-size:20px;}.station{color:@fore;border:0;font-size:10px;}.bitrate{color:#ccc;border:0;font-size:10px;}.timer{color:#ccc;border:0;font-size:10px;padding-right:4px;}.title{color:#cff;border:0;font-size:10px;}.genre{color:#fcc;border:0;font-size:10px;}`)
	win.SetTitle("xPlay")
	win.SetIconFromFile("fsto.png")
	win.SetDefaultSize(300, 12)
	win.SetResizable(false)
	win.SetKeepAbove(true)

	cont, _ := gtk.GridNew()
	cont.SetRowHomogeneous(true)
	cont.SetColumnSpacing(4)
	cont.SetSizeRequest(300, 12)
	cont.SetVExpand(false)

	plus, _ := gtk.LabelNew("")
	station, _ := gtk.LabelNew("")
	bitrate, _ := gtk.LabelNew("")
	genre, _ := gtk.LabelNew("")
	title, _ := gtk.LabelNew("")
	timer, _ := gtk.LabelNew("00:00")

	var labs = &Labels{plus, station, bitrate, genre, timer, title}

	ebox, _ := gtk.EventBoxNew()
	ubox, _ := gtk.EventBoxNew()
	cbox, _ := gtk.EventBoxNew()
	bbox, _ := gtk.EventBoxNew()

	Style(provider, &cont.Widget, "container")
	Style(provider, &station.Widget, "station")
	Style(provider, &bitrate.Widget, "bitrate")
	Style(provider, &genre.Widget, "genre")
	Style(provider, &title.Widget, "title")
	Style(provider, &timer.Widget, "timer")
	Style(provider, &plus.Widget, "plus")

	plus.SetSizeRequest(20, 12)
	station.SetSizeRequest(230, 12)
	station.SetXAlign(0)
	bitrate.SetSizeRequest(20, 12)
	bitrate.SetXAlign(-1)
	timer.SetSizeRequest(20, 12)
	timer.SetXAlign(-1)
	title.SetSizeRequest(230, 12)
	title.SetXAlign(0)

	station.SetMaxWidthChars(10)
	station.SetEllipsize(pango.ELLIPSIZE_END)
	station.SetJustify(gtk.JUSTIFY_LEFT)

	title.SetLines(2)
	title.SetMaxWidthChars(10)
	title.SetLineWrap(true)
	//title.SetEllipsize(pango.ELLIPSIZE_END)
	title.SetJustify(gtk.JUSTIFY_CENTER)
	title.SetVisible(false)

	bitrate.SetMaxWidthChars(10)
	bitrate.SetEllipsize(pango.ELLIPSIZE_END)
	bitrate.SetJustify(gtk.JUSTIFY_RIGHT)
	timer.SetJustify(gtk.JUSTIFY_RIGHT)

	ebox.Add(timer)
	ubox.Add(station)
	cbox.Add(plus)
	bbox.Add(bitrate)

	cont.Attach(cbox, 0, 0, 1, 1)
	cont.Attach(ubox, 1, 0, 1, 1)
	cont.Attach(title, 1, 0, 1, 1)
	cont.Attach(bbox, 2, 0, 1, 1)
	cont.Attach(ebox, 3, 0, 1, 1)

	var ch = make(chan struct{})
	var run = 0
	var play = stream.NewPlayer()
	var tmp = stream.Streams{}

	proxy := os.Getenv("http_proxy")

	if proxy == "" {
		tmp = append(tmp, stream.Stream{Crnt: 0, Next: 0, SName: "Radio Swiss Jazz", SUrl: "http://stream.srg-ssr.ch/m/rsj/aacp_96"})
	} else {
		os.Setenv("http_proxy", proxy)
		tmp = stream.Plist()
	}
	cplay := tmp[0]

	labs.Count.SetMarkup("•")
	labs.Station.SetText(cplay.SName)

	ubox.Connect("event", func() {
		if labs.Station.GetVisible() == false {
			labs.Station.SetVisible(true)
			labs.Title.SetVisible(false)
		} else {
			labs.Station.SetVisible(false)
			labs.Title.SetVisible(true)
		}
	})

	ebox.Connect("button-press-event", func() {
		hb := &http.Response{}
		ha := 0
		titl := &Titles{Lab: labs}
		timr := &Timer{time.Now(), labs}
		var wg sync.WaitGroup
		if run == 0 {
			run = 1
			uri, prx := cplay.SUrl, cplay.SProxy
			hb, ha = stream.TryOne(uri, prx)
			if ha == 0 {
				hb, ha = stream.TryTwo(uri, prx)
			}
			labs.Station.SetText(cplay.SName)
			if hb.StatusCode == 200 && ha > 0 {
				data := &Data{hb.Body, ha}
				titl.Now = &timr.Now
				cplay.SBitr = hb.Header.Get("icy-br")
				titl.Tch = data.Update(&wg, ch)
				labs.Station.SetVisible(false)
				labs.Title.SetVisible(true)
				wg.Add(1)
				go titl.Update(&wg, ch)
				labs.Count.SetMarkup("•")
				labs.Bitrate.SetMarkup("" + cplay.SBitr + "k")
				wg.Add(1)
				go timr.Update(&wg, ch)
				play.Player(cplay.SUrl)
			} else {
				run = 0
				labs.Title.SetVisible(false)
			}
		} else {
			run = 0
			labs.Clear()
			labs.Count.SetMarkup("•")
			play.Player("")
			ch <- struct{}{}
			ch <- struct{}{}
			labs.Title.SetVisible(false)
			labs.Station.SetVisible(true)
			wg.Wait()
		}
	})

	cbox.Connect("button-press-event", func() {
		cplay = tmp[cplay.Next]
		labs.Clear()
		labs.Station.SetText(cplay.SName)
		labs.Count.SetMarkup("•")
	})

	ubox.Connect("button-press-event", func() {
		if proxy != "" {
			tmp = stream.Plist()
			labs.Clear()
			labs.Station.SetText(cplay.SName)
			labs.Count.SetMarkup("•")
			cplay = tmp[0]
		}
	})

	//bbox.Connect("event", func() {
	//	bitrate.SetMarkup("move")
	//})

	bbox.Connect("button-press-event", func() {
		x, y := win.GetPosition()
		w, h := win.GetSize()

		if win.GetDecorated() == true {
			win.SetDecorated(false)
			if x < W/2 {
				x = 0
			}
			if y < H/2 {
				y = 0
			}
			if x > W/2 {
				x = W - w
			}
			if y > H/2 {
				y = H
			}
			win.Move(x, y)
		} else {
			win.Move(W/2-w/2, H/2-h/2)
			win.SetDecorated(true)
		}
	})
	win.Add(cont)
	win.ShowAll()
	gtk.Main()
}

func Style(p *gtk.CssProvider, w *gtk.Widget, cn string) error {
	ctx, err := w.GetStyleContext()
	if err != nil {
		return err
	}
	ctx.AddProvider(p, 600)
	ctx.AddClass(cn)
	return nil
}

type Timer struct {
	Now time.Time
	Lab *Labels
}

func (t *Timer) Update(wg *sync.WaitGroup, ch chan struct{}) {
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
			dur := time.Since(t.Now)
			tm, _ := time.Parse("0405", "0000")
			tt := tm.Add(dur)
			t.Lab.Timer.SetMarkup("" + tt.Format("04:05") + "")
		case <-ch:
			t.Lab.Timer.SetText("00:00")
			wg.Done()
			return
		}
	}
}

type Titles struct {
	Tch <-chan string
	Lab *Labels
	Now *time.Time
}

type Data struct {
	rdr  io.Reader
	skip int
}

func (t *Titles) Update(wg *sync.WaitGroup, ch chan struct{}) {
	select {
	default:
		for meta := range t.Tch {
			*t.Now = time.Now()
			xtx:=toUtf8([]byte(meta))
			if len(xtx)>0{
				xtx=strings.TrimLeft(xtx,"'")
				xtx=strings.TrimRight(xtx,"'")
				if strings.Contains(xtx,"&"){
					xtx = strings.Replace(xtx, "&", "&", -1)
				}
			}
			t.Lab.Title.SetMarkup(""+xtx+"")
		}
	case <-ch:
		wg.Done()
		return
	}
}

func toUtf8(iso8859_1_buf []byte) string {
	buf := make([]rune, len(iso8859_1_buf))
	for i, b := range iso8859_1_buf {
		buf[i] = rune(b)
	}
	return string(buf)
}

func (L *Labels) Clear() {
	L.Bitrate.SetText("")
	L.Title.SetText("")
}

func (d *Data) Update(wg *sync.WaitGroup, ch chan struct{}) <-chan string {
	dh := make(chan string)
	wg.Add(1)
	go func() {
		bufrdr := bufio.NewReaderSize(d.rdr, d.skip)
		for {
			skipbytes := make([]byte, d.skip)
			_, err := io.ReadFull(bufrdr, skipbytes)
			if err != nil {
				log.Printf("Failed: %v\n", err)
				close(dh)
				return
			}
			c, err := bufrdr.ReadByte()
			if err != nil {
				log.Panic(err)
			}
			if c > 0 {
				meta, err := stream.ParseIcy(bufrdr, c)
				if err != nil {
					log.Panic(err)
				}
				dh <- meta
			}
			select {
			default:
			case <-ch:
				wg.Done()
				close(dh)
				return
			}
		}
	}()
	return dh
}

<|endoftext|>


<commit_before>/*  Copyright 2013, Raphael Estrada
    Author email:  <galaktor@gmx.de>
    Project home:  <https://github.com/galaktor/gorf24>
    Licensed under The MIT License (see README and LICENSE files)

    Updated to RF24 v.13
    2017, Marian Craciunescu, Marius Staicu
    Authors email:  <marian.craciunescu@esolutions.ro>, <marius.staicu@esolutions.ro>
    Project home:  <https://github.com/mariusstaicu/gorf24>
*/
package gorf24

/*
  #cgo LDFLAGS: -L./RF24_c
  #cgo LDFLAGS: -lrf24_c
  #cgo CFLAGS: -I./RF24_c
  #include "RF24_c.h"
  #include <stdio.h>
*/
import "C"
import (
	// "encoding/binary"
	// "fmt"
	"unsafe"
)

type LibRF24 interface {
	Delete()
	Begin()
	IsChipConnected() bool
	StartListening()
	StopListening()
	Available() bool
	Read(length uint8) ([]byte, bool)
	OpenWritingPipeDeprecated(address uint64)
	OpenReadingPipeDeprecated(pipe uint8, address uint64)
	OpenWritingPipe(address *uint8)
	OpenReadingPipe(pipe uint8, address *uint8)
	Write(data []byte, length uint8) bool
	PrintDetails()
	AvailablePipe() (bool, uint8)
	IsRxFifoFull() bool
	PowerDown()
	PowerUp()
	WriteMulticast(data []byte, length uint8, multicast bool) bool
	WriteFast(data []byte, length uint8) bool
	WriteFastMulticast(data []byte, length uint8, multicast bool) bool
	WriteBlocking(data []byte, length uint8, timeout uint32) bool
	IsTxStandBy() bool
	IsTxStandByExtended(timeout uint32, startTx bool) bool
	WriteAckPayload(pipe uint8, data []byte, length uint8)
	IsAckPayloadAvailable() bool
	WhatHappened() (tx_ok, tx_fail, rx_ready bool)
	StartWrite(data []byte, length uint8, multicast bool)
	StartFastWrite(data []byte, length uint8, multicast bool, startTx bool)
	ReUseTx()
	FlushTx() uint8
	TestCarrier() bool
	TestRPD() bool
	CloseReadingPipe(pipe uint8)
	SetAddressWidth(width uint8)
	SetRetries(delay uint8, count uint8)
	SetChannel(channel uint8)
	GetChannel(channel uint8) uint8
	SetPayloadSize(size uint8)
	GetPayloadSize() uint8
	GetDynamicPayloadSize() uint8
	EnableAckPayload()
	EnableDynamicPayloads()
	DisableDynamicPayloads()
	EnableDynamicAck()
	IsPVariant() bool
	SetAutoAck(enable bool)
	SetAutoAckPipe(pipe uint8, enable bool)
	SetPALevel(level PA_DBM)
	GetPALevel() PA_DBM
	SetDataRate(rate DATARATE)
	GetDataRate() DATARATE
	SetCRCLength(length CRCLENGTH)
	GetCRCLength() CRCLENGTH
	DisableCRC()
	MaskIRQ(txOk, txFail, rxReady bool)
}

// TODO: more idiomatic:
//   error handling
//   Read/Write interfaces
//   possibly more conventional byte slice passing
//   more type safety?
//   channel for available data, like time.Tick? r.Available() <-chan []byte  or so?
type RF24 struct {
	cptr        C.RF24Handle
	buffer_size uint8
	buffer      []byte
}

/*
func main() {
	var pipe uint64 = 0xF0F0F0F0E1
	r := New(25, 8, 32)
	defer r.Delete()
	r.Begin()
	r.SetRetries(15, 15)
	r.SetAutoAck(true)
	r.OpenReadingPipe(1, pipe)
	r.StartListening()
	r.PrintDetails()
	for {
		if r.Available() {
			data, _ := r.Read(4)
//			fmt.Printf("data: %v\n", data)
			payload := binary.LittleEndian.Uint32(data)
			fmt.Printf("Received %v\n", payload)
		} else {
			//
		}
	}
}
*/
func New(cepin uint8, cspin uint8, spispeed uint32) *RF24 {
	var r RF24
	r.cptr = C.new_rf24(C.uint8_t(cepin), C.uint8_t(cspin), C.uint32_t(spispeed))
	r.buffer = make([]byte, 128) // max payload length according to nrf24 spec
	return &r
}

func (r *RF24) Delete() {
	C.rf24_delete(r.cptr)
	r.cptr = nil
}
func (r *RF24) Begin() {
	C.rf24_begin(r.cptr)
}

func (r *RF24) IsChipConnected() bool {
	return gobool(C.rf24_isChipConnected(r.cptr))
}

func (r *RF24) StartListening() {
	C.rf24_startListening(r.cptr)
}

func (r *RF24) StopListening() {
	C.rf24_stopListening(r.cptr)
}

func (r *RF24) Available() bool {
	return gobool(C.rf24_available(r.cptr))
}

func (r *RF24) Read(length uint8) ([]byte, bool) {
	ok := gobool(C.rf24_read(r.cptr, unsafe.Pointer(&r.buffer[0]), C.uint8_t(length)))
	return r.buffer[:length], ok
}

func (r *RF24) OpenWritingPipeDeprecated(address uint64) {
	C.rf24_openWritingPipeDeprecated(r.cptr, C.uint64_t(address))
}

func (r *RF24) OpenReadingPipeDeprecated(pipe uint8, address uint64) {
	C.rf24_openReadingPipeDeprecated(r.cptr, C.uint8_t(pipe), C.uint64_t(address))
}

// TODO: implement Reader/Writer compatible interfaces
func (r *RF24) Write(data []byte, length uint8) bool {
	return gobool(C.rf24_write(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length)))
}

// TODO: String() method would be great
func (r *RF24) PrintDetails() {
	C.rf24_printDetails(r.cptr)
}

// TODO: create Pipe type, make this a func on Pipe
func (r *RF24) AvailablePipe() (bool, uint8) {
	var pipe C.uint8_t
	available := gobool(C.rf24_available_pipe(r.cptr, &pipe))
	return available, uint8(pipe)
}

func (r *RF24) IsRxFifoFull() bool {
	return gobool(C.rf24_rxFifoFull(r.cptr))
}

func (r *RF24) PowerDown() {
	C.rf24_powerDown(r.cptr)
}

func (r *RF24) PowerUp() {
	C.rf24_powerUp(r.cptr)
}

func (r *RF24) WriteMulticast(data []byte, length uint8, multicast bool) bool {
	return gobool(C.rf24_writeMulticast(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), cbool(multicast)))
}

func (r *RF24) WriteFast(data []byte, length uint8) bool {
	return gobool(C.rf24_writeFast(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length)))
}

func (r *RF24) WriteFastMulticast(data []byte, length uint8, multicast bool) bool {
	return gobool(C.rf24_writeFastMulticast(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), cbool(multicast)))
}

func (r *RF24) WriteBlocking(data []byte, length uint8, timeout uint32) bool {
	return gobool(C.rf24_writeBlocking(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), C.uint32_t(timeout)))
}

func (r *RF24) IsTxStandBy() bool {
	return gobool(C.rf24_txStandBy(r.cptr))
}

func (r *RF24) IsTxStandByExtended(timeout uint32, startTx bool) bool {
	return gobool(C.rf24_txStandByExtended(r.cptr, C.uint32_t(timeout), cbool(startTx)))
}

func (r *RF24) WriteAckPayload(pipe uint8, data []byte, length uint8) {
	C.rf24_writeAckPayload(r.cptr, C.uint8_t(pipe), unsafe.Pointer(&data[0]), C.uint8_t(length))
}

func (r *RF24) IsAckPayloadAvailable() bool {
	return gobool(C.rf24_isAckPayloadAvailable(r.cptr))
}

func (r *RF24) WhatHappened() (tx_ok, tx_fail, rx_ready bool) {
	var out_tx_ok, out_tx_fail, out_rx_ready C.cbool
	C.rf24_whatHappened(r.cptr, &out_tx_ok, &out_tx_fail, &out_rx_ready)
	tx_ok, tx_fail, rx_ready = gobool(out_tx_ok), gobool(out_tx_fail), gobool(out_rx_ready)
	return
}

func (r *RF24) StartWrite(data []byte, length uint8, multicast bool) {
	C.rf24_startWrite(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), cbool(multicast))
}

func (r *RF24) StartFastWrite(data []byte, length uint8, multicast bool, startTx bool) {
	C.rf24_startFastWrite(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), cbool(multicast), cbool(startTx))
}

func (r *RF24) ReUseTx() {
	C.rf24_reUseTX(r.cptr)
}

func (r *RF24) FlushTx() uint8 {
	return uint8(C.rf24_flush_tx(r.cptr))
}

func (r *RF24) TestCarrier() bool {
	return gobool(C.rf24_testCarrier(r.cptr))
}

func (r *RF24) TestRPD() bool {
	return gobool(C.rf24_testRPD(r.cptr))
}

func (r *RF24) CloseReadingPipe(pipe uint8) {
	C.rf24_closeReadingPipe(r.cptr, C.uint8_t(pipe))
}

func (r *RF24) SetAddressWidth(width uint8) {
	C.rf24_setAddressWidth(r.cptr, C.uint8_t(width))
}

func (r *RF24) SetRetries(delay uint8, count uint8) {
	C.rf24_setRetries(r.cptr, C.uint8_t(delay), C.uint8_t(count))
}

func (r *RF24) SetChannel(channel uint8) {
	C.rf24_setChannel(r.cptr, C.uint8_t(channel))
}

func (r *RF24) GetChannel(channel uint8) uint8 {
	return uint8(C.rf24_getChannel(r.cptr))
}

func (r *RF24) SetPayloadSize(size uint8) {
	C.rf24_setPayloadSize(r.cptr, C.uint8_t(size))
}

func (r *RF24) GetPayloadSize() uint8 {
	return uint8(C.rf24_getPayloadSize(r.cptr))
}

func (r *RF24) GetDynamicPayloadSize() uint8 {
	return uint8(C.rf24_getDynamicPayloadSize(r.cptr))
}

func (r *RF24) EnableAckPayload() {
	C.rf24_enableAckPayload(r.cptr)
}

func (r *RF24) EnableDynamicPayloads() {
	C.rf24_enableDynamicPayloads(r.cptr)
}

func (r *RF24) DisableDynamicPayloads() {
	C.rf24_disableDynamicPayloads(r.cptr)
}

func (r *RF24) EnableDynamicAck() {
	C.rf24_enableDynamicAck(r.cptr)
}

func (r *RF24) IsPVariant() bool {
	return gobool(C.rf24_isPVariant(r.cptr))
}

func (r *RF24) SetAutoAck(enable bool) {
	C.rf24_setAutoAck(r.cptr, cbool(enable))
}

func (r *RF24) SetAutoAckPipe(pipe uint8, enable bool) {
	C.rf24_setAutoAck_pipe(r.cptr, C.uint8_t(pipe), cbool(enable))
}

// Is there any way to use the rf24_pa_dbm_e enum type directly
func (r *RF24) SetPALevel(level PA_DBM) {
	C.rf24_setPALevel(r.cptr, C.rf24_pa_dbm_val(level))
}

func (r *RF24) GetPALevel() PA_DBM {
	return PA_DBM(C.rf24_getPALevel(r.cptr))
}

func (r *RF24) SetDataRate(rate DATARATE) {
	C.rf24_setDataRate(r.cptr, C.rf24_datarate_val(rate))
}

func (r *RF24) GetDataRate() DATARATE {
	return DATARATE(C.rf24_getDataRate(r.cptr))
}

func (r *RF24) SetCRCLength(length CRCLENGTH) {
	C.rf24_setCRCLength(r.cptr, C.rf24_crclength_val(length))
}

func (r *RF24) GetCRCLength() CRCLENGTH {
	return CRCLENGTH(C.rf24_getCRCLength(r.cptr))
}

func (r *RF24) DisableCRC() {
	C.rf24_disableCRC(r.cptr)
}

func (r *RF24) MaskIRQ(txOk, txFail, rxReady bool) {
	C.rf24_maskIRQ(r.cptr, cbool(txOk), cbool(txFail), cbool(rxReady))
}
<commit_msg>addded mising function impl<commit_after>/*  Copyright 2013, Raphael Estrada
    Author email:  <galaktor@gmx.de>
    Project home:  <https://github.com/galaktor/gorf24>
    Licensed under The MIT License (see README and LICENSE files)

    Updated to RF24 v.13
    2017, Marian Craciunescu, Marius Staicu
    Authors email:  <marian.craciunescu@esolutions.ro>, <marius.staicu@esolutions.ro>
    Project home:  <https://github.com/mariusstaicu/gorf24>
*/
package gorf24

/*
  #cgo LDFLAGS: -L./RF24_c
  #cgo LDFLAGS: -lrf24_c
  #cgo CFLAGS: -I./RF24_c
  #include "RF24_c.h"
  #include <stdio.h>
*/
import "C"
import (
	// "encoding/binary"
	// "fmt"
	"unsafe"
)

type LibRF24 interface {
	Delete()
	Begin()
	IsChipConnected() bool
	StartListening()
	StopListening()
	Available() bool
	Read(length uint8) ([]byte, bool)
	OpenWritingPipeDeprecated(address uint64)
	OpenReadingPipeDeprecated(pipe uint8, address uint64)
	OpenWritingPipe(address *uint8)
	OpenReadingPipe(pipe uint8, address *uint8)
	Write(data []byte, length uint8) bool
	PrintDetails()
	AvailablePipe() (bool, uint8)
	IsRxFifoFull() bool
	PowerDown()
	PowerUp()
	WriteMulticast(data []byte, length uint8, multicast bool) bool
	WriteFast(data []byte, length uint8) bool
	WriteFastMulticast(data []byte, length uint8, multicast bool) bool
	WriteBlocking(data []byte, length uint8, timeout uint32) bool
	IsTxStandBy() bool
	IsTxStandByExtended(timeout uint32, startTx bool) bool
	WriteAckPayload(pipe uint8, data []byte, length uint8)
	IsAckPayloadAvailable() bool
	WhatHappened() (tx_ok, tx_fail, rx_ready bool)
	StartWrite(data []byte, length uint8, multicast bool)
	StartFastWrite(data []byte, length uint8, multicast bool, startTx bool)
	ReUseTx()
	FlushTx() uint8
	TestCarrier() bool
	TestRPD() bool
	CloseReadingPipe(pipe uint8)
	SetAddressWidth(width uint8)
	SetRetries(delay uint8, count uint8)
	SetChannel(channel uint8)
	GetChannel(channel uint8) uint8
	SetPayloadSize(size uint8)
	GetPayloadSize() uint8
	GetDynamicPayloadSize() uint8
	EnableAckPayload()
	EnableDynamicPayloads()
	DisableDynamicPayloads()
	EnableDynamicAck()
	IsPVariant() bool
	SetAutoAck(enable bool)
	SetAutoAckPipe(pipe uint8, enable bool)
	SetPALevel(level PA_DBM)
	GetPALevel() PA_DBM
	SetDataRate(rate DATARATE)
	GetDataRate() DATARATE
	SetCRCLength(length CRCLENGTH)
	GetCRCLength() CRCLENGTH
	DisableCRC()
	MaskIRQ(txOk, txFail, rxReady bool)
}

// TODO: more idiomatic:
//   error handling
//   Read/Write interfaces
//   possibly more conventional byte slice passing
//   more type safety?
//   channel for available data, like time.Tick? r.Available() <-chan []byte  or so?
type RF24 struct {
	cptr        C.RF24Handle
	buffer_size uint8
	buffer      []byte
}

/*
func main() {
	var pipe uint64 = 0xF0F0F0F0E1
	r := New(25, 8, 32)
	defer r.Delete()
	r.Begin()
	r.SetRetries(15, 15)
	r.SetAutoAck(true)
	r.OpenReadingPipe(1, pipe)
	r.StartListening()
	r.PrintDetails()
	for {
		if r.Available() {
			data, _ := r.Read(4)
//			fmt.Printf("data: %v\n", data)
			payload := binary.LittleEndian.Uint32(data)
			fmt.Printf("Received %v\n", payload)
		} else {
			//
		}
	}
}
*/
func New(cepin uint8, cspin uint8, spispeed uint32) *RF24 {
	var r RF24
	r.cptr = C.new_rf24(C.uint8_t(cepin), C.uint8_t(cspin), C.uint32_t(spispeed))
	r.buffer = make([]byte, 128) // max payload length according to nrf24 spec
	return &r
}

func (r *RF24) Delete() {
	C.rf24_delete(r.cptr)
	r.cptr = nil
}
func (r *RF24) Begin() {
	C.rf24_begin(r.cptr)
}

func (r *RF24) IsChipConnected() bool {
	return gobool(C.rf24_isChipConnected(r.cptr))
}

func (r *RF24) StartListening() {
	C.rf24_startListening(r.cptr)
}

func (r *RF24) StopListening() {
	C.rf24_stopListening(r.cptr)
}

func (r *RF24) Available() bool {
	return gobool(C.rf24_available(r.cptr))
}

func (r *RF24) Read(length uint8) ([]byte, bool) {
	ok := gobool(C.rf24_read(r.cptr, unsafe.Pointer(&r.buffer[0]), C.uint8_t(length)))
	return r.buffer[:length], ok
}

func (r *RF24) OpenWritingPipe(address *uint8) {
	C.rf24_openWritingPipe(r.cptr, unsafe.Pointer(address))
}

func (r *RF24) OpenWritingPipeDeprecated(address uint64) {
	C.rf24_openWritingPipeDeprecated(r.cptr, C.uint64_t(address))
}

func (r *RF24) OpenReadingPipe(pipe uint8, address *uint8) {
	C.rf24_openReadingPipe(r.cptr, C.uint8_t(pipe), unsafe.Pointer(address))
}

func (r *RF24) OpenReadingPipeDeprecated(pipe uint8, address uint64) {
	C.rf24_openReadingPipeDeprecated(r.cptr, C.uint8_t(pipe), C.uint64_t(address))
}

// TODO: implement Reader/Writer compatible interfaces
func (r *RF24) Write(data []byte, length uint8) bool {
	return gobool(C.rf24_write(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length)))
}

// TODO: String() method would be great
func (r *RF24) PrintDetails() {
	C.rf24_printDetails(r.cptr)
}

// TODO: create Pipe type, make this a func on Pipe
func (r *RF24) AvailablePipe() (bool, uint8) {
	var pipe C.uint8_t
	available := gobool(C.rf24_available_pipe(r.cptr, &pipe))
	return available, uint8(pipe)
}

func (r *RF24) IsRxFifoFull() bool {
	return gobool(C.rf24_rxFifoFull(r.cptr))
}

func (r *RF24) PowerDown() {
	C.rf24_powerDown(r.cptr)
}

func (r *RF24) PowerUp() {
	C.rf24_powerUp(r.cptr)
}

func (r *RF24) WriteMulticast(data []byte, length uint8, multicast bool) bool {
	return gobool(C.rf24_writeMulticast(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), cbool(multicast)))
}

func (r *RF24) WriteFast(data []byte, length uint8) bool {
	return gobool(C.rf24_writeFast(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length)))
}

func (r *RF24) WriteFastMulticast(data []byte, length uint8, multicast bool) bool {
	return gobool(C.rf24_writeFastMulticast(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), cbool(multicast)))
}

func (r *RF24) WriteBlocking(data []byte, length uint8, timeout uint32) bool {
	return gobool(C.rf24_writeBlocking(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), C.uint32_t(timeout)))
}

func (r *RF24) IsTxStandBy() bool {
	return gobool(C.rf24_txStandBy(r.cptr))
}

func (r *RF24) IsTxStandByExtended(timeout uint32, startTx bool) bool {
	return gobool(C.rf24_txStandByExtended(r.cptr, C.uint32_t(timeout), cbool(startTx)))
}

func (r *RF24) WriteAckPayload(pipe uint8, data []byte, length uint8) {
	C.rf24_writeAckPayload(r.cptr, C.uint8_t(pipe), unsafe.Pointer(&data[0]), C.uint8_t(length))
}

func (r *RF24) IsAckPayloadAvailable() bool {
	return gobool(C.rf24_isAckPayloadAvailable(r.cptr))
}

func (r *RF24) WhatHappened() (tx_ok, tx_fail, rx_ready bool) {
	var out_tx_ok, out_tx_fail, out_rx_ready C.cbool
	C.rf24_whatHappened(r.cptr, &out_tx_ok, &out_tx_fail, &out_rx_ready)
	tx_ok, tx_fail, rx_ready = gobool(out_tx_ok), gobool(out_tx_fail), gobool(out_rx_ready)
	return
}

func (r *RF24) StartWrite(data []byte, length uint8, multicast bool) {
	C.rf24_startWrite(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), cbool(multicast))
}

func (r *RF24) StartFastWrite(data []byte, length uint8, multicast bool, startTx bool) {
	C.rf24_startFastWrite(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length), cbool(multicast), cbool(startTx))
}

func (r *RF24) ReUseTx() {
	C.rf24_reUseTX(r.cptr)
}

func (r *RF24) FlushTx() uint8 {
	return uint8(C.rf24_flush_tx(r.cptr))
}

func (r *RF24) TestCarrier() bool {
	return gobool(C.rf24_testCarrier(r.cptr))
}

func (r *RF24) TestRPD() bool {
	return gobool(C.rf24_testRPD(r.cptr))
}

func (r *RF24) CloseReadingPipe(pipe uint8) {
	C.rf24_closeReadingPipe(r.cptr, C.uint8_t(pipe))
}

func (r *RF24) SetAddressWidth(width uint8) {
	C.rf24_setAddressWidth(r.cptr, C.uint8_t(width))
}

func (r *RF24) SetRetries(delay uint8, count uint8) {
	C.rf24_setRetries(r.cptr, C.uint8_t(delay), C.uint8_t(count))
}

func (r *RF24) SetChannel(channel uint8) {
	C.rf24_setChannel(r.cptr, C.uint8_t(channel))
}

func (r *RF24) GetChannel(channel uint8) uint8 {
	return uint8(C.rf24_getChannel(r.cptr))
}

func (r *RF24) SetPayloadSize(size uint8) {
	C.rf24_setPayloadSize(r.cptr, C.uint8_t(size))
}

func (r *RF24) GetPayloadSize() uint8 {
	return uint8(C.rf24_getPayloadSize(r.cptr))
}

func (r *RF24) GetDynamicPayloadSize() uint8 {
	return uint8(C.rf24_getDynamicPayloadSize(r.cptr))
}

func (r *RF24) EnableAckPayload() {
	C.rf24_enableAckPayload(r.cptr)
}

func (r *RF24) EnableDynamicPayloads() {
	C.rf24_enableDynamicPayloads(r.cptr)
}

func (r *RF24) DisableDynamicPayloads() {
	C.rf24_disableDynamicPayloads(r.cptr)
}

func (r *RF24) EnableDynamicAck() {
	C.rf24_enableDynamicAck(r.cptr)
}

func (r *RF24) IsPVariant() bool {
	return gobool(C.rf24_isPVariant(r.cptr))
}

func (r *RF24) SetAutoAck(enable bool) {
	C.rf24_setAutoAck(r.cptr, cbool(enable))
}

func (r *RF24) SetAutoAckPipe(pipe uint8, enable bool) {
	C.rf24_setAutoAck_pipe(r.cptr, C.uint8_t(pipe), cbool(enable))
}

// Is there any way to use the rf24_pa_dbm_e enum type directly
func (r *RF24) SetPALevel(level PA_DBM) {
	C.rf24_setPALevel(r.cptr, C.rf24_pa_dbm_val(level))
}

func (r *RF24) GetPALevel() PA_DBM {
	return PA_DBM(C.rf24_getPALevel(r.cptr))
}

func (r *RF24) SetDataRate(rate DATARATE) {
	C.rf24_setDataRate(r.cptr, C.rf24_datarate_val(rate))
}

func (r *RF24) GetDataRate() DATARATE {
	return DATARATE(C.rf24_getDataRate(r.cptr))
}

func (r *RF24) SetCRCLength(length CRCLENGTH) {
	C.rf24_setCRCLength(r.cptr, C.rf24_crclength_val(length))
}

func (r *RF24) GetCRCLength() CRCLENGTH {
	return CRCLENGTH(C.rf24_getCRCLength(r.cptr))
}

func (r *RF24) DisableCRC() {
	C.rf24_disableCRC(r.cptr)
}

func (r *RF24) MaskIRQ(txOk, txFail, rxReady bool) {
	C.rf24_maskIRQ(r.cptr, cbool(txOk), cbool(txFail), cbool(rxReady))
}
<|endoftext|>


<commit_before>// Command taggo is a simple audio tag parser, which is meant to demonstrate the functionality
// of the taggolib package.
package main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/jesseward/taggolib"
)

func main() {
	// Ensure at least one parameter was passed
	if len(os.Args) < 2 {
		fmt.Println("taggo: no file path parameter")
		return
	}

	// Verify path actually exists
	if _, err := os.Stat(os.Args[1]); err != nil {
		fmt.Println("taggo:", err)
		return
	}

	// Invoke a recursive file walk on all parameter directories
	for _, arg := range os.Args[1:] {
		err := filepath.Walk(arg, func(path string, info os.FileInfo, err error) error {
			// Skip directories
			if info.IsDir() {
				return nil
			}

			// Open file
			file, err := os.Open(path)
			if err != nil {
				return err
			}
			defer file.Close()

			// Load file using taggolib
			audio, err := taggolib.New(file)
			if err != nil {
				// Check for unknown format, which will be skipped
				if taggolib.IsUnknownFormat(err) {
					return nil
				}

				// Check for unsupported version, invalid stream, or EOF, which will be logged and skipped
				if taggolib.IsUnsupportedVersion(err) || taggolib.IsInvalidStream(err) || err == io.EOF {
					fmt.Println("taggo:", err, ":", path)
					return nil
				}

				return err
			}

			// Calculate duration in mm:ss format
			seconds := int(audio.Duration().Seconds())
			minutes := seconds / 60
			seconds = seconds - (minutes * 60)

			// Print information about file
			fmt.Printf("%s - %s - %s [#%d.%02d] [%02d:%02d] [%s/%dkbps/%dbit/%dkHz] [%s]\n",
				audio.Artist(), audio.Album(), audio.Title(), audio.DiscNumber(), audio.TrackNumber(),
				minutes, seconds, audio.Format(), audio.Bitrate(), audio.BitDepth(), audio.SampleRate()/1000, audio.Publisher())

			return nil
		})

		// Check for fatal walk error
		if err != nil {
			fmt.Println("taggo: fatal:", err)
			return
		}
	}
}
<commit_msg>reverting import path for taggo example script.<commit_after>// Command taggo is a simple audio tag parser, which is meant to demonstrate the functionality
// of the taggolib package.
package main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/mdlayher/taggolib"
)

func main() {
	// Ensure at least one parameter was passed
	if len(os.Args) < 2 {
		fmt.Println("taggo: no file path parameter")
		return
	}

	// Verify path actually exists
	if _, err := os.Stat(os.Args[1]); err != nil {
		fmt.Println("taggo:", err)
		return
	}

	// Invoke a recursive file walk on all parameter directories
	for _, arg := range os.Args[1:] {
		err := filepath.Walk(arg, func(path string, info os.FileInfo, err error) error {
			// Skip directories
			if info.IsDir() {
				return nil
			}

			// Open file
			file, err := os.Open(path)
			if err != nil {
				return err
			}
			defer file.Close()

			// Load file using taggolib
			audio, err := taggolib.New(file)
			if err != nil {
				// Check for unknown format, which will be skipped
				if taggolib.IsUnknownFormat(err) {
					return nil
				}

				// Check for unsupported version, invalid stream, or EOF, which will be logged and skipped
				if taggolib.IsUnsupportedVersion(err) || taggolib.IsInvalidStream(err) || err == io.EOF {
					fmt.Println("taggo:", err, ":", path)
					return nil
				}

				return err
			}

			// Calculate duration in mm:ss format
			seconds := int(audio.Duration().Seconds())
			minutes := seconds / 60
			seconds = seconds - (minutes * 60)

			// Print information about file
			fmt.Printf("%s - %s - %s [#%d.%02d] [%02d:%02d] [%s/%dkbps/%dbit/%dkHz] [%s]\n",
				audio.Artist(), audio.Album(), audio.Title(), audio.DiscNumber(), audio.TrackNumber(),
				minutes, seconds, audio.Format(), audio.Bitrate(), audio.BitDepth(), audio.SampleRate()/1000, audio.Publisher())

			return nil
		})

		// Check for fatal walk error
		if err != nil {
			fmt.Println("taggo: fatal:", err)
			return
		}
	}
}
<|endoftext|>


<commit_before>package gautomator

import (
	"fmt"
	"github.com/gonum/matrix/mat64" // Matrix
	"io"
	"time"
)

// A task is an action executed by a module
type Task struct {
	Id     int      `json:"id"`
	Origin string   `json:"origin"`
	Name   string   `json:"name"` //the task name
	Node   string   `json:"node"` // The node name
	Module string   `json:"module"`
	Args   []string `json:"args"`
	Status int      `json:"status"` //-3: queued
	// -2 Advertized (infored that the dependencies are done)
	// -1: running
	// >=0 : return code
	StartTime      time.Time `json:"startTime"`
	EndTime        time.Time `json:"endTime"`
	TaskCanRunChan chan bool // true: run, false: wait
}

// This is the structure corresponding to the "dot-graph" of a task list
// We store the nodes in a map
// The index is the source node
type TaskGraphStructure struct {
	Tasks           map[int]*Task
	DegreeMatrix    *mat64.Dense
	AdjacencyMatrix *mat64.Dense // Row id is the map id of the source task
	// Col id is the map id of the destination task
}

func (this *TaskGraphStructure) PrintAdjacencyMatrix() {
	rowSize, colSize := this.AdjacencyMatrix.Dims()
	fmt.Printf("  ")
	for c := 0; c < colSize; c++ {
		fmt.Printf("%v ", this.Tasks[c].Name)
	}
	fmt.Printf("\n")
	for r := 0; r < rowSize; r++ {
		fmt.Printf("%v ", this.Tasks[r].Name)
		for c := 0; c < colSize; c++ {
			fmt.Printf("%v ", this.AdjacencyMatrix.At(r, c))
		}
		fmt.Printf("\n")
	}
}

func (this *TaskGraphStructure) PrintDegreeMatrix() {
	rowSize, colSize := this.DegreeMatrix.Dims()
	for r := 0; r < rowSize; r++ {
		for c := 0; c < colSize; c++ {
			fmt.Printf("%v ", this.DegreeMatrix.At(r, c))
		}
		fmt.Printf("\n")
	}
}

func NewTask() *Task {
	return &Task{
		-1,
		"null",
		"null",
		"null",
		"dummy",
		make([]string, 1),
		-3,
		time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
		time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
		make(chan bool),
	}

}
func NewTaskGraphStructure() *TaskGraphStructure {
	return &TaskGraphStructure{
		make(map[int]*Task, 0),
		mat64.NewDense(0, 0, nil),
		mat64.NewDense(0, 0, nil),
	}
}

// Returns a combination of the current structure
// and the one passed as argument
func (this *TaskGraphStructure) AugmentTaskStructure(taskStructure *TaskGraphStructure) *TaskGraphStructure {
	// merging adjacency matrix
	initialRowLen, initialColLen := this.AdjacencyMatrix.Dims()
	addedRowLen, addedColLen := taskStructure.AdjacencyMatrix.Dims()
	this.AdjacencyMatrix = mat64.DenseCopyOf(this.AdjacencyMatrix.Grow(addedRowLen, addedColLen))
	//a, b := this.AdjacencyMatrix.Dims()
	for r := 0; r < initialRowLen+addedRowLen; r++ {
		for c := 0; c < initialColLen+addedColLen; c++ {
			switch {
			case r < initialRowLen && c < initialColLen:
				// If we are in the original matrix: do nothing
			case r < initialRowLen && c > initialColLen:
				// If outside, put some zero
				this.AdjacencyMatrix.Set(r, c, float64(0))
			case r > initialRowLen && c < initialColLen:
				// If outside, put some zero
				this.AdjacencyMatrix.Set(r, c, float64(0))
			case r >= initialRowLen && c >= initialColLen:
				// Add the new matrix
				this.AdjacencyMatrix.Set(r, c, taskStructure.AdjacencyMatrix.At(r-initialRowLen, c-initialColLen))
			}
		}
	}
	// merging degree matrix
	initialRowLen, initialColLen = this.DegreeMatrix.Dims()
	addedRowLen, addedColLen = taskStructure.DegreeMatrix.Dims()
	this.DegreeMatrix = mat64.DenseCopyOf(this.DegreeMatrix.Grow(addedRowLen, addedColLen))
	for r := 0; r < initialRowLen+addedRowLen; r++ {
		for c := 0; c < initialColLen+addedColLen; c++ {
			switch {
			case r < initialRowLen && c < initialColLen:
				// If we are in the original matrix: do nothing
			case r < initialRowLen && c > initialColLen:
				// If outside, set zero
				this.DegreeMatrix.Set(r, c, float64(0))
			case r > initialRowLen && c < initialColLen:
				// If outside, set zero
				this.DegreeMatrix.Set(r, c, float64(0))
			case r >= initialRowLen && c >= initialColLen:
				// Add the new matrix
				this.DegreeMatrix.Set(r, c, taskStructure.DegreeMatrix.At(r-initialRowLen, c-initialColLen))
			}
		}
	}
	actualSize := len(this.Tasks)
	for i, task := range taskStructure.Tasks {
		task.Id = actualSize + i
		this.Tasks[actualSize+i] = task
	}
	return this
}

func (this *TaskGraphStructure) getTaskFromName(name string) []int {
	indexA := make([]int,1)
	indexA[0] = -1
	for _ , task := range this.Tasks {
		if task.Name == name {
		    if indexA[0] == -1 {
			indexA = append(indexA[1:],task.Id)
		    } else {
			indexA = append(indexA,task.Id)
		    }
		}
	}
	return indexA
}

func colSum(matrix *mat64.Dense, colId int) float64 {
	row, _ := matrix.Dims()
	sum := float64(0)
	for r := 0; r < row; r++ {
		sum += matrix.At(r, colId)
	}
	return sum
}

func rowSum(matrix *mat64.Dense, rowId int) float64 {
	_, col := matrix.Dims()
	sum := float64(0)
	for c := 0; c < col; c++ {
		sum += matrix.At(rowId, c)
	}
	return sum
}

// the aim of this function is to find if a task has a subdefinition (aka an origin) and change it
// Example:
// imagine the graphs
// digraph bla {
//    a -> b;
//    b -> c;
// }
// digraph b {
//    alpha -> gamma;
// }
// then alpha and beta will have "b" as Origin.
// therefore we should add a link in the AdjacencyMatix and in the DegreeMatrix
func (this *TaskGraphStructure) Relink() *TaskGraphStructure {
	// IN this array we store the row,col on which we set 1
	backup := make(map[string][]int, 0)
	_, col := this.AdjacencyMatrix.Dims()
	for _, task := range this.Tasks {
		if colSum(this.AdjacencyMatrix, task.Id) == 0 {
			id := this.getTaskFromName(task.Origin)
			// TODO There should be only one task, otherwise display an error
			if id[0] != -1 {
				// Task is a meta task
				this.Tasks[id[0]].Module = "meta"
				this.AdjacencyMatrix.Set(id[0], task.Id, float64(1))
				backup[task.Origin] = append(backup[task.Origin], id[0], task.Id)
			}
		}
		if rowSum(this.AdjacencyMatrix, task.Id) == 0 {
			id := this.getTaskFromName(task.Origin)
			// TODO There should be only one task, otherwise display an error
			if id[0] != -1 {
				for c := 0; c < col; c++ {
					add := true
					for counter := 0; counter < len(backup[task.Origin])-1; counter += 2 {
						if backup[task.Origin][counter] == id[0] && backup[task.Origin][counter+1] == c {
							add = false
						}
					}
					if add == true && this.Tasks[c].Origin != task.Origin {
						this.AdjacencyMatrix.Set(task.Id, c, this.AdjacencyMatrix.At(task.Id, c)+this.AdjacencyMatrix.At(id[0], c))
					}
				}
			}
		}
	}
	//TODO: complete the degreematrix
	return this
}

// Duplicate the task "id"
// Returns the id of the new task and the whole structure
func (this *TaskGraphStructure) DuplicateTask(name string) []int {
	newIds := make([]int,1)
	newIds[0] = -1
	Ids := this.getTaskFromName(name)
	for _, id := range Ids {
	    if id != -1 {
		newId, _ := this.AdjacencyMatrix.Dims()
		if newIds[0] == -1 {
		    newIds = append(newIds[1:],newId)
		} else {
		    newIds = append(newIds,newId)
		}
		newTask := NewTask()
		newTask.Id = newId
		newTask.Name = this.Tasks[id].Name
		newTask.Origin = this.Tasks[id].Origin
		newTask.Module = this.Tasks[id].Module
		newTask.Node = this.Tasks[id].Node
		newTask.Args = this.Tasks[id].Args
		newTask.Status = this.Tasks[id].Status
		this.Tasks[newId] = newTask
		this.AdjacencyMatrix = mat64.DenseCopyOf(this.AdjacencyMatrix.Grow(1, 1))
		this.DegreeMatrix = mat64.DenseCopyOf(this.DegreeMatrix.Grow(1, 1))
		for r := 0; r < newId; r++ {
		    this.AdjacencyMatrix.Set(r, newId, this.AdjacencyMatrix.At(r, id))
		    this.DegreeMatrix.Set(r, newId, this.DegreeMatrix.At(r, id))
		}
		// Copy the col 'id' to col 'newId'
		for c := 0; c < newId; c++ {
		    this.AdjacencyMatrix.Set(newId, c, this.AdjacencyMatrix.At(id, c))
		    this.DegreeMatrix.Set(newId, c, this.DegreeMatrix.At(id, c))
		}
	    }
	}
	return newIds
}

// This function print the dot file associated with the graph
func (this *TaskGraphStructure) PrintDot(w io.Writer) {
	fmt.Fprintln(w, "digraph G {")
	// Writing node definition
	for _, task := range this.Tasks {
		fmt.Fprintf(w, "\t\"%v\" [\n", task.Id)
		fmt.Fprintf(w, "\t\tid = \"%v\"\n", task.Id)
		if task.Module == "meta" {
			fmt.Fprintln(w, "\t\tshape=diamond")
			fmt.Fprintf(w, "\t\tlabel=\"%v\"", task.Name)
		} else {
			fmt.Fprintf(w, "\t\tlabel = \"<name>%v|<node>%v|<module>%v\"\n", task.Name, task.Node, task.Module)
			fmt.Fprintf(w, "\t\tshape = \"record\"\n")
		}
		fmt.Fprintf(w, "\t];\n")
	}
	row, col := this.AdjacencyMatrix.Dims()
	for r := 0; r < row; r++ {
		for c := 0; c < col; c++ {
			if this.AdjacencyMatrix.At(r, c) == 1 {
				fmt.Fprintf(w, "\t%v -> %v\n", this.Tasks[r].Id, this.Tasks[c].Id)
			}
		}
	}
	fmt.Fprintln(w, "}")
}

// Return a structure of all the task with the given origin
func (this *TaskGraphStructure) GetSubstructure(origin string) *TaskGraphStructure {
	subTaskStructure := NewTaskGraphStructure()
	index := 0
	tasksToExtract := make(map[int]*Task, 0)
	for _, task := range this.Tasks {
		if task.Origin == origin {
			//fmt.Printf("Adding %v(%v) at index:%v\n", task.Name, task.Id, index)
			tasksToExtract[index] = task
			index += 1
		}
	}
	// Create the matrix of the correct size
	size := len(tasksToExtract)
	if size > 0 {
		subTaskStructure.AdjacencyMatrix = mat64.NewDense(size, size, nil)
		subTaskStructure.DegreeMatrix = mat64.NewDense(size, size, nil)
		for i := 0; i < size; i++ {
			task := tasksToExtract[i]
			//fmt.Printf("Task with ID:%v and name:%v will have id:%v\n", task.Id, task.Name, i)
			// Construct the AdjacencyMatrix line by line
			for col := 0; col < size; col++ {
				task2 := tasksToExtract[col]
				//fmt.Printf("Setting %v,%v with value from %v,%v\n", i, col, task.Id, task2.Id)
				subTaskStructure.AdjacencyMatrix.Set(i, col, this.AdjacencyMatrix.At(task.Id, task2.Id))
			}
			subTaskStructure.DegreeMatrix.Set(i, i, this.DegreeMatrix.At(task.Id, task.Id))
			subTaskStructure.Tasks[i] = NewTask()
			subTaskStructure.Tasks[i].Name = task.Name
			subTaskStructure.Tasks[i].Module = task.Module
			subTaskStructure.Tasks[i].Args = task.Args
			subTaskStructure.Tasks[i].Origin = task.Origin
			subTaskStructure.Tasks[i].Id = i
		}
		//subTaskStructure.PrintAdjacencyMatrix()
		return subTaskStructure
	} else {
		return nil
	}
}
<commit_msg>Added the skeletons of some functions<commit_after>package gautomator

import (
	"fmt"
	"github.com/gonum/matrix/mat64" // Matrix
	"io"
	"time"
)

// A task is an action executed by a module
type Task struct {
	Id     int      `json:"id"`
	Origin string   `json:"origin"`
	Name   string   `json:"name"` //the task name
	Node   string   `json:"node"` // The node name
	Module string   `json:"module"`
	Args   []string `json:"args"`
	Status int      `json:"status"` //-3: queued
	// -2 Advertized (infored that the dependencies are done)
	// -1: running
	// >=0 : return code
	StartTime      time.Time `json:"startTime"`
	EndTime        time.Time `json:"endTime"`
	TaskCanRunChan chan bool // true: run, false: wait
}

// This is the structure corresponding to the "dot-graph" of a task list
// We store the nodes in a map
// The index is the source node
type TaskGraphStructure struct {
	Tasks           map[int]*Task
	DegreeMatrix    *mat64.Dense
	AdjacencyMatrix *mat64.Dense // Row id is the map id of the source task
	// Col id is the map id of the destination task
}

func (this *TaskGraphStructure) PrintAdjacencyMatrix() {
	rowSize, colSize := this.AdjacencyMatrix.Dims()
	fmt.Printf("  ")
	for c := 0; c < colSize; c++ {
		fmt.Printf("%v ", this.Tasks[c].Name)
	}
	fmt.Printf("\n")
	for r := 0; r < rowSize; r++ {
		fmt.Printf("%v ", this.Tasks[r].Name)
		for c := 0; c < colSize; c++ {
			fmt.Printf("%v ", this.AdjacencyMatrix.At(r, c))
		}
		fmt.Printf("\n")
	}
}

func (this *TaskGraphStructure) PrintDegreeMatrix() {
	rowSize, colSize := this.DegreeMatrix.Dims()
	for r := 0; r < rowSize; r++ {
		for c := 0; c < colSize; c++ {
			fmt.Printf("%v ", this.DegreeMatrix.At(r, c))
		}
		fmt.Printf("\n")
	}
}

func NewTask() *Task {
	return &Task{
		-1,
		"null",
		"null",
		"null",
		"dummy",
		make([]string, 1),
		-3,
		time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
		time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
		make(chan bool),
	}

}
func NewTaskGraphStructure() *TaskGraphStructure {
	return &TaskGraphStructure{
		make(map[int]*Task, 0),
		mat64.NewDense(0, 0, nil),
		mat64.NewDense(0, 0, nil),
	}
}

// Returns a combination of the current structure
// and the one passed as argument
func (this *TaskGraphStructure) AugmentTaskStructure(taskStructure *TaskGraphStructure) *TaskGraphStructure {
	// merging adjacency matrix
	initialRowLen, initialColLen := this.AdjacencyMatrix.Dims()
	addedRowLen, addedColLen := taskStructure.AdjacencyMatrix.Dims()
	this.AdjacencyMatrix = mat64.DenseCopyOf(this.AdjacencyMatrix.Grow(addedRowLen, addedColLen))
	//a, b := this.AdjacencyMatrix.Dims()
	for r := 0; r < initialRowLen+addedRowLen; r++ {
		for c := 0; c < initialColLen+addedColLen; c++ {
			switch {
			case r < initialRowLen && c < initialColLen:
				// If we are in the original matrix: do nothing
			case r < initialRowLen && c > initialColLen:
				// If outside, put some zero
				this.AdjacencyMatrix.Set(r, c, float64(0))
			case r > initialRowLen && c < initialColLen:
				// If outside, put some zero
				this.AdjacencyMatrix.Set(r, c, float64(0))
			case r >= initialRowLen && c >= initialColLen:
				// Add the new matrix
				this.AdjacencyMatrix.Set(r, c, taskStructure.AdjacencyMatrix.At(r-initialRowLen, c-initialColLen))
			}
		}
	}
	// merging degree matrix
	initialRowLen, initialColLen = this.DegreeMatrix.Dims()
	addedRowLen, addedColLen = taskStructure.DegreeMatrix.Dims()
	this.DegreeMatrix = mat64.DenseCopyOf(this.DegreeMatrix.Grow(addedRowLen, addedColLen))
	for r := 0; r < initialRowLen+addedRowLen; r++ {
		for c := 0; c < initialColLen+addedColLen; c++ {
			switch {
			case r < initialRowLen && c < initialColLen:
				// If we are in the original matrix: do nothing
			case r < initialRowLen && c > initialColLen:
				// If outside, set zero
				this.DegreeMatrix.Set(r, c, float64(0))
			case r > initialRowLen && c < initialColLen:
				// If outside, set zero
				this.DegreeMatrix.Set(r, c, float64(0))
			case r >= initialRowLen && c >= initialColLen:
				// Add the new matrix
				this.DegreeMatrix.Set(r, c, taskStructure.DegreeMatrix.At(r-initialRowLen, c-initialColLen))
			}
		}
	}
	actualSize := len(this.Tasks)
	for i, task := range taskStructure.Tasks {
		task.Id = actualSize + i
		this.Tasks[actualSize+i] = task
	}
	return this
}

func (this *TaskGraphStructure) getTaskFromName(name string) []int {
	indexA := make([]int,1)
	indexA[0] = -1
	for _ , task := range this.Tasks {
		if task.Name == name {
		    if indexA[0] == -1 {
			indexA = append(indexA[1:],task.Id)
		    } else {
			indexA = append(indexA,task.Id)
		    }
		}
	}
	return indexA
}

func colSum(matrix *mat64.Dense, colId int) float64 {
	row, _ := matrix.Dims()
	sum := float64(0)
	for r := 0; r < row; r++ {
		sum += matrix.At(r, colId)
	}
	return sum
}

func rowSum(matrix *mat64.Dense, rowId int) float64 {
	_, col := matrix.Dims()
	sum := float64(0)
	for c := 0; c < col; c++ {
		sum += matrix.At(rowId, c)
	}
	return sum
}

// the aim of this function is to find if a task has a subdefinition (aka an origin) and change it
// Example:
// imagine the graphs
// digraph bla {
//    a -> b;
//    b -> c;
// }
// digraph b {
//    alpha -> gamma;
// }
// then alpha and beta will have "b" as Origin.
// therefore we should add a link in the AdjacencyMatix and in the DegreeMatrix
func (this *TaskGraphStructure) Relink() *TaskGraphStructure {
	// IN this array we store the row,col on which we set 1
	backup := make(map[string][]int, 0)
	_, col := this.AdjacencyMatrix.Dims()
	for _, task := range this.Tasks {
		if colSum(this.AdjacencyMatrix, task.Id) == 0 {
			id := this.getTaskFromName(task.Origin)
			// TODO There should be only one task, otherwise display an error
			if id[0] != -1 {
				// Task is a meta task
				this.Tasks[id[0]].Module = "meta"
				this.AdjacencyMatrix.Set(id[0], task.Id, float64(1))
				backup[task.Origin] = append(backup[task.Origin], id[0], task.Id)
			}
		}
		if rowSum(this.AdjacencyMatrix, task.Id) == 0 {
			id := this.getTaskFromName(task.Origin)
			// TODO There should be only one task, otherwise display an error
			if id[0] != -1 {
				for c := 0; c < col; c++ {
					add := true
					for counter := 0; counter < len(backup[task.Origin])-1; counter += 2 {
						if backup[task.Origin][counter] == id[0] && backup[task.Origin][counter+1] == c {
							add = false
						}
					}
					if add == true && this.Tasks[c].Origin != task.Origin {
						this.AdjacencyMatrix.Set(task.Id, c, this.AdjacencyMatrix.At(task.Id, c)+this.AdjacencyMatrix.At(id[0], c))
					}
				}
			}
		}
	}
	//TODO: complete the degreematrix
	return this
}

// Duplicate the task "id"
// Returns the id of the new task and the whole structure
func (this *TaskGraphStructure) DuplicateTask(name string) []int {
	newIds := make([]int,1)
	newIds[0] = -1
	Ids := this.getTaskFromName(name)
	for _, id := range Ids {
	    if id != -1 {
		newId, _ := this.AdjacencyMatrix.Dims()
		if newIds[0] == -1 {
		    newIds = append(newIds[1:],newId)
		} else {
		    newIds = append(newIds,newId)
		}
		newTask := NewTask()
		newTask.Id = newId
		newTask.Name = this.Tasks[id].Name
		newTask.Origin = this.Tasks[id].Origin
		newTask.Module = this.Tasks[id].Module
		newTask.Node = this.Tasks[id].Node
		newTask.Args = this.Tasks[id].Args
		newTask.Status = this.Tasks[id].Status
		this.Tasks[newId] = newTask
		this.AdjacencyMatrix = mat64.DenseCopyOf(this.AdjacencyMatrix.Grow(1, 1))
		this.DegreeMatrix = mat64.DenseCopyOf(this.DegreeMatrix.Grow(1, 1))
		for r := 0; r < newId; r++ {
		    this.AdjacencyMatrix.Set(r, newId, this.AdjacencyMatrix.At(r, id))
		    this.DegreeMatrix.Set(r, newId, this.DegreeMatrix.At(r, id))
		}
		// Copy the col 'id' to col 'newId'
		for c := 0; c < newId; c++ {
		    this.AdjacencyMatrix.Set(newId, c, this.AdjacencyMatrix.At(id, c))
		    this.DegreeMatrix.Set(newId, c, this.DegreeMatrix.At(id, c))
		}
	    }
	}
	return newIds
}

// This function print the dot file associated with the graph
func (this *TaskGraphStructure) PrintDot(w io.Writer) {
	fmt.Fprintln(w, "digraph G {")
	// Writing node definition
	for _, task := range this.Tasks {
		fmt.Fprintf(w, "\t\"%v\" [\n", task.Id)
		fmt.Fprintf(w, "\t\tid = \"%v\"\n", task.Id)
		if task.Module == "meta" {
			fmt.Fprintln(w, "\t\tshape=diamond")
			fmt.Fprintf(w, "\t\tlabel=\"%v\"", task.Name)
		} else {
			fmt.Fprintf(w, "\t\tlabel = \"<name>%v|<node>%v|<module>%v\"\n", task.Name, task.Node, task.Module)
			fmt.Fprintf(w, "\t\tshape = \"record\"\n")
		}
		fmt.Fprintf(w, "\t];\n")
	}
	row, col := this.AdjacencyMatrix.Dims()
	for r := 0; r < row; r++ {
		for c := 0; c < col; c++ {
			if this.AdjacencyMatrix.At(r, c) == 1 {
				fmt.Fprintf(w, "\t%v -> %v\n", this.Tasks[r].Id, this.Tasks[c].Id)
			}
		}
	}
	fmt.Fprintln(w, "}")
}

// Return a structure of all the task with the given origin
func (this *TaskGraphStructure) GetSubstructure(origin string) *TaskGraphStructure {
	subTaskStructure := NewTaskGraphStructure()
	index := 0
	tasksToExtract := make(map[int]*Task, 0)
	for _, task := range this.Tasks {
		if task.Origin == origin {
			//fmt.Printf("Adding %v(%v) at index:%v\n", task.Name, task.Id, index)
			tasksToExtract[index] = task
			index += 1
		}
	}
	// Create the matrix of the correct size
	size := len(tasksToExtract)
	if size > 0 {
		subTaskStructure.AdjacencyMatrix = mat64.NewDense(size, size, nil)
		subTaskStructure.DegreeMatrix = mat64.NewDense(size, size, nil)
		for i := 0; i < size; i++ {
			task := tasksToExtract[i]
			//fmt.Printf("Task with ID:%v and name:%v will have id:%v\n", task.Id, task.Name, i)
			// Construct the AdjacencyMatrix line by line
			for col := 0; col < size; col++ {
				task2 := tasksToExtract[col]
				//fmt.Printf("Setting %v,%v with value from %v,%v\n", i, col, task.Id, task2.Id)
				subTaskStructure.AdjacencyMatrix.Set(i, col, this.AdjacencyMatrix.At(task.Id, task2.Id))
			}
			subTaskStructure.DegreeMatrix.Set(i, i, this.DegreeMatrix.At(task.Id, task.Id))
			subTaskStructure.Tasks[i] = NewTask()
			subTaskStructure.Tasks[i].Name = task.Name
			subTaskStructure.Tasks[i].Module = task.Module
			subTaskStructure.Tasks[i].Args = task.Args
			subTaskStructure.Tasks[i].Origin = task.Origin
			subTaskStructure.Tasks[i].Id = i
		}
		//subTaskStructure.PrintAdjacencyMatrix()
		return subTaskStructure
	} else {
		return nil
	}
}

// Returns a tasks array of all tasks with the same origin
func getTasksWithOrigin(origin string) []*Tasks {
    return nil
}

// Returns an extract of taskStructure containing only the tasks listed as argument.
// All other tasks are nil, and non relative elements of the matrix are zeroed
func getSubStructure(taskList []*Tasks, taskStructure *TaskStructure) TaskStructure {
    return nil
}

// Duplicate a taskstructure
func duplicateTaskStructure(taskstructure *TaskStructure) *TaskStructure {

}

<|endoftext|>


<commit_before>package terra

import (
	"github.com/arukim/terrarium/helpers"
	"log"
	"time"
)

type TurnSummary struct {
	Turn int
}

type PlayerTurn struct {
}

type PlayerInfo struct {
	Name          string
	TurnSummaryCh chan TurnSummary
	PlayerTurnCh  chan PlayerTurn
	Score         int
}

type Game struct {
	// settings
	maxPlayers  int
	maxTurns    int
	turnTimeout time.Duration
	// current info
	players      []PlayerInfo
	playersCount int
	turn         int
}

func NewGame(maxPlayers int, maxTurns int, turnTimeout time.Duration) *Game {
	g := new(Game)
	g.maxPlayers = maxPlayers
	g.maxTurns = maxTurns
	g.turnTimeout = turnTimeout
	return g
}

func (g *Game) Start() chan PlayerInfo {
	connectQueue := make(chan PlayerInfo)
	go func() {
		log.Printf("Waiting for players\n")
		g.players = make([]PlayerInfo, g.maxPlayers, g.maxPlayers)
		g.playersCount = 0
		for g.playersCount < g.maxPlayers {
			player := <-connectQueue
			log.Printf("Player %s connected\n", player.Name)
			g.players[g.playersCount] = player
			g.playersCount++
		}

		log.Printf("Starting the game\n")
		go func() {
			for g.turn < g.maxTurns {
				g.Turn()
			}
			g.FindWinner()
		}()
	}()
	return connectQueue
}

func (g *Game) FindWinner() {
	maxScore := 0
	for _, player := range g.players {
		if player.Score > maxScore {
			maxScore = player.Score
		}
	}

	for _, player := range g.players {
		if player.Score == maxScore {
			log.Printf("%s is winner with %v score", player.Name, player.Score)
		}
	}
}

func (g *Game) Turn() {
	log.Printf("Turn %d\n", g.turn)
	for i, _ := range g.players {
		player := &g.players[i]

		// check for old turns
		select {
		case <-player.PlayerTurnCh:
		default:
		}

		// start timeout, send turn summary
		var timeout = helpers.NewTimeout(g.turnTimeout)
		player.TurnSummaryCh <- TurnSummary{Turn: g.turn}

		// wait for player answer
		select {
		case <-player.PlayerTurnCh:
			log.Printf("turn was made")
			player.Score++
		case <-timeout.Alarm:
			log.Printf("turn timeout")
		}
	}
	g.turn++
}
<commit_msg>added food generation<commit_after>package terra

import (
	"github.com/arukim/terrarium/helpers"
	"log"
	"math/rand"
	"time"
)

type TurnSummary struct {
	Turn int
}

type PlayerTurn struct {
}

type PlayerInfo struct {
	Name          string
	TurnSummaryCh chan TurnSummary
	PlayerTurnCh  chan PlayerTurn
	Score         int
}

type Point struct {
	X int
	Y int
}

type Game struct {
	// settings
	maxPlayers    int
	maxTurns      int
	mapWidth      int
	mapHeight     int
	foodSpawnRate int
	turnTimeout   time.Duration
	// current info
	players      []PlayerInfo
	playersCount int
	turn         int
	food         map[Point]int
}

func NewGame(maxPlayers int, maxTurns int, turnTimeout time.Duration) *Game {
	g := new(Game)
	g.maxPlayers = maxPlayers
	g.maxTurns = maxTurns
	g.turnTimeout = turnTimeout
	g.mapWidth = 100
	g.mapHeight = 100
	g.foodSpawnRate = 20

	g.food = make(map[Point]int)
	return g
}

func (g *Game) Start() chan PlayerInfo {
	connectQueue := make(chan PlayerInfo)
	go func() {
		log.Printf("Waiting for players\n")
		g.players = make([]PlayerInfo, g.maxPlayers, g.maxPlayers)
		g.playersCount = 0
		for g.playersCount < g.maxPlayers {
			player := <-connectQueue
			log.Printf("Player %s connected\n", player.Name)
			g.players[g.playersCount] = player
			g.playersCount++
		}

		log.Printf("Starting the game\n")
		go func() {
			for g.turn < g.maxTurns {
				g.Turn()
			}
			g.PrintFoodMap()
			g.FindWinner()
		}()
	}()
	return connectQueue
}

func (g *Game) FindWinner() {
	maxScore := 0
	for _, player := range g.players {
		if player.Score > maxScore {
			maxScore = player.Score
		}
	}

	for _, player := range g.players {
		if player.Score == maxScore {
			log.Printf("%s is winner with %v score", player.Name, player.Score)
		}
	}
}

func (g *Game) SpawnFood() {
	for i := 0; i < g.foodSpawnRate; i++ {
		var point = Point{X: rand.Intn(g.mapWidth),
			Y: rand.Intn(g.mapHeight)}
		var currValue = g.food[point]
		currValue++
		g.food[point] = currValue
	}
}

func (g *Game) PrintFoodMap() {
	for key, value := range g.food {
		log.Printf("%v - %v", value, key)
	}
}

func (g *Game) Turn() {
	log.Printf("Turn %d\n", g.turn)
	for i, _ := range g.players {
		g.SpawnFood()

		player := &g.players[i]

		// check for old turns
		select {
		case <-player.PlayerTurnCh:
		default:
		}

		// start timeout, send turn summary
		var timeout = helpers.NewTimeout(g.turnTimeout)
		player.TurnSummaryCh <- TurnSummary{Turn: g.turn}

		// wait for player answer
		select {
		case <-player.PlayerTurnCh:
			log.Printf("turn was made")
			player.Score++
		case <-timeout.Alarm:
			log.Printf("turn timeout")
		}
	}
	g.turn++
}
<|endoftext|>


<commit_before>package netlink

import (
	"fmt"
	"net"
	"strings"
)

// Addr represents an IP address from netlink. Netlink ip addresses
// include a mask, so it stores the address as a net.IPNet.
type Addr struct {
	*net.IPNet
	Label string
}

// String returns $ip/$netmask $label
func (a Addr) String() string {
	return fmt.Sprintf("%s %s", a.IPNet, a.Label)
}

// ParseAddr parses the string representation of an address in the
// form $ip/$netmask $label. The label portion is optional
func ParseAddr(s string) (*Addr, error) {
	label := ""
	parts := strings.Split(s, " ")
	if len(parts) > 1 {
		s = parts[0]
		label = parts[1]
	}
	m, err := ParseIPNet(s)
	if err != nil {
		return nil, err
	}
	return &Addr{IPNet: m, Label: label}, nil
}

// Equal returns true if both Addrs have the same net.IPNet value.
func (a Addr) Equal(x Addr) bool {
	sizea, _ := a.Mask.Size()
	sizeb, _ := x.Mask.Size()
	// ignore label for comparison
	return a.IP.Equal(x.IP) && sizea == sizeb
}
<commit_msg>Trim whitespace from Addr.String()<commit_after>package netlink

import (
	"fmt"
	"net"
	"strings"
)

// Addr represents an IP address from netlink. Netlink ip addresses
// include a mask, so it stores the address as a net.IPNet.
type Addr struct {
	*net.IPNet
	Label string
}

// String returns $ip/$netmask $label
func (a Addr) String() string {
	return strings.TrimSpace(fmt.Sprintf("%s %s", a.IPNet, a.Label))
}

// ParseAddr parses the string representation of an address in the
// form $ip/$netmask $label. The label portion is optional
func ParseAddr(s string) (*Addr, error) {
	label := ""
	parts := strings.Split(s, " ")
	if len(parts) > 1 {
		s = parts[0]
		label = parts[1]
	}
	m, err := ParseIPNet(s)
	if err != nil {
		return nil, err
	}
	return &Addr{IPNet: m, Label: label}, nil
}

// Equal returns true if both Addrs have the same net.IPNet value.
func (a Addr) Equal(x Addr) bool {
	sizea, _ := a.Mask.Size()
	sizeb, _ := x.Mask.Size()
	// ignore label for comparison
	return a.IP.Equal(x.IP) && sizea == sizeb
}
<|endoftext|>


<commit_before>// +build darwin,linux
// run

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

// Test that NaNs in maps don't go quadratic.

package main

import (
	"fmt"
	"math"
	"time"
	"syscall"
)

func main() {

	// Test that NaNs in maps don't go quadratic.
	t := func(n int) time.Duration {
		var u0 syscall.Rusage
		if err := syscall.Getrusage(0,  &u0); err != nil {
			panic(err)
		}
		m := map[float64]int{}
		nan := math.NaN()
		for i := 0; i < n; i++ {
			m[nan] = 1
		}
		if len(m) != n {
			panic("wrong size map after nan insertion")
		}
		var u1 syscall.Rusage
		if err := syscall.Getrusage(0,  &u1); err != nil {
			panic(err)
		}
		return time.Duration(u1.Utime.Nano() - u0.Utime.Nano())
	}

	// Depending on the machine and OS, this test might be too fast
	// to measure with accurate enough granularity. On failure,
	// make it run longer, hoping that the timing granularity
	// is eventually sufficient.

	n := 30000 // ~8ms user time on a Mid 2011 MacBook Air (1.8 GHz Core i7)
	fails := 0
	for {
		t1 := t(n)
		t2 := t(2 * n)
		// should be 2x (linear); allow up to 3x
		if t2 < 3*t1 {
			return
		}
		fails++
		if fails == 6 {
			panic(fmt.Sprintf("too slow: %d inserts: %v; %d inserts: %v\n", n, t1, 2*n, t2))
		}
		if fails < 4 {
			n *= 2
		}
	}
}
<commit_msg>test: fix mapnan.go build tag<commit_after>// +build darwin linux
// run

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

// Test that NaNs in maps don't go quadratic.

package main

import (
	"fmt"
	"math"
	"time"
	"syscall"
)

func main() {

	// Test that NaNs in maps don't go quadratic.
	t := func(n int) time.Duration {
		var u0 syscall.Rusage
		if err := syscall.Getrusage(0,  &u0); err != nil {
			panic(err)
		}
		m := map[float64]int{}
		nan := math.NaN()
		for i := 0; i < n; i++ {
			m[nan] = 1
		}
		if len(m) != n {
			panic("wrong size map after nan insertion")
		}
		var u1 syscall.Rusage
		if err := syscall.Getrusage(0,  &u1); err != nil {
			panic(err)
		}
		return time.Duration(u1.Utime.Nano() - u0.Utime.Nano())
	}

	// Depending on the machine and OS, this test might be too fast
	// to measure with accurate enough granularity. On failure,
	// make it run longer, hoping that the timing granularity
	// is eventually sufficient.

	n := 30000 // ~8ms user time on a Mid 2011 MacBook Air (1.8 GHz Core i7)
	fails := 0
	for {
		t1 := t(n)
		t2 := t(2 * n)
		// should be 2x (linear); allow up to 3x
		if t2 < 3*t1 {
			return
		}
		fails++
		if fails == 6 {
			panic(fmt.Sprintf("too slow: %d inserts: %v; %d inserts: %v\n", n, t1, 2*n, t2))
		}
		if fails < 4 {
			n *= 2
		}
	}
}
<|endoftext|>


<commit_before>package spice

import (
	"crypto/rand"
	"crypto/rsa"
	"net"

	"crypto/sha1"
)

type Authenticator interface {
	Next(*AuthContext) (accessGranted bool, computeDestination string, err error)
	Method() AuthMethod
	Init() error
}

//go:generate stringer -type=AuthMethod
type AuthMethod uint8

const (
	AuthMethodSpice AuthMethod = 1
	AuthMethodSASL  AuthMethod = 2
)

var _ Authenticator = &NOOPAuth{}

type NOOPAuth struct{}

func (a *NOOPAuth) Next(ctx *AuthContext) (bool, string, error) {
	ctx.ReadTicket()
	return true, "127.0.0.1:5900", nil
}

func (a *NOOPAuth) Method() AuthMethod {
	return AuthMethodSpice
}

func (a *NOOPAuth) Init() error { return nil }

type AuthContext struct {
	tenant          net.Conn
	ticketCrypted   []byte
	ticketUncrypted []byte

	privateKey *rsa.PrivateKey // needed for Spice auth
	otp        string          // previously authenticated ticket
	address    string          // destination compute node
}

func (a *AuthContext) ReadTicket() []byte {
	if len(a.ticketCrypted) != 0 {
		return a.ticketCrypted
	}
	a.ticketCrypted = make([]byte, 128)
	if _, err := a.tenant.Read(a.ticketCrypted); err != nil {
		return nil
	}
	return a.ticketCrypted
}

func (a *AuthContext) PrivateKey() *rsa.PrivateKey {
	key := a.privateKey
	if key == nil {
		return nil
	}
	return key
}

func (a *AuthContext) Password() string {
	crypted := a.ReadTicket()

	key := a.PrivateKey()
	if key == nil {
		return ""
	}

	rng := rand.Reader
	plaintext, err := rsa.DecryptOAEP(sha1.New(), rng, key, crypted, []byte{})
	if err != nil {
		return ""
	}

	// do we need to remove this last char??
	a.ticketUncrypted = plaintext[:len(plaintext)-1]

	return string(a.ticketUncrypted)
}

func (a *AuthContext) OTP() string {
	return a.otp
}

func (a *AuthContext) SetOTP(otp string) {
	a.otp = otp
}

func (a *AuthContext) Address() string {
	return a.address
}

func (a *AuthContext) SetAddress(address string) {
	a.address = address
}
<commit_msg>auth: trim trailing nul bytes from password<commit_after>package spice

import (
	"crypto/rand"
	"crypto/rsa"
	"net"

	"bytes"
	"crypto/sha1"
)

type Authenticator interface {
	Next(*AuthContext) (accessGranted bool, computeDestination string, err error)
	Method() AuthMethod
	Init() error
}

//go:generate stringer -type=AuthMethod
type AuthMethod uint8

const (
	AuthMethodSpice AuthMethod = 1
	AuthMethodSASL  AuthMethod = 2
)

var _ Authenticator = &NOOPAuth{}

type NOOPAuth struct{}

func (a *NOOPAuth) Next(ctx *AuthContext) (bool, string, error) {
	ctx.ReadTicket()
	return true, "127.0.0.1:5900", nil
}

func (a *NOOPAuth) Method() AuthMethod {
	return AuthMethodSpice
}

func (a *NOOPAuth) Init() error { return nil }

type AuthContext struct {
	tenant          net.Conn
	ticketCrypted   []byte
	ticketUncrypted []byte

	privateKey *rsa.PrivateKey // needed for Spice auth
	otp        string          // previously authenticated ticket
	address    string          // destination compute node
}

func (a *AuthContext) ReadTicket() []byte {
	if a.ticketCrypted != nil {
		return a.ticketCrypted
	}
	a.ticketCrypted = make([]byte, 128)
	if _, err := a.tenant.Read(a.ticketCrypted); err != nil {
		return nil
	}
	return a.ticketCrypted
}

func (a *AuthContext) PrivateKey() *rsa.PrivateKey {
	key := a.privateKey
	if key == nil {
		return nil
	}
	return key
}

func (a *AuthContext) Password() string {
	crypted := a.ReadTicket()

	key := a.PrivateKey()
	if key == nil {
		return ""
	}

	rng := rand.Reader
	plaintext, err := rsa.DecryptOAEP(sha1.New(), rng, key, crypted, []byte{})
	if err != nil {
		return ""
	}

	// trim trailing nul
	a.ticketUncrypted = bytes.Trim(plaintext, "\x00")

	return string(a.ticketUncrypted)
}

func (a *AuthContext) OTP() string {
	return a.otp
}

func (a *AuthContext) SetOTP(otp string) {
	a.otp = otp
}

func (a *AuthContext) Address() string {
	return a.address
}

func (a *AuthContext) SetAddress(address string) {
	a.address = address
}
<|endoftext|>


<commit_before>package otp

import (
	"bytes"
	"crypto/hmac"
	"encoding/base32"
	"encoding/binary"
	"hash"
	"strconv"
	"time"
)

type Hash func() hash.Hash

// Returns the current time interval.
func GetInterval(period int64) int64 {
	return time.Now().Unix() / period
}

/* Returns a one-time password.

- `Secret` is a Base32 encoded HMAC key.
- `iv` is the initialization value for the HMAC.
- `hashFunc` is the hashing function to use in the HMAC. See `HASHES` for list of valid functions.
- `digits` is the length of digits to display in the output code.

Example:
    code, err := GetCode("MFRGGZDFMZTWQ2LK", 1, sha1.New, 6)
*/
func GetCode(secret string, iv int64, hashFunc Hash, digits int) (string, error) {
	key, err := base32.StdEncoding.DecodeString(secret)
	if err != nil {
		return "", err
	}

	msg := bytes.Buffer{}
	_ = binary.Write(&msg, binary.BigEndian, iv)

	mac := hmac.New(hashFunc, key)
	mac.Write(msg.Bytes())
	digest := mac.Sum(nil)

	offset := digest[len(digest)-1] & 0xF
	trunc := digest[offset : offset+4]

	var code int32
	truncBytes := bytes.NewBuffer(trunc)
	_ = binary.Read(truncBytes, binary.BigEndian, &code)

	code = (code & 0x7FFFFFFF) % 1000000
	stringCode := strconv.Itoa(int(code))
	for len(stringCode) < digits {
		stringCode = "0" + stringCode
	}
	return stringCode, nil
}
<commit_msg>docs again<commit_after>package otp

import (
	"bytes"
	"crypto/hmac"
	"encoding/base32"
	"encoding/binary"
	"hash"
	"strconv"
	"time"
)

type Hash func() hash.Hash

// Returns the current time interval.
func GetInterval(period int64) int64 {
	return time.Now().Unix() / period
}

// Returns a one-time password.
// secret is a Base32 encoded HMAC key.
// iv is the initialization value for the HMAC.
// hashFunc is the hashing function to use in the HMAC. See HASHES for list of valid functions.
// digits is the length of digits to display in the output code.
//
// Example:
//      code, err := GetCode("MFRGGZDFMZTWQ2LK", 1, sha1.New, 6)
func GetCode(secret string, iv int64, hashFunc Hash, digits int) (string, error) {
	key, err := base32.StdEncoding.DecodeString(secret)
	if err != nil {
		return "", err
	}

	msg := bytes.Buffer{}
	_ = binary.Write(&msg, binary.BigEndian, iv)

	mac := hmac.New(hashFunc, key)
	mac.Write(msg.Bytes())
	digest := mac.Sum(nil)

	offset := digest[len(digest)-1] & 0xF
	trunc := digest[offset : offset+4]

	var code int32
	truncBytes := bytes.NewBuffer(trunc)
	_ = binary.Read(truncBytes, binary.BigEndian, &code)

	code = (code & 0x7FFFFFFF) % 1000000
	stringCode := strconv.Itoa(int(code))
	for len(stringCode) < digits {
		stringCode = "0" + stringCode
	}
	return stringCode, nil
}
<|endoftext|>