<commit_before>// Package db implements an immutable, consistent, in-memory key/value store.
// DB uses an immutable Left-Leaning Red-Black tree (LLRB) internally.
package db

import (
	"bytes"
	"reflect"
	"sync"
	"sync/atomic"
	"unsafe"

	"github.com/azmodb/llrb"
)

const (
	// errRevisionNotFound is returned when trying to access a revision
	// that has not been created.
	errRevisionNotFound = perror("revision not found")

	// errKeyNotFound is returned when trying to access a key that has
	// not been created.
	errKeyNotFound = perror("key not found")

	// errIncompatibleValue is returned when trying create or delete a
	// value on an imcompatible key.
	errIncompatibleValue = perror("incompatible value")

	// pairDeleted is the error returned by a watcher when the
	// underlying is deleted.
	pairDeleted = perror("key/value pair deleted")

	// notifierCanceled is the error returned when the watcher is
	// canceled.
	notifierCanceled = perror("watcher shut down")

	// errInvertedRange is returned when a inverted range is supplied.
	errInvertedRange = perror("inverted range")
)

type perror string

func (e perror) Error() string { return string(e) }

// DB represents an immutable, consistent, in-memory key/value database.
// All access is performed through a transaction which can be obtained
// through the database.
type DB struct {
	writer sync.Mutex // exclusive writer transaction
	tree   unsafe.Pointer
}

type tree struct {
	root *llrb.Tree
	rev  int64
}

// New returns an immutable, consistent, in-memory key/value database.
func New() *DB { return newDB(nil) }

func newDB(t *tree) *DB {
	if t == nil {
		t = &tree{root: &llrb.Tree{}}
	}
	return &DB{tree: unsafe.Pointer(t)}
}

func (db *DB) store(t *tree) {
	atomic.StorePointer(&db.tree, unsafe.Pointer(t))
}

func (db *DB) load() *tree {
	return (*tree)(atomic.LoadPointer(&db.tree))
}

// Get retrieves the value for a key at revision rev. If rev <= 0 it
// returns the current value for a key. If equal is true the value
// revision must match the supplied rev.
func (db *DB) Get(key []byte, rev int64, equal bool) (interface{}, int64, int64, error) {
	match := newMatcher(key)
	defer match.release()
	tree := db.load()

	if elem := tree.root.Get(match); elem != nil {
		p := elem.(*pair)
		b, found := lookup(p, rev, equal)
		if found {
			return b.data, b.rev, tree.rev, nil
		}
		return nil, 0, tree.rev, errRevisionNotFound
	}
	return nil, 0, tree.rev, errKeyNotFound
}

func lookup(p *pair, rev int64, equal bool) (block, bool) {
	var b block
	if rev > 0 {
		index, found := p.find(rev, equal)
		if !found {
			return b, false
		}
		b = p.at(index)
	} else {
		b = p.last()
	}
	return b, true
}

func rangeFunc(n *Notifier, rev int64, current int64, limit int32) llrb.Visitor {
	return func(elem llrb.Element) bool {
		p := elem.(*pair)
		b, found := lookup(p, rev, false)
		if found {
			return !n.send(p.key, b.data, b.rev, current)
		}
		return false // ignore revision not found error
	}
}

func (db *DB) get(tree *tree, key []byte, rev int64) (*Notifier, int64, error) {
	n := newNotifier(42, nil, 1)
	go func() {
		data, created, current, err := db.Get(key, rev, false)
		if err != nil {
			n.close(err)
		} else {
			n.send(key, data, created, current)
		}
	}()
	return n, tree.rev, nil
}

// Range iterates over values stored in the database in the range at rev
// over the interval [from, to] from left to right. Limit limits the
// number of keys returned. If rev <= 0 Range gets the keys at the
// current revision of the database. From/To combination:
//
//	from == nil && to == nil:
//		the request returns all keys in the database
//	from != nil && to != nil:
//		the request returns the keys in the interval
//	from != nil && to == nil:
//		the request returns the key (like Get)
//
// Range a notifier, the current revision of the database and an error
// if any.
func (db *DB) Range(from, to []byte, rev int64, limit int32) (*Notifier, int64, error) {
	tree := db.load()
	if bytes.Compare(from, to) > 0 {
		return nil, tree.rev, errInvertedRange
	}

	if from != nil && to == nil { // simulate get request with equal == false
		return db.get(tree, from, rev)
	}

	n := newNotifier(42, nil, defaultNotifierCapacity)
	go func() {
		defer n.Cancel() // in any case cancel the infinte event queue

		if from == nil && to == nil { // foreach request
			tree.root.ForEach(rangeFunc(n, rev, tree.rev, limit))
			return
		}

		lo, hi := newMatcher(from), newMatcher(to)
		defer func() {
			lo.release()
			hi.release()
		}()
		tree.root.Range(lo, hi, rangeFunc(n, rev, tree.rev, limit))
	}()

	return n, tree.rev, nil
}

// Rev returns the current revision of the database.
func (db *DB) Rev() int64 {
	tree := db.load()
	return tree.rev
}

// Watch returns a notifier for a key. If the key does not exist it
// returns an error.
func (db *DB) Watch(key []byte) (*Notifier, int64, error) {
	match := newMatcher(key)
	defer match.release()
	tree := db.load()

	if elem := tree.root.Get(match); elem != nil {
		p := elem.(*pair)
		return p.stream.Register(), tree.rev, nil
	}
	return nil, tree.rev, errKeyNotFound
}

// Txn starts a new batch transaction. Only one batch transaction can
// be used at a time. Starting multiple batch transactions will cause
// the calls to block and be serialized until the current transaction
// finishes.
func (db *DB) Txn() *Txn {
	db.writer.Lock()
	tree := db.load()
	return &Txn{txn: tree.root.Txn(), rev: tree.rev, db: db}
}

// Txn represents a batch transaction on the database.
type Txn struct {
	txn *llrb.Txn
	rev int64
	db  *DB
}

// Updater is a function that operates on a key/value pair
type Updater func(data interface{}) interface{}

// Update updates the value for a key. If the key exists and tombstone is
// true then its previous versions will be overwritten. Supplied key
// and value must remain valid for the life of the database.
//
// It the key exists and the value data type differ it returns an error.
func (tx *Txn) Update(key []byte, up Updater, tombstone bool) (int64, error) {
	match := newMatcher(key)
	defer match.release()

	rev := tx.rev + 1
	var p *pair
	if elem := tx.txn.Get(match); elem != nil {
		p = elem.(*pair)
		last := p.last().data
		data := up(last)
		if !typeEqual(last, data) {
			return tx.rev, errIncompatibleValue
		}
		p = p.insert(data, rev, tombstone)
	} else {
		p = newPair(key, up(nil), rev)
	}
	tx.txn.Insert(p)
	tx.rev = rev
	p.stream.Notify(p, rev)

	return tx.rev, nil
}

func noop(data interface{}) Updater {
	return func(_ interface{}) interface{} {
		return data
	}
}

// Put sets the value for a key. If the key exists and tombstone is true
// then its previous versions will be overwritten. Supplied key and
// value must remain valid for the life of the database.
//
// It the key exists and the value data type differ, it returns an error.
func (tx *Txn) Put(key []byte, data interface{}, tombstone bool) (int64, error) {
	return tx.Update(key, noop(data), tombstone)
}

// Delete removes a key/value pair and returns the current revision of the
// database.
func (tx *Txn) Delete(key []byte) int64 {
	match := newMatcher(key)
	defer match.release()

	if elem := tx.txn.Get(match); elem != nil {
		p := elem.(*pair)
		tx.txn.Delete(p)
		tx.rev++
		p.stream.Notify(p, tx.rev)
		p.stream.Cancel()
	}
	return tx.rev
}

// Commit closes the transaction and writes all changes into the
// database.
func (tx *Txn) Commit() {
	if tx.txn == nil { // already aborted or committed
		return
	}

	tree := &tree{root: tx.txn.Commit(), rev: tx.rev}
	tx.db.store(tree)
	tx.txn = nil
	tx.rev = 0
	tx.db.writer.Unlock() // release the writer lock
	tx.db = nil
}

// Rollback closes the transaction and ignores all previous updates.
func (tx *Txn) Rollback() {
	if tx.txn == nil { // already aborted or committed
		return
	}

	tx.txn = nil
	tx.db.writer.Unlock() // release the writer lock
	tx.db = nil
}

func typeEqual(a, b interface{}) bool {
	at, bt := reflect.TypeOf(a), reflect.TypeOf(b)
	ak, bk := at.Kind(), bt.Kind()
	if ak != bk {
		return false
	}
	if ak == reflect.Slice ||
		ak == reflect.Array ||
		ak == reflect.Chan ||
		ak == reflect.Map ||
		ak == reflect.Ptr {
		if at.Elem() != bt.Elem() {
			println("x")
			return false
		}
	}
	return true
}
<commit_msg>update memdb<commit_after>// Package db implements an immutable, consistent, in-memory key/value store.
// DB uses an immutable Left-Leaning Red-Black tree (LLRB) internally.
package db

import (
	"reflect"
	"sync"
	"sync/atomic"
	"unsafe"

	"github.com/azmodb/llrb"
)

const (
	// errRevisionNotFound is returned when trying to access a revision
	// that has not been created.
	errRevisionNotFound = perror("revision not found")

	// errKeyNotFound is returned when trying to access a key that has
	// not been created.
	errKeyNotFound = perror("key not found")

	// errIncompatibleValue is returned when trying create or delete a
	// value on an imcompatible key.
	errIncompatibleValue = perror("incompatible value")

	// pairDeleted is the error returned by a watcher when the
	// underlying is deleted.
	pairDeleted = perror("key/value pair deleted")

	// notifierCanceled is the error returned when the watcher is
	// canceled.
	notifierCanceled = perror("watcher shut down")

	// errInvertedRange is returned when a inverted range is supplied.
	errInvertedRange = perror("inverted range")
)

type perror string

func (e perror) Error() string { return string(e) }

// DB represents an immutable, consistent, in-memory key/value database.
// All access is performed through a transaction which can be obtained
// through the database.
type DB struct {
	writer sync.Mutex // exclusive writer transaction
	tree   unsafe.Pointer
}

type tree struct {
	root *llrb.Tree
	rev  int64
}

// New returns an immutable, consistent, in-memory key/value database.
func New() *DB { return newDB(nil) }

func newDB(t *tree) *DB {
	if t == nil {
		t = &tree{root: &llrb.Tree{}}
	}
	return &DB{tree: unsafe.Pointer(t)}
}

func (db *DB) store(t *tree) {
	atomic.StorePointer(&db.tree, unsafe.Pointer(t))
}

func (db *DB) load() *tree {
	return (*tree)(atomic.LoadPointer(&db.tree))
}

// Get retrieves the value for a key at revision rev. If rev <= 0 it
// returns the current value for a key. If equal is true the value
// revision must match the supplied rev.
func (db *DB) Get(key []byte, rev int64, equal bool) (interface{}, int64, int64, error) {
	match := newMatcher(key)
	defer match.release()
	tree := db.load()

	if elem := tree.root.Get(match); elem != nil {
		p := elem.(*pair)
		b, found := lookup(p, rev, equal)
		if found {
			return b.data, b.rev, tree.rev, nil
		}
		return nil, 0, tree.rev, errRevisionNotFound
	}
	return nil, 0, tree.rev, errKeyNotFound
}

func lookup(p *pair, rev int64, equal bool) (block, bool) {
	var b block
	if rev > 0 {
		index, found := p.find(rev, equal)
		if !found {
			return b, false
		}
		b = p.at(index)
	} else {
		b = p.last()
	}
	return b, true
}

func rangeFunc(n *Notifier, rev int64, current int64, limit int32) llrb.Visitor {
	return func(elem llrb.Element) bool {
		p := elem.(*pair)
		b, found := lookup(p, rev, false)
		if found {
			return !n.send(p.key, b.data, b.rev, current)
		}
		return false // ignore revision not found error
	}
}

func (db *DB) get(tree *tree, key []byte, rev int64) (*Notifier, int64, error) {
	n := newNotifier(42, nil, 1)
	go func() {
		data, created, current, err := db.Get(key, rev, false)
		if err != nil {
			n.close(err)
		} else {
			n.send(key, data, created, current)
		}
	}()
	return n, tree.rev, nil
}

// Range iterates over values stored in the database in the range at rev
// over the interval [from, to] from left to right. Limit limits the
// number of keys returned. If rev <= 0 Range gets the keys at the
// current revision of the database. From/To combination:
//
//	from == nil && to == nil:
//		the request returns all keys in the database
//	from != nil && to != nil:
//		the request returns the keys in the interval
//	from != nil && to == nil:
//		the request returns the key (like Get)
//
// Range a notifier, the current revision of the database and an error
// if any.
func (db *DB) Range(from, to []byte, rev int64, limit int32) (*Notifier, int64, error) {
	tree := db.load()
	if compare(from, to) > 0 {
		return nil, tree.rev, errInvertedRange
	}

	if from != nil && to == nil { // simulate get request with equal == false
		return db.get(tree, from, rev)
	}

	n := newNotifier(42, nil, defaultNotifierCapacity)
	go func() {
		defer n.Cancel() // in any case cancel the infinte event queue

		if from == nil && to == nil { // foreach request
			tree.root.ForEach(rangeFunc(n, rev, tree.rev, limit))
			return
		}

		lo, hi := newMatcher(from), newMatcher(to)
		defer func() {
			lo.release()
			hi.release()
		}()
		tree.root.Range(lo, hi, rangeFunc(n, rev, tree.rev, limit))
	}()

	return n, tree.rev, nil
}

// Rev returns the current revision of the database.
func (db *DB) Rev() int64 {
	tree := db.load()
	return tree.rev
}

// Watch returns a notifier for a key. If the key does not exist it
// returns an error.
func (db *DB) Watch(key []byte) (*Notifier, int64, error) {
	match := newMatcher(key)
	defer match.release()
	tree := db.load()

	if elem := tree.root.Get(match); elem != nil {
		p := elem.(*pair)
		return p.stream.Register(), tree.rev, nil
	}
	return nil, tree.rev, errKeyNotFound
}

// Txn starts a new batch transaction. Only one batch transaction can
// be used at a time. Starting multiple batch transactions will cause
// the calls to block and be serialized until the current transaction
// finishes.
func (db *DB) Txn() *Txn {
	db.writer.Lock()
	tree := db.load()
	return &Txn{txn: tree.root.Txn(), rev: tree.rev, db: db}
}

// Txn represents a batch transaction on the database.
type Txn struct {
	txn *llrb.Txn
	rev int64
	db  *DB
}

// Updater is a function that operates on a key/value pair
type Updater func(data interface{}) interface{}

// Update updates the value for a key. If the key exists and tombstone is
// true then its previous versions will be overwritten. Supplied key
// and value must remain valid for the life of the database.
//
// It the key exists and the value data type differ it returns an error.
func (tx *Txn) Update(key []byte, up Updater, tombstone bool) (int64, error) {
	match := newMatcher(key)
	defer match.release()

	rev := tx.rev + 1
	var p *pair
	if elem := tx.txn.Get(match); elem != nil {
		p = elem.(*pair)
		last := p.last().data
		data := up(last)
		if !typeEqual(last, data) {
			return tx.rev, errIncompatibleValue
		}
		p = p.insert(data, rev, tombstone)
	} else {
		p = newPair(key, up(nil), rev)
	}
	tx.txn.Insert(p)
	tx.rev = rev
	p.stream.Notify(p, rev)

	return tx.rev, nil
}

func noop(data interface{}) Updater {
	return func(_ interface{}) interface{} {
		return data
	}
}

// Put sets the value for a key. If the key exists and tombstone is true
// then its previous versions will be overwritten. Supplied key and
// value must remain valid for the life of the database.
//
// It the key exists and the value data type differ, it returns an error.
func (tx *Txn) Put(key []byte, data interface{}, tombstone bool) (int64, error) {
	return tx.Update(key, noop(data), tombstone)
}

// Delete removes a key/value pair and returns the current revision of the
// database.
func (tx *Txn) Delete(key []byte) int64 {
	match := newMatcher(key)
	defer match.release()

	if elem := tx.txn.Get(match); elem != nil {
		p := elem.(*pair)
		tx.txn.Delete(p)
		tx.rev++
		p.stream.Notify(p, tx.rev)
		p.stream.Cancel()
	}
	return tx.rev
}

// Commit closes the transaction and writes all changes into the
// database.
func (tx *Txn) Commit() {
	if tx.txn == nil { // already aborted or committed
		return
	}

	tree := &tree{root: tx.txn.Commit(), rev: tx.rev}
	tx.db.store(tree)
	tx.txn = nil
	tx.rev = 0
	tx.db.writer.Unlock() // release the writer lock
	tx.db = nil
}

// Rollback closes the transaction and ignores all previous updates.
func (tx *Txn) Rollback() {
	if tx.txn == nil { // already aborted or committed
		return
	}

	tx.txn = nil
	tx.db.writer.Unlock() // release the writer lock
	tx.db = nil
}

func typeEqual(a, b interface{}) bool {
	at, bt := reflect.TypeOf(a), reflect.TypeOf(b)
	ak, bk := at.Kind(), bt.Kind()
	if ak != bk {
		return false
	}
	if ak == reflect.Slice ||
		ak == reflect.Array ||
		ak == reflect.Chan ||
		ak == reflect.Map ||
		ak == reflect.Ptr {
		if at.Elem() != bt.Elem() {
			println("x")
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/bcicen/ctop/config"
	"github.com/bcicen/ctop/container"
	"github.com/bcicen/ctop/widgets"
	"github.com/bcicen/ctop/widgets/menu"
	ui "github.com/gizak/termui"
)

var helpDialog = []menu.Item{
	{"[a] - toggle display of all containers", ""},
	{"[f] - filter displayed containers", ""},
	{"[h] - open this help dialog", ""},
	{"[H] - toggle ctop header", ""},
	{"[s] - select container sort field", ""},
	{"[r] - reverse container sort order", ""},
	{"[m] - Manage container (start, stop and/or remove)", ""},
	{"[l] - View container logs ([t] to toggle timestamp when open)", ""},
	{"[q] - exit ctop", ""},
}

func HelpMenu() {
	ui.Clear()
	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	m := menu.NewMenu()
	m.BorderLabel = "Help"
	m.AddItems(helpDialog...)
	ui.Render(m)
	ui.Handle("/sys/kbd/", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Loop()
}

func FilterMenu() {
	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	i := widgets.NewInput()
	i.BorderLabel = "Filter"
	i.SetY(ui.TermHeight() - i.Height)
	i.Data = config.GetVal("filterStr")
	ui.Render(i)

	// refresh container rows on input
	stream := i.Stream()
	go func() {
		for s := range stream {
			config.Update("filterStr", s)
			RefreshDisplay()
			ui.Render(i)
		}
	}()

	i.InputHandlers()
	ui.Handle("/sys/kbd/<escape>", func(ui.Event) {
		config.Update("filterStr", "")
		ui.StopLoop()
	})
	ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
		config.Update("filterStr", i.Data)
		ui.StopLoop()
	})
	ui.Loop()
}

func SortMenu() {
	ui.Clear()
	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	m := menu.NewMenu()
	m.Selectable = true
	m.SortItems = true
	m.BorderLabel = "Sort Field"

	for _, field := range container.SortFields() {
		m.AddItems(menu.Item{field, ""})
	}

	// set cursor position to current sort field
	m.SetCursor(config.GetVal("sortField"))

	HandleKeys("up", m.Up)
	HandleKeys("down", m.Down)
	HandleKeys("exit", ui.StopLoop)

	ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
		config.Update("sortField", m.SelectedItem().Val)
		ui.StopLoop()
	})

	ui.Render(m)
	ui.Loop()
}

func ContainerMenu() {

	c := cursor.Selected()
	if c == nil {
		return
	}

	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	m := menu.NewMenu()
	m.Selectable = true

	m.BorderLabel = "Menu"
	items := []menu.Item{menu.Item{Val: "single", Label: "single view"}}
	if c.Meta["state"] == "running" {
		items = append(items, menu.Item{Val: "stop", Label: "stop"})
	}
	if c.Meta["state"] == "exited" {
		items = append(items, menu.Item{Val: "start", Label: "start"})
		items = append(items, menu.Item{Val: "remove", Label: "remove"})
	}
	items = append(items, menu.Item{Val: "cancel", Label: "cancel"})

	m.AddItems(items...)
	ui.Render(m)

	HandleKeys("up", m.Up)
	HandleKeys("down", m.Down)
	ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
		switch m.SelectedItem().Val {
		case "single":
			SingleView(c)
			ui.StopLoop()
		case "start":
			c.Start()
			ui.StopLoop()
		case "stop":
			c.Stop()
			ui.StopLoop()
		case "remove":
			c.Remove()
			ui.StopLoop()
		case "cancel":
			ui.StopLoop()
		}
	})
	ui.Handle("/sys/kbd/", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Loop()
}

func LogMenu() {

	c := cursor.Selected()
	if c == nil {
		return
	}

	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	logs, quit := logReader(c)
	m := widgets.NewTextView(logs)
	m.BorderLabel = "Logs"
	ui.Render(m)

	ui.Handle("/sys/wnd/resize", func(e ui.Event) {
		m.Resize()
	})
	ui.Handle("/sys/kbd/t", func(ui.Event) {
		m.Toggle()
	})
	ui.Handle("/sys/kbd/", func(ui.Event) {
		quit <- true
		ui.StopLoop()
	})
	ui.Loop()
}

type toggleLog struct {
	timestamp time.Time
	message   string
}

func (t *toggleLog) Toggle(on bool) string {
	if on {
		return fmt.Sprintf("%s %s", t.timestamp.Format("2006-01-02T15:04:05.999Z07:00"), t.message)
	}
	return t.message
}

func logReader(container *container.Container) (logs chan widgets.ToggleText, quit chan bool) {

	logCollector := container.Logs()
	stream := logCollector.Stream()
	logs = make(chan widgets.ToggleText)
	quit = make(chan bool)

	go func() {
		for {
			select {
			case log := <-stream:
				logs <- &toggleLog{timestamp: log.Timestamp, message: log.Message}
			case <-quit:
				logCollector.Stop()
				close(logs)
				return
			}
		}
	}()
	return
}
<commit_msg>add logs to container menu<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/bcicen/ctop/config"
	"github.com/bcicen/ctop/container"
	"github.com/bcicen/ctop/widgets"
	"github.com/bcicen/ctop/widgets/menu"
	ui "github.com/gizak/termui"
)

var helpDialog = []menu.Item{
	{"<enter> - open container menu", ""},
	{"", ""},
	{"[a] - toggle display of all containers", ""},
	{"[f] - filter displayed containers", ""},
	{"[h] - open this help dialog", ""},
	{"[H] - toggle ctop header", ""},
	{"[s] - select container sort field", ""},
	{"[r] - reverse container sort order", ""},
	{"[o] - open single view", ""},
	{"[l] - view container logs ([t] to toggle timestamp when open)", ""},
	{"[q] - exit ctop", ""},
}

func HelpMenu() {
	ui.Clear()
	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	m := menu.NewMenu()
	m.BorderLabel = "Help"
	m.AddItems(helpDialog...)
	ui.Render(m)
	ui.Handle("/sys/kbd/", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Loop()
}

func FilterMenu() {
	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	i := widgets.NewInput()
	i.BorderLabel = "Filter"
	i.SetY(ui.TermHeight() - i.Height)
	i.Data = config.GetVal("filterStr")
	ui.Render(i)

	// refresh container rows on input
	stream := i.Stream()
	go func() {
		for s := range stream {
			config.Update("filterStr", s)
			RefreshDisplay()
			ui.Render(i)
		}
	}()

	i.InputHandlers()
	ui.Handle("/sys/kbd/<escape>", func(ui.Event) {
		config.Update("filterStr", "")
		ui.StopLoop()
	})
	ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
		config.Update("filterStr", i.Data)
		ui.StopLoop()
	})
	ui.Loop()
}

func SortMenu() {
	ui.Clear()
	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	m := menu.NewMenu()
	m.Selectable = true
	m.SortItems = true
	m.BorderLabel = "Sort Field"

	for _, field := range container.SortFields() {
		m.AddItems(menu.Item{field, ""})
	}

	// set cursor position to current sort field
	m.SetCursor(config.GetVal("sortField"))

	HandleKeys("up", m.Up)
	HandleKeys("down", m.Down)
	HandleKeys("exit", ui.StopLoop)

	ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
		config.Update("sortField", m.SelectedItem().Val)
		ui.StopLoop()
	})

	ui.Render(m)
	ui.Loop()
}

func ContainerMenu() {

	c := cursor.Selected()
	if c == nil {
		return
	}

	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	m := menu.NewMenu()
	m.Selectable = true

	m.BorderLabel = "Menu"
	items := []menu.Item{
		menu.Item{Val: "single", Label: "single view"},
		menu.Item{Val: "logs", Label: "log view"},
	}
	if c.Meta["state"] == "running" {
		items = append(items, menu.Item{Val: "stop", Label: "stop"})
	}
	if c.Meta["state"] == "exited" {
		items = append(items, menu.Item{Val: "start", Label: "start"})
		items = append(items, menu.Item{Val: "remove", Label: "remove"})
	}
	items = append(items, menu.Item{Val: "cancel", Label: "cancel"})

	m.AddItems(items...)
	ui.Render(m)

	HandleKeys("up", m.Up)
	HandleKeys("down", m.Down)
	ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
		switch m.SelectedItem().Val {
		case "single":
			SingleView(c)
			ui.StopLoop()
		case "logs":
			LogMenu()
			ui.StopLoop()
		case "start":
			c.Start()
			ui.StopLoop()
		case "stop":
			c.Stop()
			ui.StopLoop()
		case "remove":
			c.Remove()
			ui.StopLoop()
		case "cancel":
			ui.StopLoop()
		}
	})
	ui.Handle("/sys/kbd/", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Loop()
}

func LogMenu() {

	c := cursor.Selected()
	if c == nil {
		return
	}

	ui.DefaultEvtStream.ResetHandlers()
	defer ui.DefaultEvtStream.ResetHandlers()

	logs, quit := logReader(c)
	m := widgets.NewTextView(logs)
	m.BorderLabel = "Logs"
	ui.Render(m)

	ui.Handle("/sys/wnd/resize", func(e ui.Event) {
		m.Resize()
	})
	ui.Handle("/sys/kbd/t", func(ui.Event) {
		m.Toggle()
	})
	ui.Handle("/sys/kbd/", func(ui.Event) {
		quit <- true
		ui.StopLoop()
	})
	ui.Loop()
}

type toggleLog struct {
	timestamp time.Time
	message   string
}

func (t *toggleLog) Toggle(on bool) string {
	if on {
		return fmt.Sprintf("%s %s", t.timestamp.Format("2006-01-02T15:04:05.999Z07:00"), t.message)
	}
	return t.message
}

func logReader(container *container.Container) (logs chan widgets.ToggleText, quit chan bool) {

	logCollector := container.Logs()
	stream := logCollector.Stream()
	logs = make(chan widgets.ToggleText)
	quit = make(chan bool)

	go func() {
		for {
			select {
			case log := <-stream:
				logs <- &toggleLog{timestamp: log.Timestamp, message: log.Message}
			case <-quit:
				logCollector.Stop()
				close(logs)
				return
			}
		}
	}()
	return
}
<|endoftext|>


<commit_before>package multibar

import (
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/sethgrid/curse"
)

type progressFunc func(progress int)

type BarContainer struct {
	Bars []*ProgressBar
}

type ProgressBar struct {
	Width           int
	Total           int
	LeftEnd         byte
	RightEnd        byte
	Fill            byte
	Head            byte
	Empty           byte
	ShowPercent     bool
	ShowTimeElapsed bool
	StartTime       time.Time
	Line            int
	Prepend         string
	progressChan    chan int
}

func New() (*BarContainer, error) {
	return &BarContainer{}, nil
}

func (b *BarContainer) Listen() {
	cases := make([]reflect.SelectCase, len(b.Bars))
	for i, bar := range b.Bars {
		cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(bar.progressChan)}
	}

	remaining := len(cases)
	for remaining > 0 {
		chosen, value, ok := reflect.Select(cases)
		if !ok {
			// The chosen channel has been closed, so zero out the channel to disable the case
			cases[chosen].Chan = reflect.ValueOf(nil)
			remaining -= 1
			continue
		}

		b.Bars[chosen].Update(int(value.Int()))
	}
	fmt.Println()
}

func (b *BarContainer) MakeBar(total int, prepend string) progressFunc {
	// can swallow err because sensible defaults are returned
	fmt.Println("\n")
	width, _, _ := curse.GetScreenDimensions()
	ch := make(chan int)
	bar := &ProgressBar{
		Width:           (width - len(prepend)) * 3 / 5,
		Total:           total,
		Prepend:         prepend,
		LeftEnd:         '[',
		RightEnd:        ']',
		Fill:            '=',
		Head:            '>',
		Empty:           '-',
		ShowPercent:     true,
		ShowTimeElapsed: true,
		StartTime:       time.Now(),
		progressChan:    ch,
	}

	b.Bars = append(b.Bars, bar)
	bar.Display()
	return func(progress int) { bar.progressChan <- progress }
}

func (p *ProgressBar) AddPrepend(str string) {
	width, _, _ := curse.GetScreenDimensions()
	p.Prepend = str
	p.Width = (width - len(str)) * 3 / 5
}

func (p *ProgressBar) Display() {
	_, line, _ := curse.GetCursorPosition()
	p.Line = line
	p.Update(0)
}

func (p *ProgressBar) Update(progress int) {
	bar := make([]string, p.Width)

	// avoid division by zero errors on non-properly constructed progressbars
	if p.Width == 0 {
		p.Width = 1
	}
	if p.Total == 0 {
		p.Total = 1
	}
	justGotToFirstEmptySpace := true
	for i, _ := range bar {
		if float32(progress)/float32(p.Total) > float32(i)/float32(p.Width) {
			bar[i] = string(p.Fill)
		} else {
			bar[i] = string(p.Empty)
			if justGotToFirstEmptySpace {
				bar[i] = string(p.Head)
				justGotToFirstEmptySpace = false
			}
		}
	}

	percent := ""
	if p.ShowPercent {
		asInt := int(100 * (float32(progress) / float32(p.Total)))
		padding := ""
		if asInt < 10 {
			padding = "  "
		} else if asInt < 99 {
			padding = " "
		}
		percent = padding + strconv.Itoa(asInt) + "% "
	}

	timeElapsed := ""
	if p.ShowTimeElapsed {
		timeElapsed = " " + prettyTime(time.Since(p.StartTime))
	}
	currentRow, currentLine, _ := curse.GetCursorPosition()
	c := &curse.Cursor{}
	c.Move(1, p.Line)
	c.EraseCurrentLine()
	fmt.Printf("\r%s%s%c%s%c%s", p.Prepend, percent, p.LeftEnd, strings.Join(bar, ""), p.RightEnd, timeElapsed)
	c.Move(currentRow, currentLine)
}

func prettyTime(t time.Duration) string {
	re, err := regexp.Compile(`(\d+).(\d+)(\w+)`)
	if err != nil {
		return err.Error()
	}
	parts := re.FindSubmatch([]byte(t.String()))

	return string(parts[1]) + string(parts[3])
}
<commit_msg>as long as we are not at the bottom of the terminal, it is working.<commit_after>package multibar

import (
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/sethgrid/curse"
)

type progressFunc func(progress int)

type BarContainer struct {
	Bars []*ProgressBar
}

type ProgressBar struct {
	Width           int
	Total           int
	LeftEnd         byte
	RightEnd        byte
	Fill            byte
	Head            byte
	Empty           byte
	ShowPercent     bool
	ShowTimeElapsed bool
	StartTime       time.Time
	Line            int
	Prepend         string
	progressChan    chan int
}

func New() (*BarContainer, error) {
	return &BarContainer{}, nil
}

func (b *BarContainer) Listen() {
	cases := make([]reflect.SelectCase, len(b.Bars))
	for i, bar := range b.Bars {
		cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(bar.progressChan)}
	}

	remaining := len(cases)
	for remaining > 0 {
		chosen, value, ok := reflect.Select(cases)
		if !ok {
			// The chosen channel has been closed, so zero out the channel to disable the case
			cases[chosen].Chan = reflect.ValueOf(nil)
			remaining -= 1
			continue
		}

		b.Bars[chosen].Update(int(value.Int()))
	}
	fmt.Println()
}

func (b *BarContainer) MakeBar(total int, prepend string) progressFunc {
	// can swallow err because sensible defaults are returned
	width, _, _ := curse.GetScreenDimensions()
	ch := make(chan int)
	bar := &ProgressBar{
		Width:           (width - len(prepend)) * 3 / 5,
		Total:           total,
		Prepend:         prepend,
		LeftEnd:         '[',
		RightEnd:        ']',
		Fill:            '=',
		Head:            '>',
		Empty:           '-',
		ShowPercent:     true,
		ShowTimeElapsed: true,
		StartTime:       time.Now(),
		progressChan:    ch,
	}

	b.Bars = append(b.Bars, bar)
	_, line, _ := curse.GetCursorPosition()
	bar.Line = line
	bar.Update(0)
	fmt.Println()
	return func(progress int) { bar.progressChan <- progress }
}

func (p *ProgressBar) AddPrepend(str string) {
	width, _, _ := curse.GetScreenDimensions()
	p.Prepend = str
	p.Width = (width - len(str)) * 3 / 5
}

func (p *ProgressBar) Update(progress int) {
	bar := make([]string, p.Width)

	// avoid division by zero errors on non-properly constructed progressbars
	if p.Width == 0 {
		p.Width = 1
	}
	if p.Total == 0 {
		p.Total = 1
	}
	justGotToFirstEmptySpace := true
	for i, _ := range bar {
		if float32(progress)/float32(p.Total) > float32(i)/float32(p.Width) {
			bar[i] = string(p.Fill)
		} else {
			bar[i] = string(p.Empty)
			if justGotToFirstEmptySpace {
				bar[i] = string(p.Head)
				justGotToFirstEmptySpace = false
			}
		}
	}

	percent := ""
	if p.ShowPercent {
		asInt := int(100 * (float32(progress) / float32(p.Total)))
		padding := ""
		if asInt < 10 {
			padding = "  "
		} else if asInt < 99 {
			padding = " "
		}
		percent = padding + strconv.Itoa(asInt) + "% "
	}

	timeElapsed := ""
	if p.ShowTimeElapsed {
		timeElapsed = " " + prettyTime(time.Since(p.StartTime))
	}
	currentRow, currentLine, _ := curse.GetCursorPosition()
	c := &curse.Cursor{}
	c.Move(1, p.Line)
	c.EraseCurrentLine()
	fmt.Printf("\r%s %s%c%s%c%s", p.Prepend, percent, p.LeftEnd, strings.Join(bar, ""), p.RightEnd, timeElapsed)
	c.Move(currentRow, currentLine)
}

func prettyTime(t time.Duration) string {
	re, err := regexp.Compile(`(\d+).(\d+)(\w+)`)
	if err != nil {
		return err.Error()
	}
	parts := re.FindSubmatch([]byte(t.String()))

	return string(parts[1]) + string(parts[3])
}
<|endoftext|>


<commit_before>/******
* B1 Yönetim Sistemleri Yazılım ve Danışmanlık Limited Şirketi
* B1 Digitial
* http://www.b1.com.tr
*
*
*
* Date      : 15/12/2016
* Time      : 18:22
* Developer : ibrahimcobani
*
*******/
package GOTCMBCurrencyHelper

import (
	"net/http"
	"encoding/xml"
	"time"
	"io"
	"bytes"
	"strings"
	"strconv"
	"log"
)

type CurrencyJournal struct {
	Id         string `json:"_id" bson:"_id"`
	Date       time.Time
	JournalNo  string
	Currencies []Currency
}

type Currency struct {
	Code            string
	CrossOrder      int
	Unit            int
	CurrencyNameTR  string
	CurrencyName    string
	ForexBuying     float64
	ForexSelling    float64
	BanknoteBuying  float64
	BanknoteSelling float64
	CrossRateUSD    float64
	CrossRateOther  float64
}

func GetArchive(CurrencyDate time.Time) CurrencyJournal {
	ghostDate := CurrencyDate
	t := new(tarih_Date)
	cj := t.getArchive(CurrencyDate, ghostDate)
	for {
		if (cj.Id == "") {
			CurrencyDate = CurrencyDate.AddDate(0, 0, -1)
			cj = t.getArchive(CurrencyDate, ghostDate)
			if (cj.Id != "") {
				break
			}
		} else {
			break
		}
	}
	return cj
}

type tarih_Date struct {
	XMLName   xml.Name   `xml:"Tarih_Date"`
	Tarih     string     `xml:"Tarih,attr"`
	Date      string     `xml:"Date,attr"`
	Bulten_No string     `xml:"Bulten_No,attr"`
	Currency  []currency `xml:"Currency"`
}

type currency struct {
	Kod             string `xml:"Kod,attr"`
	CrossOrder      string `xml:"CrossOrder,attr"`
	CurrencyCode    string `xml:"CurrencyCode,attr"`
	Unit            string `xml:"Unit"`
	Isim            string `xml:"Isim"`
	CurrencyName    string `xml:"CurrencyName"`
	ForexBuying     string `xml:"ForexBuying"`
	ForexSelling    string `xml:"ForexSelling"`
	BanknoteBuying  string `xml:"BanknoteBuying"`
	BanknoteSelling string `xml:"BanknoteSelling"`
	CrossRateUSD    string `xml:"CrossRateUSD"`
	CrossRateOther  string `xml:"CrossRateOther"`
}

//*********************

type CharsetISO88591er struct {
	r   io.ByteReader
	buf *bytes.Buffer
}

func NewCharsetISO88591(r io.Reader) *CharsetISO88591er {
	buf := bytes.Buffer{}
	return &CharsetISO88591er{r.(io.ByteReader), &buf}
}

func (cs *CharsetISO88591er) Read(p []byte) (n int, err error) {
	for _ = range p {
		if r, err := cs.r.ReadByte(); err != nil {
			break
		} else {
			cs.buf.WriteRune(rune(r))
		}
	}
	return cs.buf.Read(p)
}

func isCharset(charset string, names []string) bool {
	charset = strings.ToLower(charset)
	for _, n := range names {
		if charset == strings.ToLower(n) {
			return true
		}
	}
	return false
}

func IsCharsetISO88591(charset string) bool {
	// http://www.iana.org/assignments/character-sets
	// (last updated 2010-11-04)
	names := []string{
		// Name
		"ISO_8859-1:1987",
		// Alias (preferred MIME name)
		"ISO-8859-1",
		// Aliases
		"iso-ir-100",
		"ISO_8859-1",
		"ISO-8859-9",
		"latin1",
		"l1",
		"IBM819",
		"CP819",
		"csISOLatin1",
	}
	return isCharset(charset, names)
}

func CharsetReader(charset string, input io.Reader) (io.Reader, error) {
	if IsCharsetISO88591(charset) {
		return NewCharsetISO88591(input), nil
	}
	return input, nil
}

//********************

func (c *tarih_Date) getArchive(CurrencyDate time.Time, GhostDate time.Time) CurrencyJournal {
	cj := CurrencyJournal{}
	var resp *http.Response
	var err error
	var url string
	url = "http://www.tcmb.gov.tr/kurlar/" + CurrencyDate.Format("200601") + "/" + CurrencyDate.Format("02012006") + ".xml"
	log.Println(url)
	resp, err = http.Get(url)

	if err != nil {
		log.Println(err)
	} else {
		defer resp.Body.Close()
		if resp.StatusCode != http.StatusNotFound {
			tarih := new(tarih_Date)
			d := xml.NewDecoder(resp.Body)
			d.CharsetReader = CharsetReader
			marshalErr := d.Decode(&tarih)
			if marshalErr != nil {
				log.Printf("error: %v", marshalErr)
			}
			c = &tarih_Date{}
			cj.Id = GhostDate.Format("20060102")
			cj.Date = GhostDate
			cj.JournalNo = tarih.Bulten_No
			cj.Currencies = make([]Currency, len(tarih.Currency))
			for i, curr := range tarih.Currency {
				cj.Currencies[i].Code = curr.CurrencyCode
				cj.Currencies[i].CurrencyName = curr.CurrencyName
				cj.Currencies[i].CurrencyNameTR = curr.Isim
				cj.Currencies[i].BanknoteBuying, err = strconv.ParseFloat(curr.BanknoteBuying, 64)
				cj.Currencies[i].BanknoteSelling, err = strconv.ParseFloat(curr.BanknoteSelling, 64)
				cj.Currencies[i].ForexBuying, err = strconv.ParseFloat(curr.ForexBuying, 64)
				cj.Currencies[i].ForexSelling, err = strconv.ParseFloat(curr.ForexSelling, 64)
				cj.Currencies[i].CrossOrder, err = strconv.Atoi(curr.CrossOrder)
				cj.Currencies[i].CrossRateOther, err = strconv.ParseFloat(curr.CrossRateOther, 64)
				cj.Currencies[i].CrossRateUSD, err = strconv.ParseFloat(curr.CrossRateUSD, 64)
				cj.Currencies[i].Unit, err = strconv.Atoi(curr.Unit)
			}

		} else {
			cj = CurrencyJournal{}
		}

	}
	return cj
}
<commit_msg>Maksimum geriye doğru tarih deneme sayısı 30 gün olarak belirlendi.<commit_after>/******
* B1 Yönetim Sistemleri Yazılım ve Danışmanlık Limited Şirketi
* B1 Digitial
* http://www.b1.com.tr
*
*
*
* Date      : 15/12/2016
* Time      : 18:22
* Developer : ibrahimcobani
*
*******/
package GOTCMBCurrencyHelper

import (
	"net/http"
	"encoding/xml"
	"time"
	"io"
	"bytes"
	"strings"
	"strconv"
	"log"
)

type CurrencyJournal struct {
	Id         string `json:"_id" bson:"_id"`
	Date       time.Time
	JournalNo  string
	Currencies []Currency
}

type Currency struct {
	Code            string
	CrossOrder      int
	Unit            int
	CurrencyNameTR  string
	CurrencyName    string
	ForexBuying     float64
	ForexSelling    float64
	BanknoteBuying  float64
	BanknoteSelling float64
	CrossRateUSD    float64
	CrossRateOther  float64
}

func GetArchive(CurrencyDate time.Time) CurrencyJournal {
	numberOfTrial := 0
	MaxnumberOfTrial := 30
	ghostDate := CurrencyDate
	t := new(tarih_Date)
	cj := t.getArchive(CurrencyDate, ghostDate)
	for {
		numberOfTrial +=1
		if (cj.Id == "") {
			CurrencyDate = CurrencyDate.AddDate(0, 0, -1)
			cj = t.getArchive(CurrencyDate, ghostDate)
			if (cj.Id != "") {
				break
			}
		} else {
			break
		}
		if numberOfTrial > MaxnumberOfTrial {
			break
		}
	}
	return cj
}

type tarih_Date struct {
	XMLName   xml.Name   `xml:"Tarih_Date"`
	Tarih     string     `xml:"Tarih,attr"`
	Date      string     `xml:"Date,attr"`
	Bulten_No string     `xml:"Bulten_No,attr"`
	Currency  []currency `xml:"Currency"`
}

type currency struct {
	Kod             string `xml:"Kod,attr"`
	CrossOrder      string `xml:"CrossOrder,attr"`
	CurrencyCode    string `xml:"CurrencyCode,attr"`
	Unit            string `xml:"Unit"`
	Isim            string `xml:"Isim"`
	CurrencyName    string `xml:"CurrencyName"`
	ForexBuying     string `xml:"ForexBuying"`
	ForexSelling    string `xml:"ForexSelling"`
	BanknoteBuying  string `xml:"BanknoteBuying"`
	BanknoteSelling string `xml:"BanknoteSelling"`
	CrossRateUSD    string `xml:"CrossRateUSD"`
	CrossRateOther  string `xml:"CrossRateOther"`
}

//*********************

type CharsetISO88591er struct {
	r   io.ByteReader
	buf *bytes.Buffer
}

func NewCharsetISO88591(r io.Reader) *CharsetISO88591er {
	buf := bytes.Buffer{}
	return &CharsetISO88591er{r.(io.ByteReader), &buf}
}

func (cs *CharsetISO88591er) Read(p []byte) (n int, err error) {
	for _ = range p {
		if r, err := cs.r.ReadByte(); err != nil {
			break
		} else {
			cs.buf.WriteRune(rune(r))
		}
	}
	return cs.buf.Read(p)
}

func isCharset(charset string, names []string) bool {
	charset = strings.ToLower(charset)
	for _, n := range names {
		if charset == strings.ToLower(n) {
			return true
		}
	}
	return false
}

func IsCharsetISO88591(charset string) bool {
	// http://www.iana.org/assignments/character-sets
	// (last updated 2010-11-04)
	names := []string{
		// Name
		"ISO_8859-1:1987",
		// Alias (preferred MIME name)
		"ISO-8859-1",
		// Aliases
		"iso-ir-100",
		"ISO_8859-1",
		"ISO-8859-9",
		"latin1",
		"l1",
		"IBM819",
		"CP819",
		"csISOLatin1",
	}
	return isCharset(charset, names)
}

func CharsetReader(charset string, input io.Reader) (io.Reader, error) {
	if IsCharsetISO88591(charset) {
		return NewCharsetISO88591(input), nil
	}
	return input, nil
}

//********************

func (c *tarih_Date) getArchive(CurrencyDate time.Time, GhostDate time.Time) CurrencyJournal {
	cj := CurrencyJournal{}
	var resp *http.Response
	var err error
	var url string
	url = "http://www.tcmb.gov.tr/kurlar/" + CurrencyDate.Format("200601") + "/" + CurrencyDate.Format("02012006") + ".xml"
	log.Println(url)
	resp, err = http.Get(url)

	if err != nil {
		log.Println(err)
	} else {
		defer resp.Body.Close()
		if resp.StatusCode != http.StatusNotFound {
			tarih := new(tarih_Date)
			d := xml.NewDecoder(resp.Body)
			d.CharsetReader = CharsetReader
			marshalErr := d.Decode(&tarih)
			if marshalErr != nil {
				log.Printf("error: %v", marshalErr)
			}
			c = &tarih_Date{}
			cj.Id = GhostDate.Format("20060102")
			cj.Date = GhostDate
			cj.JournalNo = tarih.Bulten_No
			cj.Currencies = make([]Currency, len(tarih.Currency))
			for i, curr := range tarih.Currency {
				cj.Currencies[i].Code = curr.CurrencyCode
				cj.Currencies[i].CurrencyName = curr.CurrencyName
				cj.Currencies[i].CurrencyNameTR = curr.Isim
				cj.Currencies[i].BanknoteBuying, err = strconv.ParseFloat(curr.BanknoteBuying, 64)
				cj.Currencies[i].BanknoteSelling, err = strconv.ParseFloat(curr.BanknoteSelling, 64)
				cj.Currencies[i].ForexBuying, err = strconv.ParseFloat(curr.ForexBuying, 64)
				cj.Currencies[i].ForexSelling, err = strconv.ParseFloat(curr.ForexSelling, 64)
				cj.Currencies[i].CrossOrder, err = strconv.Atoi(curr.CrossOrder)
				cj.Currencies[i].CrossRateOther, err = strconv.ParseFloat(curr.CrossRateOther, 64)
				cj.Currencies[i].CrossRateUSD, err = strconv.ParseFloat(curr.CrossRateUSD, 64)
				cj.Currencies[i].Unit, err = strconv.Atoi(curr.Unit)
			}

		} else {
			cj = CurrencyJournal{}
		}

	}
	return cj
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"strings"
)

const (
	path = "./"
)

func usage() {
	log.Printf("Usage of %s:\n", os.Args[0])
	log.Printf("\nnakedret [flags] # runs on package in current directory\n")
	log.Printf("\nnakedret [flags] [packages]\n")
	log.Printf("Flags:\n")
	flag.PrintDefaults()
}

type returnsVisitor struct {
	f         *token.FileSet
	maxLength uint
}

func main() {

	// Remove log timestamp
	log.SetFlags(0)

	maxLength := flag.Uint("l", 5, "maximum number of lines for a naked return function")
	flag.Usage = usage
	flag.Parse()

	if err := checkNakedReturns(flag.Args(), maxLength); err != nil {
		log.Println(err)
	}
}

func checkNakedReturns(args []string, maxLength *uint) error {

	fset := token.NewFileSet()

	files, err := parseInput(args, fset)
	if err != nil {
		return fmt.Errorf("could not parse input %v", err)
	}

	if maxLength == nil {
		return errors.New("max length nil")
	}

	retVis := &returnsVisitor{
		f:         fset,
		maxLength: *maxLength,
	}

	for _, f := range files {
		ast.Walk(retVis, f)
	}

	return nil
}

func parseInput(args []string, fset *token.FileSet) ([]*ast.File, error) {
	var directoryList []string
	var fileMode bool
	files := make([]*ast.File, 0)

	for _, arg := range args {
		if strings.HasSuffix(arg, "/...") {

			trimmedArg := strings.TrimSuffix(arg, "/...")
			if isDir(trimmedArg) {
				err := filepath.Walk(trimmedArg, func(path string, f os.FileInfo, err error) error {
					if f.IsDir() {
						directoryList = append(directoryList, path)
					}
					return nil
				})
				if err != nil {
					return nil, err
				}
			} else {
				return nil, fmt.Errorf("%v is not a valid directory", arg)
			}

		} else if isDir(arg) {
			directoryList = append(directoryList, arg)

		} else {
			if strings.HasSuffix(arg, ".go") {
				fileMode = true
				f, err := parser.ParseFile(fset, arg, nil, 0)
				if err != nil {
					return nil, err
				}
				files = append(files, f)
			} else {
				return nil, fmt.Errorf("invalid file %v specified", arg)
			}

		}
	}

	// if we're not in file mode, then we need to grab each and every package in each directory
	// we can to grab all the files
	if !fileMode {
		for _, fpath := range directoryList {
			pkgs, err := parser.ParseDir(fset, fpath, nil, 0)
			if err != nil {
				return nil, err
			}

			for _, pkg := range pkgs {
				for _, f := range pkg.Files {
					files = append(files, f)
				}
			}
		}
	}

	return files, nil
}

func isDir(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.IsDir()
}

func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor {
	var namedReturns []*ast.Ident

	funcDecl, ok := node.(*ast.FuncDecl)
	if !ok {
		return v
	}
	var functionLineLength int
	// We've found a function
	if funcDecl.Type != nil && funcDecl.Type.Results != nil {
		for _, field := range funcDecl.Type.Results.List {
			for _, ident := range field.Names {
				if ident != nil {
					namedReturns = append(namedReturns, ident)
				}
			}
		}
		file := v.f.File(funcDecl.Pos())
		functionLineLength = file.Position(funcDecl.End()).Line - file.Position(funcDecl.Pos()).Line
	}

	if len(namedReturns) > 0 && funcDecl.Body != nil {
		// Scan the body for usage of the named returns
		for _, stmt := range funcDecl.Body.List {

			switch s := stmt.(type) {
			case *ast.ReturnStmt:
				if len(s.Results) == 0 {
					file := v.f.File(s.Pos())
					if file != nil && uint(functionLineLength) > v.maxLength {
						if funcDecl.Name != nil {
							log.Printf("%v:%v %v naked returns on %v line function \n", file.Name(), file.Position(s.Pos()).Line, funcDecl.Name.Name, functionLineLength)
						}
					}
					continue
				}

			default:
			}
		}
	}

	return v
}
<commit_msg>fix no arg case<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"strings"
)

const (
	path = "./"
)

func usage() {
	log.Printf("Usage of %s:\n", os.Args[0])
	log.Printf("\nnakedret [flags] # runs on package in current directory\n")
	log.Printf("\nnakedret [flags] [packages]\n")
	log.Printf("Flags:\n")
	flag.PrintDefaults()
}

type returnsVisitor struct {
	f         *token.FileSet
	maxLength uint
}

func main() {

	// Remove log timestamp
	log.SetFlags(0)

	maxLength := flag.Uint("l", 5, "maximum number of lines for a naked return function")
	flag.Usage = usage
	flag.Parse()

	if err := checkNakedReturns(flag.Args(), maxLength); err != nil {
		log.Println(err)
	}
}

func checkNakedReturns(args []string, maxLength *uint) error {

	fset := token.NewFileSet()

	files, err := parseInput(args, fset)
	if err != nil {
		return fmt.Errorf("could not parse input %v", err)
	}

	if maxLength == nil {
		return errors.New("max length nil")
	}

	retVis := &returnsVisitor{
		f:         fset,
		maxLength: *maxLength,
	}

	for _, f := range files {
		ast.Walk(retVis, f)
	}

	return nil
}

func parseInput(args []string, fset *token.FileSet) ([]*ast.File, error) {
	var directoryList []string
	var fileMode bool
	files := make([]*ast.File, 0)

	if len(args) == 0 {
		directoryList = append(directoryList, path)
	} else {
		for _, arg := range args {
			if strings.HasSuffix(arg, "/...") {

				trimmedArg := strings.TrimSuffix(arg, "/...")
				if isDir(trimmedArg) {
					err := filepath.Walk(trimmedArg, func(path string, f os.FileInfo, err error) error {
						if f.IsDir() {
							directoryList = append(directoryList, path)
						}
						return nil
					})
					if err != nil {
						return nil, err
					}
				} else {
					return nil, fmt.Errorf("%v is not a valid directory", arg)
				}

			} else if isDir(arg) {
				directoryList = append(directoryList, arg)

			} else {
				if strings.HasSuffix(arg, ".go") {
					fileMode = true
					f, err := parser.ParseFile(fset, arg, nil, 0)
					if err != nil {
						return nil, err
					}
					files = append(files, f)
				} else {
					return nil, fmt.Errorf("invalid file %v specified", arg)
				}

			}
		}
	}

	// if we're not in file mode, then we need to grab each and every package in each directory
	// we can to grab all the files
	if !fileMode {
		for _, fpath := range directoryList {
			pkgs, err := parser.ParseDir(fset, fpath, nil, 0)
			if err != nil {
				return nil, err
			}

			for _, pkg := range pkgs {
				for _, f := range pkg.Files {
					files = append(files, f)
				}
			}
		}
	}

	return files, nil
}

func isDir(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.IsDir()
}

func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor {
	var namedReturns []*ast.Ident

	funcDecl, ok := node.(*ast.FuncDecl)
	if !ok {
		return v
	}
	var functionLineLength int
	// We've found a function
	if funcDecl.Type != nil && funcDecl.Type.Results != nil {
		for _, field := range funcDecl.Type.Results.List {
			for _, ident := range field.Names {
				if ident != nil {
					namedReturns = append(namedReturns, ident)
				}
			}
		}
		file := v.f.File(funcDecl.Pos())
		functionLineLength = file.Position(funcDecl.End()).Line - file.Position(funcDecl.Pos()).Line
	}

	if len(namedReturns) > 0 && funcDecl.Body != nil {
		// Scan the body for usage of the named returns
		for _, stmt := range funcDecl.Body.List {

			switch s := stmt.(type) {
			case *ast.ReturnStmt:
				if len(s.Results) == 0 {
					file := v.f.File(s.Pos())
					if file != nil && uint(functionLineLength) > v.maxLength {
						if funcDecl.Name != nil {
							log.Printf("%v:%v %v naked returns on %v line function \n", file.Name(), file.Position(s.Pos()).Line, funcDecl.Name.Name, functionLineLength)
						}
					}
					continue
				}

			default:
			}
		}
	}

	return v
}
<|endoftext|>


<commit_before>package net

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net"
	"strings"

	"github.com/PuerkitoBio/gred/cmd"
	"github.com/PuerkitoBio/gred/resp"
	"github.com/PuerkitoBio/gred/srv"
)

var (
	pong  = []byte("+PONG\r\n")
	ok    = []byte("+OK\r\n")
	defdb = srv.NewDB(0)
)

type Conn interface {
	io.ReadWriter

	Handle() error
}

// conn represents a network connection to the server.
type conn struct {
	net.Conn
	db srv.DB
}

// NewConn creates a new Conn for the underlying net.Conn network
// connection.
func NewConn(c net.Conn) Conn {
	conn := &conn{
		Conn: c,
		db:   defdb,
	}
	return conn
}

// Handle handles a connection to the server, and processes its requests.
func (c *conn) Handle() error {
	defer c.Close()

	br := bufio.NewReader(c)

	for {
		// Get the request
		ar, err := resp.DecodeRequest(br)
		if err != nil {
			// Network error, return
			if _, ok := err.(net.Error); ok {
				return err
			}
			// Write the error to the client
			err = resp.Encode(c, resp.Error(err.Error()))
			if err != nil {
				// If write failed, return
				return errors.New("db.Conn.Handle: write failed: " + err.Error())
			}
			continue
		}

		// Run the command
		var res interface{}
		var rerr error
		if cd, ok := cmd.Commands[strings.ToLower(ar[0])]; ok {
			args, ints, floats, err := cd.GetArgDef().ParseArgs(ar[0], ar[1:])
			if err != nil {
				rerr = err
			} else {
				switch cd := cd.(type) {
				case cmd.DBCmd:
					res, rerr = cd.ExecWithDB(c.db, args, ints, floats)
				}
			}
		} else {
			rerr = fmt.Errorf("ERR unknown command '%s'", ar[0])
		}
		err = c.writeResponse(res, rerr)
		if err != nil {
			return err
		}
	}
}

// writeResponse writes the response to the network connection.
func (c *conn) writeResponse(res interface{}, err error) error {
	switch err {
	case cmd.ErrNilSuccess:
		// Special-case for success but nil return value
		return resp.Encode(c, nil)

	case cmd.ErrPong:
		// Special-case for pong response
		_, err = c.Write(pong)
		return err

	case nil:
		if res == nil {
			// If the result is nil, send the OK response
			_, err = c.Write(ok)
			return err
		}
		// Otherwise encode the response
		return resp.Encode(c, res)

	default:
		// Return the non-nil error
		return resp.Encode(c, resp.Error(err.Error()))
	}
}
<commit_msg>add todo<commit_after>package net

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net"
	"strings"

	"github.com/PuerkitoBio/gred/cmd"
	"github.com/PuerkitoBio/gred/resp"
	"github.com/PuerkitoBio/gred/srv"
)

var (
	// TODO : Ideally these protocol optimizations should be in resp package
	pong = []byte("+PONG\r\n")
	ok   = []byte("+OK\r\n")

	defdb = srv.NewDB(0)
)

type Conn interface {
	io.ReadWriter

	Handle() error
}

// conn represents a network connection to the server.
type conn struct {
	net.Conn
	db srv.DB
}

// NewConn creates a new Conn for the underlying net.Conn network
// connection.
func NewConn(c net.Conn) Conn {
	conn := &conn{
		Conn: c,
		db:   defdb,
	}
	return conn
}

// Handle handles a connection to the server, and processes its requests.
func (c *conn) Handle() error {
	defer c.Close()

	br := bufio.NewReader(c)

	for {
		// Get the request
		ar, err := resp.DecodeRequest(br)
		if err != nil {
			// Network error, return
			if _, ok := err.(net.Error); ok {
				return err
			}
			// Write the error to the client
			err = resp.Encode(c, resp.Error(err.Error()))
			if err != nil {
				// If write failed, return
				return errors.New("db.Conn.Handle: write failed: " + err.Error())
			}
			continue
		}

		// Run the command
		var res interface{}
		var rerr error
		if cd, ok := cmd.Commands[strings.ToLower(ar[0])]; ok {
			args, ints, floats, err := cd.GetArgDef().ParseArgs(ar[0], ar[1:])
			if err != nil {
				rerr = err
			} else {
				switch cd := cd.(type) {
				case cmd.DBCmd:
					res, rerr = cd.ExecWithDB(c.db, args, ints, floats)
				}
			}
		} else {
			rerr = fmt.Errorf("ERR unknown command '%s'", ar[0])
		}
		err = c.writeResponse(res, rerr)
		if err != nil {
			return err
		}
	}
}

// writeResponse writes the response to the network connection.
func (c *conn) writeResponse(res interface{}, err error) error {
	switch err {
	case cmd.ErrNilSuccess:
		// Special-case for success but nil return value
		return resp.Encode(c, nil)

	case cmd.ErrPong:
		// Special-case for pong response
		_, err = c.Write(pong)
		return err

	case nil:
		if res == nil {
			// If the result is nil, send the OK response
			_, err = c.Write(ok)
			return err
		}
		// Otherwise encode the response
		return resp.Encode(c, res)

	default:
		// Return the non-nil error
		return resp.Encode(c, resp.Error(err.Error()))
	}
}
<|endoftext|>


<commit_before>/*
** Copyright 2014 Edward Walker
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http ://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
** Description: Model describes the properties of the Support Vector Machine after training.
** @author: Ed Walker
 */
package libSvm

import (
	"fmt"
	"math"
	"os"
)

type Model struct {
	param     *Parameter
	l         int
	nrClass   int
	label     []int
	rho       []float64
	nSV       []int
	sV        []int
	svSpace   []snode
	svIndices []int
	svCoef    [][]float64
	probA     []float64
	probB     []float64
}

func NewModel(param *Parameter) *Model {
	return &Model{param: param}
}

func (model Model) NrClass() int {
	return model.nrClass
}

func groupClasses(prob *Problem) (nrClass int, label []int, start []int, count []int, perm []int) {
	var l int = prob.l

	label = make([]int, 0)
	count = make([]int, 0)
	data_label := make([]int, l)

	for i := 0; i < l; i++ { // find unqie labels and put them in the label slice
		this_label := int(prob.y[i])
		var j int
		for j = 0; j < len(label); j++ {
			if this_label == label[j] {
				count[j]++
				break
			}
		}
		if j == len(label) { // this is a new label we just encountered
			label = append(label, this_label)
			count = append(count, 1)
		}
		data_label[i] = j // remember what label index was assigned to SV i
	}

	// Labels are ordered by their first occurrence in the training set.
	// However, for two-class sets with -1/+1 labels and -1 appears first,
	// we swap labels to ensure that internally the binary SVM has positive data corresponding to the +1 instances.
	if len(label) == 2 && label[0] == -1 && label[1] == 1 {
		label[0], label[1] = label[1], label[0] // swap
		count[0], count[1] = count[1], count[0] // swap
		for i := 0; i < l; i++ {
			if data_label[i] == 0 {
				data_label[i] = 1
			} else {
				data_label[i] = 0
			}
		}
	}

	nrClass = len(label) // number of unique labels found
	start = make([]int, nrClass)
	start[0] = 0
	for i := 1; i < nrClass; i++ {
		start[i] = start[i-1] + count[i-1]
	}

	perm = make([]int, l)
	for i := 0; i < l; i++ {
		label_idx := data_label[i]
		next_avail_pos := start[label_idx]
		perm[next_avail_pos] = i // index i will be assigned to this position
		start[label_idx]++       // move to the next available position for this label
	}

	start[0] = 0
	for i := 1; i < nrClass; i++ { // reset the starting position again
		start[i] = start[i-1] + count[i-1]
	}

	return // nrClass, label, start, count, perm
}

func (model *Model) classification(prob *Problem) {

	nrClass, label, start, count, perm := groupClasses(prob) // group SV with the same labels together

	var l int = prob.l
	x := make([]int, l)
	for i := 0; i < l; i++ {
		x[i] = prob.x[perm[i]] // this is the new x slice with the grouped SVs
	}

	weighted_C := make([]float64, nrClass)
	for i := 0; i < nrClass; i++ {
		weighted_C[i] = model.param.C
	}
	for i := 0; i < model.param.NrWeight; i++ { // this is only done if the relative weight of the labels have been set by the user
		var j int = 0
		for j = 0; j < nrClass; j++ {
			if model.param.WeightLabel[i] == label[j] {
				break
			}
		}
		if j == nrClass {
			fmt.Fprintf(os.Stderr, "WARNING: class label %d specified in weight is not found\n", model.param.WeightLabel[i])
		} else {
			weighted_C[j] = weighted_C[j] * model.param.Weight[i] // multiple with user specified weight for label
		}
	}

	nonzero := make([]bool, l)
	for i := 0; i < l; i++ {
		nonzero[i] = false
	}

	totalCompares := nrClass * (nrClass - 1) / 2
	decisions := make([]decision, totalCompares) // slice for appending all our decisions.
	var probA, probB []float64
	if model.param.Probability {
		probA = make([]float64, totalCompares)
		probB = make([]float64, totalCompares)
	}

	var p int = 0
	for i := 0; i < nrClass; i++ {
		for j := i + 1; j < nrClass; j++ {
			var subProb Problem

			si := start[i] // SV starting from x[si] are related to label i
			sj := start[j] // SV starting from x[sj] are related to label j

			ci := count[i] // number of SV from x[si] that are related to label i
			cj := count[j] // number of SV from x[sj] that are related to label j

			subProb.xSpace = prob.xSpace // inherits the space
			subProb.l = ci + cj          // focus only on 2 labels
			subProb.x = make([]int, subProb.l)
			subProb.y = make([]float64, subProb.l)
			for k := 0; k < ci; k++ {
				subProb.x[k] = x[si+k] // starting indices for first label
				subProb.y[k] = 1
			}

			for k := 0; k < cj; k++ {
				subProb.x[ci+k] = x[sj+k] // starting indices for second label
				subProb.y[ci+k] = -1
			}

			if model.param.Probability {
				probA[p], probB[p] = binarySvcProbability(&subProb, model.param, weighted_C[i], weighted_C[j])
			}

			if decision_result, err := train_one(&subProb, model.param, weighted_C[i], weighted_C[j]); err == nil { // no error in training

				decisions[p] = decision_result

				for k := 0; k < ci; k++ {
					if !nonzero[si+k] && math.Abs(decisions[p].alpha[k]) > 0 {
						nonzero[si+k] = true
					}
				}
				for k := 0; k < cj; k++ {
					if !nonzero[sj+k] && math.Abs(decisions[p].alpha[ci+k]) > 0 {
						nonzero[sj+k] = true
					}
				}

			} else {
				fmt.Fprintln(os.Stderr, "WARNING: training failed: ", err)
				return // no point in continuing
			}

			p++
		}
	}

	// Update the model!
	model.nrClass = nrClass
	model.label = make([]int, nrClass)
	for i := 0; i < nrClass; i++ {
		model.label[i] = label[i]
	}

	model.rho = make([]float64, len(decisions))
	for i := 0; i < len(decisions); i++ {
		model.rho[i] = decisions[i].rho
	}

	if model.param.Probability {
		model.probA = probA
		model.probB = probB
	}

	var totalSV int = 0
	nz_count := make([]int, nrClass)
	model.nSV = make([]int, nrClass)
	for i := 0; i < nrClass; i++ {
		var nSV int = 0
		for j := 0; j < count[i]; j++ {
			if nonzero[start[i]+j] {
				nSV++
				totalSV++
			}
		}
		model.nSV[i] = nSV
		nz_count[i] = nSV
	}

	if !model.param.QuietMode {
		fmt.Printf("Total nSV = %d\n", totalSV)
	}

	model.l = totalSV
	model.svSpace = prob.xSpace

	model.sV = make([]int, totalSV)
	model.svIndices = make([]int, totalSV)

	p = 0
	for i := 0; i < l; i++ {
		if nonzero[i] {
			model.sV[p] = x[i]
			model.svIndices[p] = perm[i] + 1
			p++
		}
	}

	nzStart := make([]int, nrClass)
	nzStart[0] = 0
	for i := 1; i < nrClass; i++ {
		nzStart[i] = nzStart[i-1] + nz_count[i-1]
	}

	model.svCoef = make([][]float64, nrClass-1)
	for i := 0; i < nrClass-1; i++ {
		model.svCoef[i] = make([]float64, totalSV)
	}

	p = 0
	for i := 0; i < nrClass; i++ {
		for j := i + 1; j < nrClass; j++ {

			// classifier (i,j): coefficients with
			// i are in svCoef[j-1][nzStart[i]...],
			// j are in svCoef[i][nzStart[j]...]

			si := start[i]
			sj := start[j]

			ci := count[i]
			cj := count[j]

			q := nzStart[i]
			for k := 0; k < ci; k++ {
				if nonzero[si+k] {
					model.svCoef[j-1][q] = decisions[p].alpha[k]
					q++
				}
			}
			q = nzStart[j]
			for k := 0; k < cj; k++ {
				if nonzero[sj+k] {
					model.svCoef[i][q] = decisions[p].alpha[ci+k]
					q++
				}
			}
			p++
		}
	}

}

func (model *Model) regressionOneClass(prob *Problem) {

	model.nrClass = 2

	if model.param.Probability &&
		(model.param.SvmType == EPSILON_SVR || model.param.SvmType == NU_SVR) {
		model.probA = make([]float64, 1)
		model.probA[0] = svrProbability(prob, model.param)
	}

	if decision_result, err := train_one(prob, model.param, 0, 0); err == nil { // no error in training
		model.rho = append(model.rho, decision_result.rho)

		var nSV int = 0
		for i := 0; i < prob.l; i++ {
			if math.Abs(decision_result.alpha[i]) > 0 {
				nSV++
			}
		}

		model.l = nSV
		model.svSpace = prob.xSpace
		model.sV = make([]int, nSV)
		model.svCoef = make([][]float64, 1)
		model.svCoef[0] = make([]float64, nSV)
		model.svIndices = make([]int, nSV)

		var j int = 0
		for i := 0; i < prob.l; i++ {
			if math.Abs(decision_result.alpha[i]) > 0 {
				model.sV[j] = prob.x[i]
				model.svCoef[0][j] = decision_result.alpha[i]
				model.svIndices[j] = i + 1
				j++
			}
		}
	} else {
		fmt.Fprintln(os.Stderr, "WARNING: training failed: ", err)
	}
}

func (model *Model) Train(prob *Problem) error {
	switch model.param.SvmType {
	case C_SVC, NU_SVC:
		model.classification(prob)
	case ONE_CLASS, EPSILON_SVR, NU_SVR:
		model.regressionOneClass(prob)
	}
	return nil
}
<commit_msg>Create model from model file<commit_after>/*
** Copyright 2014 Edward Walker
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http ://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
** Description: Model describes the properties of the Support Vector Machine after training.
** @author: Ed Walker
 */
package libSvm

import (
	"fmt"
	"math"
	"os"
)

type Model struct {
	param     *Parameter
	l         int
	nrClass   int
	label     []int
	rho       []float64
	nSV       []int
	sV        []int
	svSpace   []snode
	svIndices []int
	svCoef    [][]float64
	probA     []float64
	probB     []float64
}

func NewModel(param *Parameter) *Model {
	return &Model{param: param}
}

func NewModelFromFile(file string) *Model {
	param := NewParameter()
	model := NewModel(param)
	model.ReadModel(file)
	return model
}

func (model Model) NrClass() int {
	return model.nrClass
}

func groupClasses(prob *Problem) (nrClass int, label []int, start []int, count []int, perm []int) {
	var l int = prob.l

	label = make([]int, 0)
	count = make([]int, 0)
	data_label := make([]int, l)

	for i := 0; i < l; i++ { // find unqie labels and put them in the label slice
		this_label := int(prob.y[i])
		var j int
		for j = 0; j < len(label); j++ {
			if this_label == label[j] {
				count[j]++
				break
			}
		}
		if j == len(label) { // this is a new label we just encountered
			label = append(label, this_label)
			count = append(count, 1)
		}
		data_label[i] = j // remember what label index was assigned to SV i
	}

	// Labels are ordered by their first occurrence in the training set.
	// However, for two-class sets with -1/+1 labels and -1 appears first,
	// we swap labels to ensure that internally the binary SVM has positive data corresponding to the +1 instances.
	if len(label) == 2 && label[0] == -1 && label[1] == 1 {
		label[0], label[1] = label[1], label[0] // swap
		count[0], count[1] = count[1], count[0] // swap
		for i := 0; i < l; i++ {
			if data_label[i] == 0 {
				data_label[i] = 1
			} else {
				data_label[i] = 0
			}
		}
	}

	nrClass = len(label) // number of unique labels found
	start = make([]int, nrClass)
	start[0] = 0
	for i := 1; i < nrClass; i++ {
		start[i] = start[i-1] + count[i-1]
	}

	perm = make([]int, l)
	for i := 0; i < l; i++ {
		label_idx := data_label[i]
		next_avail_pos := start[label_idx]
		perm[next_avail_pos] = i // index i will be assigned to this position
		start[label_idx]++       // move to the next available position for this label
	}

	start[0] = 0
	for i := 1; i < nrClass; i++ { // reset the starting position again
		start[i] = start[i-1] + count[i-1]
	}

	return // nrClass, label, start, count, perm
}

func (model *Model) classification(prob *Problem) {

	nrClass, label, start, count, perm := groupClasses(prob) // group SV with the same labels together

	var l int = prob.l
	x := make([]int, l)
	for i := 0; i < l; i++ {
		x[i] = prob.x[perm[i]] // this is the new x slice with the grouped SVs
	}

	weighted_C := make([]float64, nrClass)
	for i := 0; i < nrClass; i++ {
		weighted_C[i] = model.param.C
	}
	for i := 0; i < model.param.NrWeight; i++ { // this is only done if the relative weight of the labels have been set by the user
		var j int = 0
		for j = 0; j < nrClass; j++ {
			if model.param.WeightLabel[i] == label[j] {
				break
			}
		}
		if j == nrClass {
			fmt.Fprintf(os.Stderr, "WARNING: class label %d specified in weight is not found\n", model.param.WeightLabel[i])
		} else {
			weighted_C[j] = weighted_C[j] * model.param.Weight[i] // multiple with user specified weight for label
		}
	}

	nonzero := make([]bool, l)
	for i := 0; i < l; i++ {
		nonzero[i] = false
	}

	totalCompares := nrClass * (nrClass - 1) / 2
	decisions := make([]decision, totalCompares) // slice for appending all our decisions.
	var probA, probB []float64
	if model.param.Probability {
		probA = make([]float64, totalCompares)
		probB = make([]float64, totalCompares)
	}

	var p int = 0
	for i := 0; i < nrClass; i++ {
		for j := i + 1; j < nrClass; j++ {
			var subProb Problem

			si := start[i] // SV starting from x[si] are related to label i
			sj := start[j] // SV starting from x[sj] are related to label j

			ci := count[i] // number of SV from x[si] that are related to label i
			cj := count[j] // number of SV from x[sj] that are related to label j

			subProb.xSpace = prob.xSpace // inherits the space
			subProb.l = ci + cj          // focus only on 2 labels
			subProb.x = make([]int, subProb.l)
			subProb.y = make([]float64, subProb.l)
			for k := 0; k < ci; k++ {
				subProb.x[k] = x[si+k] // starting indices for first label
				subProb.y[k] = 1
			}

			for k := 0; k < cj; k++ {
				subProb.x[ci+k] = x[sj+k] // starting indices for second label
				subProb.y[ci+k] = -1
			}

			if model.param.Probability {
				probA[p], probB[p] = binarySvcProbability(&subProb, model.param, weighted_C[i], weighted_C[j])
			}

			if decision_result, err := train_one(&subProb, model.param, weighted_C[i], weighted_C[j]); err == nil { // no error in training

				decisions[p] = decision_result

				for k := 0; k < ci; k++ {
					if !nonzero[si+k] && math.Abs(decisions[p].alpha[k]) > 0 {
						nonzero[si+k] = true
					}
				}
				for k := 0; k < cj; k++ {
					if !nonzero[sj+k] && math.Abs(decisions[p].alpha[ci+k]) > 0 {
						nonzero[sj+k] = true
					}
				}

			} else {
				fmt.Fprintln(os.Stderr, "WARNING: training failed: ", err)
				return // no point in continuing
			}

			p++
		}
	}

	// Update the model!
	model.nrClass = nrClass
	model.label = make([]int, nrClass)
	for i := 0; i < nrClass; i++ {
		model.label[i] = label[i]
	}

	model.rho = make([]float64, len(decisions))
	for i := 0; i < len(decisions); i++ {
		model.rho[i] = decisions[i].rho
	}

	if model.param.Probability {
		model.probA = probA
		model.probB = probB
	}

	var totalSV int = 0
	nz_count := make([]int, nrClass)
	model.nSV = make([]int, nrClass)
	for i := 0; i < nrClass; i++ {
		var nSV int = 0
		for j := 0; j < count[i]; j++ {
			if nonzero[start[i]+j] {
				nSV++
				totalSV++
			}
		}
		model.nSV[i] = nSV
		nz_count[i] = nSV
	}

	if !model.param.QuietMode {
		fmt.Printf("Total nSV = %d\n", totalSV)
	}

	model.l = totalSV
	model.svSpace = prob.xSpace

	model.sV = make([]int, totalSV)
	model.svIndices = make([]int, totalSV)

	p = 0
	for i := 0; i < l; i++ {
		if nonzero[i] {
			model.sV[p] = x[i]
			model.svIndices[p] = perm[i] + 1
			p++
		}
	}

	nzStart := make([]int, nrClass)
	nzStart[0] = 0
	for i := 1; i < nrClass; i++ {
		nzStart[i] = nzStart[i-1] + nz_count[i-1]
	}

	model.svCoef = make([][]float64, nrClass-1)
	for i := 0; i < nrClass-1; i++ {
		model.svCoef[i] = make([]float64, totalSV)
	}

	p = 0
	for i := 0; i < nrClass; i++ {
		for j := i + 1; j < nrClass; j++ {

			// classifier (i,j): coefficients with
			// i are in svCoef[j-1][nzStart[i]...],
			// j are in svCoef[i][nzStart[j]...]

			si := start[i]
			sj := start[j]

			ci := count[i]
			cj := count[j]

			q := nzStart[i]
			for k := 0; k < ci; k++ {
				if nonzero[si+k] {
					model.svCoef[j-1][q] = decisions[p].alpha[k]
					q++
				}
			}
			q = nzStart[j]
			for k := 0; k < cj; k++ {
				if nonzero[sj+k] {
					model.svCoef[i][q] = decisions[p].alpha[ci+k]
					q++
				}
			}
			p++
		}
	}

}

func (model *Model) regressionOneClass(prob *Problem) {

	model.nrClass = 2

	if model.param.Probability &&
		(model.param.SvmType == EPSILON_SVR || model.param.SvmType == NU_SVR) {
		model.probA = make([]float64, 1)
		model.probA[0] = svrProbability(prob, model.param)
	}

	if decision_result, err := train_one(prob, model.param, 0, 0); err == nil { // no error in training
		model.rho = append(model.rho, decision_result.rho)

		var nSV int = 0
		for i := 0; i < prob.l; i++ {
			if math.Abs(decision_result.alpha[i]) > 0 {
				nSV++
			}
		}

		model.l = nSV
		model.svSpace = prob.xSpace
		model.sV = make([]int, nSV)
		model.svCoef = make([][]float64, 1)
		model.svCoef[0] = make([]float64, nSV)
		model.svIndices = make([]int, nSV)

		var j int = 0
		for i := 0; i < prob.l; i++ {
			if math.Abs(decision_result.alpha[i]) > 0 {
				model.sV[j] = prob.x[i]
				model.svCoef[0][j] = decision_result.alpha[i]
				model.svIndices[j] = i + 1
				j++
			}
		}
	} else {
		fmt.Fprintln(os.Stderr, "WARNING: training failed: ", err)
	}
}

func (model *Model) Train(prob *Problem) error {
	switch model.param.SvmType {
	case C_SVC, NU_SVC:
		model.classification(prob)
	case ONE_CLASS, EPSILON_SVR, NU_SVR:
		model.regressionOneClass(prob)
	}
	return nil
}

<|endoftext|>


<commit_before>package nicehash

import (
	"github.com/dghubble/sling"
	"crypto/tls"
	"net/http"
	"net/http/httputil"
	"log"
	"strings"
)

type NicehashClient struct {
	sling      *sling.Sling
	apiid      string
	apikey     string
	httpClient *nicehashHttpClient
}

// server send the api response with text/html content type
// we fix this: change content type to json
type nicehashHttpClient struct {
	client    *http.Client
	debug     bool
	useragent string
}

type Params struct {
	Method   string `url:"method"`
	ApiId    string `url:"id,omitempty"`
	ApiKey   string `url:"key,omitempty"`
	Addr     string `url:"addr,omitempty"`
	Algo     AlgoType `url:"algo"`
	Location Location `url:"location"`
	My       bool `url:"my,omitempty"`

	Order    uint `url:"order,omitempty"`
	Limit    float32 `url:"limit,omitempty"`
	Price    float32 `url:"price,omitempty"`
	Amount   float64 `url:"amount,omitempty"`
}

func (d nicehashHttpClient) Do(req *http.Request) (*http.Response, error) {
	if d.debug {
		d.dumpRequest(req)
	}
	if d.useragent != "" {
		req.Header.Set("User-Agent", d.useragent)
	}
	client := func() (*http.Client) {
		if d.client != nil {
			return d.client
		} else {
			return http.DefaultClient
		}
	}()
	if client.Transport != nil {
		if transport, ok := client.Transport.(*http.Transport); ok {
			if transport.TLSClientConfig != nil {
				transport.TLSClientConfig.InsecureSkipVerify = true;
			} else {
				transport.TLSClientConfig = &tls.Config{
					InsecureSkipVerify: true,
				}
			}
		}
	} else {
		if transport, ok := http.DefaultTransport.(*http.Transport); ok {
			if transport.TLSClientConfig != nil {
				transport.TLSClientConfig.InsecureSkipVerify = true;
			} else {
				transport.TLSClientConfig = &tls.Config{
					InsecureSkipVerify: true,
				}
			}
		}
	}
	resp, err := client.Do(req)
	if d.debug {
		d.dumpResponse(resp)
	}
	if err == nil {
		contenttype := resp.Header.Get("Content-Type");
		if len(contenttype) == 0 || strings.HasPrefix(contenttype, "text/html") {
			resp.Header.Set("Content-Type", "application/json")
		}
	}
	return resp, err
}

func (d nicehashHttpClient) dumpRequest(r *http.Request) {
	if r == nil {
		log.Print("dumpReq ok: <nil>")
		return
	}
	dump, err := httputil.DumpRequest(r, true)
	if err != nil {
		log.Print("dumpReq err:", err)
	} else {
		log.Print("dumpReq ok:", string(dump))
	}
}

func (d nicehashHttpClient) dumpResponse(r *http.Response) {
	if r == nil {
		log.Print("dumpResponse ok: <nil>")
		return
	}
	dump, err := httputil.DumpResponse(r, true)
	if err != nil {
		log.Print("dumpResponse err:", err)
	} else {
		log.Print("dumpResponse ok:", string(dump))
	}
}

func NewNicehashClient(client *http.Client, BaseURL string, ApiId string, ApiKey string, UserAgent string) *NicehashClient {
	if len(BaseURL) == 0 {
		BaseURL = "https://www.nicehash.com/"
	}
	nicehashclient := &nicehashHttpClient{client:client, useragent:UserAgent}
	return &NicehashClient{
		httpClient: nicehashclient,
		sling: sling.New().Doer(nicehashclient).Base(strings.TrimRight(BaseURL, "/") + "/").Path("api"),
		apiid: ApiId,
		apikey: ApiKey,
	}
}

func (client NicehashClient) SetDebug(debug bool) {
	client.httpClient.debug = debug
}
<commit_msg>New api base url<commit_after>package nicehash

import (
	"github.com/dghubble/sling"
	"crypto/tls"
	"net/http"
	"net/http/httputil"
	"log"
	"strings"
)

type NicehashClient struct {
	sling      *sling.Sling
	apiid      string
	apikey     string
	httpClient *nicehashHttpClient
}

// server send the api response with text/html content type
// we fix this: change content type to json
type nicehashHttpClient struct {
	client    *http.Client
	debug     bool
	useragent string
}

type Params struct {
	Method   string `url:"method"`
	ApiId    string `url:"id,omitempty"`
	ApiKey   string `url:"key,omitempty"`
	Addr     string `url:"addr,omitempty"`
	Algo     AlgoType `url:"algo"`
	Location Location `url:"location"`
	My       bool `url:"my,omitempty"`

	Order    uint `url:"order,omitempty"`
	Limit    float32 `url:"limit,omitempty"`
	Price    float32 `url:"price,omitempty"`
	Amount   float64 `url:"amount,omitempty"`
}

func (d nicehashHttpClient) Do(req *http.Request) (*http.Response, error) {
	if d.debug {
		d.dumpRequest(req)
	}
	if d.useragent != "" {
		req.Header.Set("User-Agent", d.useragent)
	}
	client := func() (*http.Client) {
		if d.client != nil {
			return d.client
		} else {
			return http.DefaultClient
		}
	}()
	if client.Transport != nil {
		if transport, ok := client.Transport.(*http.Transport); ok {
			if transport.TLSClientConfig != nil {
				transport.TLSClientConfig.InsecureSkipVerify = true;
			} else {
				transport.TLSClientConfig = &tls.Config{
					InsecureSkipVerify: true,
				}
			}
		}
	} else {
		if transport, ok := http.DefaultTransport.(*http.Transport); ok {
			if transport.TLSClientConfig != nil {
				transport.TLSClientConfig.InsecureSkipVerify = true;
			} else {
				transport.TLSClientConfig = &tls.Config{
					InsecureSkipVerify: true,
				}
			}
		}
	}
	resp, err := client.Do(req)
	if d.debug {
		d.dumpResponse(resp)
	}
	if err == nil {
		contenttype := resp.Header.Get("Content-Type");
		if len(contenttype) == 0 || strings.HasPrefix(contenttype, "text/html") {
			resp.Header.Set("Content-Type", "application/json")
		}
	}
	return resp, err
}

func (d nicehashHttpClient) dumpRequest(r *http.Request) {
	if r == nil {
		log.Print("dumpReq ok: <nil>")
		return
	}
	dump, err := httputil.DumpRequest(r, true)
	if err != nil {
		log.Print("dumpReq err:", err)
	} else {
		log.Print("dumpReq ok:", string(dump))
	}
}

func (d nicehashHttpClient) dumpResponse(r *http.Response) {
	if r == nil {
		log.Print("dumpResponse ok: <nil>")
		return
	}
	dump, err := httputil.DumpResponse(r, true)
	if err != nil {
		log.Print("dumpResponse err:", err)
	} else {
		log.Print("dumpResponse ok:", string(dump))
	}
}

func NewNicehashClient(client *http.Client, BaseURL string, ApiId string, ApiKey string, UserAgent string) *NicehashClient {
	if len(BaseURL) == 0 {
		BaseURL = "https://api.nicehash.com/"
	}
	nicehashclient := &nicehashHttpClient{client:client, useragent:UserAgent}
	return &NicehashClient{
		httpClient: nicehashclient,
		sling: sling.New().Doer(nicehashclient).Base(strings.TrimRight(BaseURL, "/") + "/").Path("api"),
		apiid: ApiId,
		apikey: ApiKey,
	}
}

func (client NicehashClient) SetDebug(debug bool) {
	client.httpClient.debug = debug
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/godbus/dbus/v5"
	"github.com/godbus/dbus/v5/introspect"
	"github.com/godbus/dbus/v5/prop"
)

type foo string

func (f foo) Foo() (string, *dbus.Error) {
	fmt.Println(f)
	return string(f), nil
}

type Foo struct {
	Id    int
	Value string
}

func main() {
	conn, err := dbus.ConnectSessionBus()
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	reply, err := conn.RequestName("com.github.guelfey.Demo",
		dbus.NameFlagDoNotQueue)
	if err != nil {
		panic(err)
	}
	if reply != dbus.RequestNameReplyPrimaryOwner {
		fmt.Fprintln(os.Stderr, "name already taken")
		os.Exit(1)
	}
	propsSpec := map[string]map[string]*prop.Prop{
		"com.github.guelfey.Demo": {
			"SomeInt": {
				int32(0),
				true,
				prop.EmitTrue,
				func(c *prop.Change) *dbus.Error {
					fmt.Println(c.Name, "changed to", c.Value)
					return nil
				},
			},
			"FooStruct": {
				Foo{Id: 1, Value: "First"},
				true,
				prop.EmitTrue,
				func(c *prop.Change) *dbus.Error {
					var foo Foo
					dbus.Store([]interface{}{c.Value}, &foo)
					fmt.Println(c.Name, "changed to", foo)
					return nil
				},
			},
		},
	}
	f := foo("Bar")
	conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
	props := prop.New(conn, "/com/github/guelfey/Demo", propsSpec)
	n := &introspect.Node{
		Name: "/com/github/guelfey/Demo",
		Interfaces: []introspect.Interface{
			introspect.IntrospectData,
			prop.IntrospectData,
			{
				Name:       "com.github.guelfey.Demo",
				Methods:    introspect.Methods(f),
				Properties: props.Introspection("com.github.guelfey.Demo"),
			},
		},
	}
	conn.Export(introspect.NewIntrospectable(n), "/com/github/guelfey/Demo",
		"org.freedesktop.DBus.Introspectable")
	fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")

	c := make(chan *dbus.Signal)
	conn.Signal(c)
	for _ = range c {
	}
}
<commit_msg>example: prop.go handle unhandle error<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/godbus/dbus/v5"
	"github.com/godbus/dbus/v5/introspect"
	"github.com/godbus/dbus/v5/prop"
)

type foo string

func (f foo) Foo() (string, *dbus.Error) {
	fmt.Println(f)
	return string(f), nil
}

type Foo struct {
	Id    int
	Value string
}

func main() {
	conn, err := dbus.ConnectSessionBus()
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	reply, err := conn.RequestName("com.github.guelfey.Demo",
		dbus.NameFlagDoNotQueue)
	if err != nil {
		panic(err)
	}
	if reply != dbus.RequestNameReplyPrimaryOwner {
		_, _ = fmt.Fprintln(os.Stderr, "name already taken")
		os.Exit(1)
	}
	propsSpec := map[string]map[string]*prop.Prop{
		"com.github.guelfey.Demo": {
			"SomeInt": {
				int32(0),
				true,
				prop.EmitTrue,
				func(c *prop.Change) *dbus.Error {
					fmt.Println(c.Name, "changed to", c.Value)
					return nil
				},
			},
			"FooStruct": {
				Foo{Id: 1, Value: "First"},
				true,
				prop.EmitTrue,
				func(c *prop.Change) *dbus.Error {
					var foo Foo
					err := dbus.Store([]interface{}{c.Value}, &foo)
					if err != nil {
						_, _ = fmt.Fprintf(os.Stderr, "dbus.Store foo failed: %v\n", err)
					}
					fmt.Println(c.Name, "changed to", foo)
					return nil
				},
			},
		},
	}
	f := foo("Bar")
	err = conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
	if err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "export f failed: %v\n", err)
		os.Exit(1)
	}
	props, err := prop.Export(conn, "/com/github/guelfey/Demo", propsSpec)
	if err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "export propsSpec failed: %v\n", err)
		os.Exit(1)
	}
	n := &introspect.Node{
		Name: "/com/github/guelfey/Demo",
		Interfaces: []introspect.Interface{
			introspect.IntrospectData,
			prop.IntrospectData,
			{
				Name:       "com.github.guelfey.Demo",
				Methods:    introspect.Methods(f),
				Properties: props.Introspection("com.github.guelfey.Demo"),
			},
		},
	}
	err = conn.Export(introspect.NewIntrospectable(n), "/com/github/guelfey/Demo",
		"org.freedesktop.DBus.Introspectable")
	if err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "export introspect failed: %v\n", err)
		os.Exit(1)
	}
	fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")

	c := make(chan *dbus.Signal)
	conn.Signal(c)
	for range c {
	}
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package dataflowlib translates a Beam pipeline model to the
// Dataflow API job model, for submission to Google Cloud Dataflow.
package dataflowlib

import (
	"context"
	"encoding/json"
	"os"

	"github.com/apache/beam/sdks/go/pkg/beam/core/metrics"
	"github.com/apache/beam/sdks/go/pkg/beam/core/util/protox"
	"github.com/apache/beam/sdks/go/pkg/beam/internal/errors"
	"github.com/apache/beam/sdks/go/pkg/beam/log"
	pipepb "github.com/apache/beam/sdks/go/pkg/beam/model/pipeline_v1"
	"github.com/apache/beam/sdks/go/pkg/beam/runners/universal/runnerlib"
	"github.com/golang/protobuf/proto"
	df "google.golang.org/api/dataflow/v1b3"
)

// Execute submits a pipeline as a Dataflow job.
func Execute(ctx context.Context, raw *pipepb.Pipeline, opts *JobOptions, workerURL, jarURL, modelURL, endpoint string, async bool) (*dataflowPipelineResult, error) {
	// (1) Upload Go binary to GCS.
	presult := &dataflowPipelineResult{}

	bin := opts.Worker
	if bin == "" {
		if self, ok := runnerlib.IsWorkerCompatibleBinary(); ok {
			bin = self
			log.Infof(ctx, "Using running binary as worker binary: '%v'", bin)
		} else {
			// Cross-compile as last resort.

			worker, err := runnerlib.BuildTempWorkerBinary(ctx)
			if err != nil {
				return presult, err
			}
			defer os.Remove(worker)

			bin = worker
		}
	} else {
		log.Infof(ctx, "Using specified worker binary: '%v'", bin)
	}

	log.Infof(ctx, "Staging worker binary: %v", bin)

	if err := StageFile(ctx, opts.Project, workerURL, bin); err != nil {
		return presult, err
	}
	log.Infof(ctx, "Staged worker binary: %v", workerURL)

	if opts.WorkerJar != "" {
		log.Infof(ctx, "Staging Dataflow worker jar: %v", opts.WorkerJar)

		if err := StageFile(ctx, opts.Project, jarURL, opts.WorkerJar); err != nil {
			return presult, err
		}
		log.Infof(ctx, "Staged worker jar: %v", jarURL)
	}

	// (2) Fixup and upload model to GCS

	p, err := Fixup(raw)
	if err != nil {
		return presult, err
	}
	log.Info(ctx, proto.MarshalTextString(p))

	if err := StageModel(ctx, opts.Project, modelURL, protox.MustEncode(p)); err != nil {
		return presult, err
	}
	log.Infof(ctx, "Staged model pipeline: %v", modelURL)

	// (3) Translate to v1b3 and submit

	job, err := Translate(ctx, p, opts, workerURL, jarURL, modelURL)
	if err != nil {
		return presult, err
	}
	PrintJob(ctx, job)

	client, err := NewClient(ctx, endpoint)
	if err != nil {
		return presult, err
	}
	upd, err := Submit(ctx, client, opts.Project, opts.Region, job)
	if err != nil {
		return presult, err
	}
	log.Infof(ctx, "Submitted job: %v", upd.Id)
	if endpoint == "" {
		log.Infof(ctx, "Console: https://console.cloud.google.com/dataflow/jobs/%v?project=%v", upd.Id, opts.Project)
	}
	log.Infof(ctx, "Logs: https://console.cloud.google.com/logs/viewer?project=%v&resource=dataflow_step%%2Fjob_id%%2F%v", opts.Project, upd.Id)

	presult.jobID = upd.Id

	if async {
		return presult, nil
	}

	// (4) Wait for completion.
	err = WaitForCompletion(ctx, client, opts.Project, opts.Region, upd.Id)

	res, presultErr := newDataflowPipelineResult(ctx, client, p, opts.Project, opts.Region, upd.Id)
	if presultErr != nil {
		if err != nil {
			return presult, errors.Wrap(err, presultErr.Error())
		}
		return presult, presultErr
	}
	return res, err
}

// PrintJob logs the Dataflow job.
func PrintJob(ctx context.Context, job *df.Job) {
	str, err := json.MarshalIndent(job, "", "  ")
	if err != nil {
		log.Infof(ctx, "Failed to print job %v: %v", job.Id, err)
	}
	log.Info(ctx, string(str))
}

type dataflowPipelineResult struct {
	jobID   string
	metrics *metrics.Results
}

func newDataflowPipelineResult(ctx context.Context, client *df.Service, p *pipepb.Pipeline, project, region, jobID string) (*dataflowPipelineResult, error) {
	res, err := GetMetrics(ctx, client, project, region, jobID)
	if err != nil {
		return &dataflowPipelineResult{jobID, nil}, errors.Wrap(err, "failed to get metrics")
	}
	return &dataflowPipelineResult{jobID, FromMetricUpdates(res.Metrics, p)}, nil
}

func (pr dataflowPipelineResult) Metrics() metrics.Results {
	return *pr.metrics
}

func (pr dataflowPipelineResult) JobID() string {
	return pr.jobID
}
<commit_msg>[BEAM-12738][GoSDK] Fix Dataflow Job URL<commit_after>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package dataflowlib translates a Beam pipeline model to the
// Dataflow API job model, for submission to Google Cloud Dataflow.
package dataflowlib

import (
	"context"
	"encoding/json"
	"os"

	"github.com/apache/beam/sdks/go/pkg/beam/core/metrics"
	"github.com/apache/beam/sdks/go/pkg/beam/core/util/protox"
	"github.com/apache/beam/sdks/go/pkg/beam/internal/errors"
	"github.com/apache/beam/sdks/go/pkg/beam/log"
	pipepb "github.com/apache/beam/sdks/go/pkg/beam/model/pipeline_v1"
	"github.com/apache/beam/sdks/go/pkg/beam/runners/universal/runnerlib"
	"github.com/golang/protobuf/proto"
	df "google.golang.org/api/dataflow/v1b3"
)

// Execute submits a pipeline as a Dataflow job.
func Execute(ctx context.Context, raw *pipepb.Pipeline, opts *JobOptions, workerURL, jarURL, modelURL, endpoint string, async bool) (*dataflowPipelineResult, error) {
	// (1) Upload Go binary to GCS.
	presult := &dataflowPipelineResult{}

	bin := opts.Worker
	if bin == "" {
		if self, ok := runnerlib.IsWorkerCompatibleBinary(); ok {
			bin = self
			log.Infof(ctx, "Using running binary as worker binary: '%v'", bin)
		} else {
			// Cross-compile as last resort.

			worker, err := runnerlib.BuildTempWorkerBinary(ctx)
			if err != nil {
				return presult, err
			}
			defer os.Remove(worker)

			bin = worker
		}
	} else {
		log.Infof(ctx, "Using specified worker binary: '%v'", bin)
	}

	log.Infof(ctx, "Staging worker binary: %v", bin)

	if err := StageFile(ctx, opts.Project, workerURL, bin); err != nil {
		return presult, err
	}
	log.Infof(ctx, "Staged worker binary: %v", workerURL)

	if opts.WorkerJar != "" {
		log.Infof(ctx, "Staging Dataflow worker jar: %v", opts.WorkerJar)

		if err := StageFile(ctx, opts.Project, jarURL, opts.WorkerJar); err != nil {
			return presult, err
		}
		log.Infof(ctx, "Staged worker jar: %v", jarURL)
	}

	// (2) Fixup and upload model to GCS

	p, err := Fixup(raw)
	if err != nil {
		return presult, err
	}
	log.Info(ctx, proto.MarshalTextString(p))

	if err := StageModel(ctx, opts.Project, modelURL, protox.MustEncode(p)); err != nil {
		return presult, err
	}
	log.Infof(ctx, "Staged model pipeline: %v", modelURL)

	// (3) Translate to v1b3 and submit

	job, err := Translate(ctx, p, opts, workerURL, jarURL, modelURL)
	if err != nil {
		return presult, err
	}
	PrintJob(ctx, job)

	client, err := NewClient(ctx, endpoint)
	if err != nil {
		return presult, err
	}
	upd, err := Submit(ctx, client, opts.Project, opts.Region, job)
	if err != nil {
		return presult, err
	}
	log.Infof(ctx, "Submitted job: %v", upd.Id)
	if endpoint == "" {
		log.Infof(ctx, "Console: https://console.cloud.google.com/dataflow/jobs/%v/%v?project=%v", opts.Region, upd.Id, opts.Project)
	}
	log.Infof(ctx, "Logs: https://console.cloud.google.com/logs/viewer?project=%v&resource=dataflow_step%%2Fjob_id%%2F%v", opts.Project, upd.Id)

	presult.jobID = upd.Id

	if async {
		return presult, nil
	}

	// (4) Wait for completion.
	err = WaitForCompletion(ctx, client, opts.Project, opts.Region, upd.Id)

	res, presultErr := newDataflowPipelineResult(ctx, client, p, opts.Project, opts.Region, upd.Id)
	if presultErr != nil {
		if err != nil {
			return presult, errors.Wrap(err, presultErr.Error())
		}
		return presult, presultErr
	}
	return res, err
}

// PrintJob logs the Dataflow job.
func PrintJob(ctx context.Context, job *df.Job) {
	str, err := json.MarshalIndent(job, "", "  ")
	if err != nil {
		log.Infof(ctx, "Failed to print job %v: %v", job.Id, err)
	}
	log.Info(ctx, string(str))
}

type dataflowPipelineResult struct {
	jobID   string
	metrics *metrics.Results
}

func newDataflowPipelineResult(ctx context.Context, client *df.Service, p *pipepb.Pipeline, project, region, jobID string) (*dataflowPipelineResult, error) {
	res, err := GetMetrics(ctx, client, project, region, jobID)
	if err != nil {
		return &dataflowPipelineResult{jobID, nil}, errors.Wrap(err, "failed to get metrics")
	}
	return &dataflowPipelineResult{jobID, FromMetricUpdates(res.Metrics, p)}, nil
}

func (pr dataflowPipelineResult) Metrics() metrics.Results {
	return *pr.metrics
}

func (pr dataflowPipelineResult) JobID() string {
	return pr.jobID
}
<|endoftext|>