<commit_before>package graphite

import (
	"io"
	"log"
	"net"
	"strings"

	"github.com/influxdb/influxdb"
)

const (
	udpBufferSize = 65536
)

// UDPerver processes Graphite data received via UDP.
type UDPServer struct {
	server SeriesWriter
	parser *Parser

	Database string
	Logger   *log.Logger
}

// NewUDPServer returns a new instance of a UDPServer
func NewUDPServer(p *Parser, s SeriesWriter) *UDPServer {
	u := UDPServer{
		parser: p,
		server: s,
	}
	return &u
}

// SetLogOutput sets writer for all Graphite log output.
func (s *UDPServer) SetLogOutput(w io.Writer) {
	s.Logger = log.New(w, "[graphite] ", log.LstdFlags)
}

// SetDatabase sets database for all Graphite log output.
func (s *UDPServer) SetDatabase(database string) {
	s.Database = database
}

// Protocol returns a string version of the supported protocol.
func (s *UDPServer) Protocol() string {
	return "udp"
}

// ListenAndServer instructs the UDPServer to start processing Graphite data
// on the given interface. iface must be in the form host:port.
func (u *UDPServer) ListenAndServe(iface string) error {
	if iface == "" { // Make sure we have an address
		return ErrBindAddressRequired
	} else if u.Database == "" { // Make sure they have a database
		// If they didn't specify a database, create one and set a default retention policy.
		if !u.server.DatabaseExists(DefaultDatabaseName) {
			u.Logger.Printf("default database %q does not exist.  creating.\n", DefaultDatabaseName)
			if e := u.server.CreateDatabase(DefaultDatabaseName); e != nil {
				return e
			}
			u.Database = DefaultDatabaseName
		}
	}

	addr, err := net.ResolveUDPAddr("udp", iface)
	if err != nil {
		return nil
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		return err
	}

	buf := make([]byte, udpBufferSize)
	go func() {
		for {
			n, _, err := conn.ReadFromUDP(buf)
			if err != nil {
				return
			}
			for _, line := range strings.Split(string(buf[:n]), "\n") {
				point, err := u.parser.Parse(line)
				if err != nil {
					continue
				}

				// Send the data to database
				_, e := u.server.WriteSeries(u.Database, "", []influxdb.Point{point})
				if e != nil {
					u.Logger.Printf("failed to write data point: %s\n", e)
				}
			}
		}
	}()
	return nil
}
<commit_msg>Fix minor typos in Graphite comments<commit_after>package graphite

import (
	"io"
	"log"
	"net"
	"strings"

	"github.com/influxdb/influxdb"
)

const (
	udpBufferSize = 65536
)

// UDPServer processes Graphite data received via UDP.
type UDPServer struct {
	server SeriesWriter
	parser *Parser

	Database string
	Logger   *log.Logger
}

// NewUDPServer returns a new instance of a UDPServer
func NewUDPServer(p *Parser, s SeriesWriter) *UDPServer {
	u := UDPServer{
		parser: p,
		server: s,
	}
	return &u
}

// SetLogOutput sets writer for all Graphite log output.
func (s *UDPServer) SetLogOutput(w io.Writer) {
	s.Logger = log.New(w, "[graphite] ", log.LstdFlags)
}

// SetDatabase sets the database for all Graphite log output.
func (s *UDPServer) SetDatabase(database string) {
	s.Database = database
}

// Protocol returns a string version of the supported protocol.
func (s *UDPServer) Protocol() string {
	return "udp"
}

// ListenAndServer instructs the UDPServer to start processing Graphite data
// on the given interface. iface must be in the form host:port.
func (u *UDPServer) ListenAndServe(iface string) error {
	if iface == "" { // Make sure we have an address
		return ErrBindAddressRequired
	} else if u.Database == "" { // Make sure they have a database
		// If they didn't specify a database, create one and set a default retention policy.
		if !u.server.DatabaseExists(DefaultDatabaseName) {
			u.Logger.Printf("default database %q does not exist.  creating.\n", DefaultDatabaseName)
			if e := u.server.CreateDatabase(DefaultDatabaseName); e != nil {
				return e
			}
			u.Database = DefaultDatabaseName
		}
	}

	addr, err := net.ResolveUDPAddr("udp", iface)
	if err != nil {
		return nil
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		return err
	}

	buf := make([]byte, udpBufferSize)
	go func() {
		for {
			n, _, err := conn.ReadFromUDP(buf)
			if err != nil {
				return
			}
			for _, line := range strings.Split(string(buf[:n]), "\n") {
				point, err := u.parser.Parse(line)
				if err != nil {
					continue
				}

				// Send the data to database
				_, e := u.server.WriteSeries(u.Database, "", []influxdb.Point{point})
				if e != nil {
					u.Logger.Printf("failed to write data point: %s\n", e)
				}
			}
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>package ingestion

import (
	"crypto/md5"
	"fmt"
	"io"
	"path/filepath"
	"sort"
	"sync"
	"testing"
	"time"

	assert "github.com/stretchr/testify/require"
	"go.skia.org/infra/go/fileutil"
	"go.skia.org/infra/go/sharedconfig"
	"go.skia.org/infra/go/util"
	"go.skia.org/infra/go/vcsinfo"
)

const LOCAL_STATUS_DIR = "./ingestion_status"

const RFLOCATION_CONTENT = "result file content"

func TestPollingIngester(t *testing.T) {
	testIngester(t, LOCAL_STATUS_DIR+"-polling", false)
}

func TestEventIngester(t *testing.T) {
	testIngester(t, LOCAL_STATUS_DIR+"-events", true)
}

func testIngester(t *testing.T, statusDir string, asEvents bool) {
	defer util.RemoveAll(statusDir)

	now := time.Now()
	beginningOfTime := now.Add(-time.Hour * 24 * 10).Unix()
	const totalCommits = 100

	// Instantiate mock VCS and the source.
	vcs := getVCS(beginningOfTime, now.Unix(), totalCommits)
	hashes := vcs.From(time.Unix(0, 0))
	assert.Equal(t, totalCommits, len(hashes))
	for _, h := range hashes {
		assert.NotEqual(t, "", h)
	}

	useNCommits := -1
	if asEvents {
		useNCommits = totalCommits / 2
	}
	sources := []Source{MockSource(t, vcs, useNCommits)}

	// Instantiate the mock processor.
	collected := map[string]int{}
	var mutex sync.Mutex

	resultFiles := []ResultFileLocation{}
	processFn := func(result ResultFileLocation) error {
		mutex.Lock()
		defer mutex.Unlock()
		collected[result.Name()] += 1
		resultFiles = append(resultFiles, result)
		return nil
	}

	finishFn := func() error { return nil }
	processor := MockProcessor(processFn, finishFn)

	// Instantiate ingesterConf
	conf := &sharedconfig.IngesterConfig{
		RunEvery:  sharedconfig.TomlDuration{Duration: 1 * time.Second},
		NCommits:  totalCommits / 2,
		MinDays:   3,
		StatusDir: statusDir,
	}

	// Instantiate ingester and start it.
	ingester, err := NewIngester("test-ingester", conf, vcs, sources, processor)
	assert.NoError(t, err)
	ingester.Start()

	// Wait until we have collected the desired result, but no more than two seconds.
	startTime := time.Now()
	for {
		mutex.Lock()
		colen := len(collected)
		mutex.Unlock()
		if colen >= (totalCommits/2) || (time.Now().Sub(startTime) > (time.Second * 2)) {
			break
		}
		time.Sleep(time.Millisecond * 100)
	}

	assert.Equal(t, totalCommits/2, len(collected))
	for _, count := range collected {
		assert.Equal(t, 1, count)
	}
	for _, result := range sources[0].(*mockSource).data[totalCommits/2:] {
		_, ok := collected[result.Name()]
		assert.True(t, ok)
	}

	// Make sure that all the files were written to disk.
	ingester.syncFileWrite()
	for _, result := range resultFiles {
		fPath := filepath.Join(ingester.resultFilesDir, result.Name())
		assert.True(t, fileutil.FileExists(fPath), fmt.Sprintf("File: %s does not exist", fPath))
	}
}

// mock processor
type mockProcessor struct {
	process func(ResultFileLocation) error
	finish  func() error
}

func MockProcessor(process func(ResultFileLocation) error, finish func() error) Processor {
	return &mockProcessor{
		process: process,
		finish:  finish,
	}
}

func (m *mockProcessor) Process(resultsFile ResultFileLocation) error {
	return m.process(resultsFile)
}

func (m *mockProcessor) BatchFinished() error {
	return m.finish()
}

type mockRFLocation struct {
	path        string
	md5         string
	lastUpdated int64
}

func (m *mockRFLocation) Open() (io.ReadCloser, error) { return nil, nil }
func (m *mockRFLocation) Name() string                 { return m.path }
func (m *mockRFLocation) MD5() string                  { return m.md5 }
func (m *mockRFLocation) TimeStamp() int64             { return m.lastUpdated }
func (m *mockRFLocation) Content() []byte              { return []byte(RFLOCATION_CONTENT) }

func rfLocation(t time.Time, fname string) ResultFileLocation {
	path := fmt.Sprintf("root/%d/%d/%d/%d/%d/%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), fname)
	return &mockRFLocation{
		path:        path,
		md5:         fmt.Sprintf("%x", md5.Sum([]byte(path))),
		lastUpdated: t.Unix(),
	}
}

// mock source
type mockSource struct {
	data          []ResultFileLocation
	nEventCommits int
}

// If the nEventCommits > 0 then it indicates to use events and send
// that number of result files.
func MockSource(t *testing.T, vcs vcsinfo.VCS, nEventCommits int) Source {
	hashes := vcs.From(time.Unix(0, 0))
	ret := make([]ResultFileLocation, 0, len(hashes))
	for _, h := range hashes {
		detail, err := vcs.Details(h, true)
		assert.NoError(t, err)
		ret = append(ret, rfLocation(detail.Timestamp, fmt.Sprintf("result-file-%s", h)))
	}
	return &mockSource{
		data:          ret,
		nEventCommits: nEventCommits,
	}
}

func (m *mockSource) Poll(startTime, endTime int64) ([]ResultFileLocation, error) {
	if m.nEventCommits <= 0 {
		startIdx := sort.Search(len(m.data), func(i int) bool { return m.data[i].TimeStamp() >= startTime })
		endIdx := startIdx
		for ; (endIdx < len(m.data)) && (m.data[endIdx].TimeStamp() <= endTime); endIdx++ {
		}
		return m.data[startIdx:endIdx], nil
	}
	return []ResultFileLocation{}, nil
}

func (m *mockSource) EventChan() <-chan []ResultFileLocation {
	if m.nEventCommits > 0 {
		ch := make(chan []ResultFileLocation)
		go func() {
			for _, oneEntry := range m.data[len(m.data)-m.nEventCommits:] {
				go func(entry ResultFileLocation) {
					ch <- []ResultFileLocation{entry}
				}(oneEntry)
				time.Sleep(time.Millisecond)
			}
		}()
		return ch
	}
	return nil
}

func (m mockSource) ID() string {
	return "test-source"
}

// return a mock vcs
func getVCS(start, end int64, nCommits int) vcsinfo.VCS {
	commits := make([]*vcsinfo.LongCommit, 0, nCommits)
	inc := (end - start - 3600) / int64(nCommits)
	t := start
	for i := 0; i < nCommits; i++ {
		commits = append(commits, &vcsinfo.LongCommit{
			ShortCommit: &vcsinfo.ShortCommit{
				Hash:    fmt.Sprintf("hash-%d", i),
				Subject: fmt.Sprintf("Commit #%d", i),
			},
			Timestamp: time.Unix(t, 0),
		})
		t += inc
	}
	return MockVCS(commits)
}

func TestRflQueue(t *testing.T) {
	locs := []ResultFileLocation{
		rfLocation(time.Now(), "1"),
		rfLocation(time.Now(), "2"),
		rfLocation(time.Now(), "3"),
		rfLocation(time.Now(), "4"),
		rfLocation(time.Now(), "5"),
	}

	queue := rflQueue([]ResultFileLocation{})
	queue.push(locs[0:3])
	queue.push(locs[3:])

	assert.Equal(t, locs, []ResultFileLocation(queue))
	queue.clear()
	assert.Equal(t, 0, len(queue))
}
<commit_msg>Fix ingestion tests<commit_after>package ingestion

import (
	"crypto/md5"
	"fmt"
	"io"
	"path/filepath"
	"sort"
	"sync"
	"testing"
	"time"

	assert "github.com/stretchr/testify/require"
	"go.skia.org/infra/go/fileutil"
	"go.skia.org/infra/go/sharedconfig"
	"go.skia.org/infra/go/util"
	"go.skia.org/infra/go/vcsinfo"
)

const LOCAL_STATUS_DIR = "./ingestion_status"

const RFLOCATION_CONTENT = "result file content"

func TestPollingIngester(t *testing.T) {
	testIngester(t, LOCAL_STATUS_DIR+"-polling", false)
}

func TestEventIngester(t *testing.T) {
	testIngester(t, LOCAL_STATUS_DIR+"-events", true)
}

func testIngester(t *testing.T, statusDir string, asEvents bool) {
	defer util.RemoveAll(statusDir)

	now := time.Now()
	beginningOfTime := now.Add(-time.Hour * 24 * 10).Unix()
	const totalCommits = 100

	// Instantiate mock VCS and the source.
	vcs := getVCS(beginningOfTime, now.Unix(), totalCommits)
	hashes := vcs.From(time.Unix(0, 0))
	assert.Equal(t, totalCommits, len(hashes))
	for _, h := range hashes {
		assert.NotEqual(t, "", h)
	}

	useNCommits := -1
	if asEvents {
		useNCommits = totalCommits / 2
	}
	sources := []Source{MockSource(t, vcs, useNCommits)}

	// Instantiate the mock processor.
	collected := map[string]int{}
	var mutex sync.Mutex

	resultFiles := []ResultFileLocation{}
	processFn := func(result ResultFileLocation) error {
		mutex.Lock()
		defer mutex.Unlock()
		collected[result.Name()] += 1
		resultFiles = append(resultFiles, result)
		return nil
	}

	finishFn := func() error { return nil }
	processor := MockProcessor(processFn, finishFn)

	// Instantiate ingesterConf
	conf := &sharedconfig.IngesterConfig{
		RunEvery:   sharedconfig.TomlDuration{Duration: 1 * time.Second},
		NCommits:   totalCommits / 2,
		MinDays:    3,
		StatusDir:  statusDir,
		LocalCache: true,
	}

	// Instantiate ingester and start it.
	ingester, err := NewIngester("test-ingester", conf, vcs, sources, processor)
	assert.NoError(t, err)
	ingester.Start()

	// Wait until we have collected the desired result, but no more than two seconds.
	startTime := time.Now()
	for {
		mutex.Lock()
		colen := len(collected)
		mutex.Unlock()
		if colen >= (totalCommits/2) || (time.Now().Sub(startTime) > (time.Second * 2)) {
			break
		}
		time.Sleep(time.Millisecond * 100)
	}

	assert.Equal(t, totalCommits/2, len(collected))
	for _, count := range collected {
		assert.Equal(t, 1, count)
	}
	for _, result := range sources[0].(*mockSource).data[totalCommits/2:] {
		_, ok := collected[result.Name()]
		assert.True(t, ok)
	}

	// Make sure that all the files were written to disk.
	ingester.syncFileWrite()
	for _, result := range resultFiles {
		fPath := filepath.Join(ingester.resultFilesDir, result.Name())
		assert.True(t, fileutil.FileExists(fPath), fmt.Sprintf("File: %s does not exist", fPath))
	}
}

// mock processor
type mockProcessor struct {
	process func(ResultFileLocation) error
	finish  func() error
}

func MockProcessor(process func(ResultFileLocation) error, finish func() error) Processor {
	return &mockProcessor{
		process: process,
		finish:  finish,
	}
}

func (m *mockProcessor) Process(resultsFile ResultFileLocation) error {
	return m.process(resultsFile)
}

func (m *mockProcessor) BatchFinished() error {
	return m.finish()
}

type mockRFLocation struct {
	path        string
	md5         string
	lastUpdated int64
}

func (m *mockRFLocation) Open() (io.ReadCloser, error) { return nil, nil }
func (m *mockRFLocation) Name() string                 { return m.path }
func (m *mockRFLocation) MD5() string                  { return m.md5 }
func (m *mockRFLocation) TimeStamp() int64             { return m.lastUpdated }
func (m *mockRFLocation) Content() []byte              { return []byte(RFLOCATION_CONTENT) }

func rfLocation(t time.Time, fname string) ResultFileLocation {
	path := fmt.Sprintf("root/%d/%d/%d/%d/%d/%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), fname)
	return &mockRFLocation{
		path:        path,
		md5:         fmt.Sprintf("%x", md5.Sum([]byte(path))),
		lastUpdated: t.Unix(),
	}
}

// mock source
type mockSource struct {
	data          []ResultFileLocation
	nEventCommits int
}

// If the nEventCommits > 0 then it indicates to use events and send
// that number of result files.
func MockSource(t *testing.T, vcs vcsinfo.VCS, nEventCommits int) Source {
	hashes := vcs.From(time.Unix(0, 0))
	ret := make([]ResultFileLocation, 0, len(hashes))
	for _, h := range hashes {
		detail, err := vcs.Details(h, true)
		assert.NoError(t, err)
		ret = append(ret, rfLocation(detail.Timestamp, fmt.Sprintf("result-file-%s", h)))
	}
	return &mockSource{
		data:          ret,
		nEventCommits: nEventCommits,
	}
}

func (m *mockSource) Poll(startTime, endTime int64) ([]ResultFileLocation, error) {
	if m.nEventCommits <= 0 {
		startIdx := sort.Search(len(m.data), func(i int) bool { return m.data[i].TimeStamp() >= startTime })
		endIdx := startIdx
		for ; (endIdx < len(m.data)) && (m.data[endIdx].TimeStamp() <= endTime); endIdx++ {
		}
		return m.data[startIdx:endIdx], nil
	}
	return []ResultFileLocation{}, nil
}

func (m *mockSource) EventChan() <-chan []ResultFileLocation {
	if m.nEventCommits > 0 {
		ch := make(chan []ResultFileLocation)
		go func() {
			for _, oneEntry := range m.data[len(m.data)-m.nEventCommits:] {
				go func(entry ResultFileLocation) {
					ch <- []ResultFileLocation{entry}
				}(oneEntry)
				time.Sleep(time.Millisecond)
			}
		}()
		return ch
	}
	return nil
}

func (m mockSource) ID() string {
	return "test-source"
}

// return a mock vcs
func getVCS(start, end int64, nCommits int) vcsinfo.VCS {
	commits := make([]*vcsinfo.LongCommit, 0, nCommits)
	inc := (end - start - 3600) / int64(nCommits)
	t := start
	for i := 0; i < nCommits; i++ {
		commits = append(commits, &vcsinfo.LongCommit{
			ShortCommit: &vcsinfo.ShortCommit{
				Hash:    fmt.Sprintf("hash-%d", i),
				Subject: fmt.Sprintf("Commit #%d", i),
			},
			Timestamp: time.Unix(t, 0),
		})
		t += inc
	}
	return MockVCS(commits)
}

func TestRflQueue(t *testing.T) {
	locs := []ResultFileLocation{
		rfLocation(time.Now(), "1"),
		rfLocation(time.Now(), "2"),
		rfLocation(time.Now(), "3"),
		rfLocation(time.Now(), "4"),
		rfLocation(time.Now(), "5"),
	}

	queue := rflQueue([]ResultFileLocation{})
	queue.push(locs[0:3])
	queue.push(locs[3:])

	assert.Equal(t, locs, []ResultFileLocation(queue))
	queue.clear()
	assert.Equal(t, 0, len(queue))
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"koding/kontrol/kontrolhelper"
	"koding/tools/amqputil"
	"koding/tools/config"
	"koding/tools/lifecycle"
	"koding/tools/logger"
	"koding/tools/sockjs"
	"koding/tools/utils"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/fatih/set"
	"github.com/streadway/amqp"
)

const BROKER_NAME = "broker"

var (
	conf *config.Config
	log  = logger.New(BROKER_NAME)

	// routeMap holds the subscription list/set for any given routing key
	routeMap = make(map[string]*set.Set)

	// sessionsMap holds sessions with their socketIds
	sessionsMap = make(map[string]*sockjs.Session)

	globalMapMutex sync.Mutex

	changeClientsGauge          = lifecycle.CreateClientsGauge()
	changeNewClientsGauge       = logger.CreateCounterGauge("newClients", logger.NoUnit, true)
	changeWebsocketClientsGauge = logger.CreateCounterGauge("websocketClients", logger.NoUnit, false)

	flagProfile      = flag.String("c", "", "Configuration profile from file")
	flagBrokerDomain = flag.String("a", "", "Send kontrol a custom domain istead of os.Hostname")
	flagKontrolUUID  = flag.String("u", "", "Enable Kontrol mode")
	flagBrokerType   = flag.String("b", "broker", "Define broker type. Available: broker and brokerKite. B")
	flagDebug        = flag.Bool("d", false, "Debug mode")
)

// Broker is a router/multiplexer that routes messages coming from a SockJS
// server to an AMQP exchange and vice versa. Broker basically listens to
// client messages (Koding users) from the SockJS server. The message is
// either passed to the appropriate exchange or a response is sent back to the
// client. Each message has an "action" field that defines how to act for a
// received message.
type Broker struct {
	Config            *config.Broker
	Hostname          string
	ServiceUniqueName string
	AuthAllExchange   string
	PublishConn       *amqp.Connection
	ConsumeConn       *amqp.Connection

	// Accepts SockJS connections
	listener net.Listener

	// Closed when SockJS server is ready to acccept connections
	ready chan struct{}
}

// NewBroker returns a new Broker instance with ServiceUniqueName and Hostname
// prepopulated. After creating a Broker instance, one has to call
// broker.Run() or broker.Start() to start the broker instance and call
// broker.Close() for a graceful stop.
func NewBroker() *Broker {
	// returns os.Hostname() if config.BrokerDomain is empty, otherwise it just
	// returns config.BrokerDomain back
	brokerHostname := kontrolhelper.CustomHostname(*flagBrokerDomain)
	sanitizedHostname := strings.Replace(brokerHostname, ".", "_", -1)
	serviceUniqueName := BROKER_NAME + "|" + sanitizedHostname

	return &Broker{
		Hostname:          brokerHostname,
		ServiceUniqueName: serviceUniqueName,
		ready:             make(chan struct{}),
	}
}

func main() {
	flag.Parse()
	if *flagProfile == "" {
		log.Fatal("Please specify profile via -c. Aborting.")
	}

	conf = config.MustConfig(*flagProfile)
	broker := NewBroker()

	switch *flagBrokerType {
	case "brokerKite":
		broker.Config = &conf.BrokerKite
	case "premiumBrokerKite":
		broker.Config = &conf.PremiumBrokerKite
	default:
		broker.Config = &conf.Broker
	}

	// update broker name
	log = logger.New(broker.Config.Name)
	var logLevel logger.Level
	if *flagDebug {
		logLevel = logger.DEBUG
	} else {
		logLevel = logger.GetLoggingLevelFromConfig(BROKER_NAME, *flagProfile)
	}

	log.SetLevel(logLevel)
	broker.Run()
}

// Run starts the broker.
func (b *Broker) Run() {
	// sets the maximum number of CPUs that can be executing simultaneously
	runtime.GOMAXPROCS(runtime.NumCPU())

	lifecycle.Startup(BROKER_NAME, false)
	logger.RunGaugesLoop(log)

	// Register broker to kontrol
	if err := b.registerToKontrol(); err != nil {
		log.Critical("Couldnt register to kontrol, stopping... %v", err)
		return
	}

	// Create AMQP exchanges/queues/bindings
	if err := b.startAMQP(); err != nil {
		log.Critical("Couldnt create amqp bindings, stopping... %v", err)
		return
	}

	// start listening/serving socket server
	b.startSockJS() // blocking
}

// Start is like Run() but waits until the SockJS listener is ready to be
// used.
func (b *Broker) Start() {
	go b.Run()
	<-b.ready
}

// Close close all amqp connections and closes the SockJS server listener
func (b *Broker) Close() {
	b.PublishConn.Close()
	b.ConsumeConn.Close()
	b.listener.Close()
}

// registerToKontrol registers the broker to KontrolDaemon. This is needed to
// populate a list of brokers and show them to the client. The list is
// available at: https://koding.com/-/services/broker?all
func (b *Broker) registerToKontrol() error {
	if err := kontrolhelper.RegisterToKontrol(
		conf,
		b.Config.Name,
		b.Config.Name, // servicGenericName
		b.ServiceUniqueName,
		*flagKontrolUUID,
		b.Hostname,
		b.Config.Port,
	); err != nil {
		return err
	}
	return nil
}

// startAMQP setups the the neccesary publisher and consumer connections for
// the broker broker.
func (b *Broker) startAMQP() error {
	b.PublishConn = amqputil.CreateConnection(conf, b.Config.Name)
	b.ConsumeConn = amqputil.CreateConnection(conf, b.Config.Name)
	consumeChannel := amqputil.CreateChannel(b.ConsumeConn)
	presenceQueue := amqputil.JoinPresenceExchange(
		consumeChannel,      // channel
		"services-presence", // exchange
		b.Config.Name,       // serviceType
		b.Config.Name,       // serviceGenericName
		b.ServiceUniqueName, // serviceUniqueName
		false,               // loadBalancing
	)

	go func() {
		sigusr1Channel := make(chan os.Signal)
		signal.Notify(sigusr1Channel, syscall.SIGUSR1)
		<-sigusr1Channel
		consumeChannel.QueueDelete(presenceQueue, false, false, false)
	}()

	stream := amqputil.DeclareBindConsumeQueue(consumeChannel, "topic", b.Config.Name, "#", false)

	if err := consumeChannel.ExchangeDeclare(
		"updateInstances", // name
		"fanout",          // kind
		false,             // durable
		false,             // autoDelete
		false,             // internal
		false,             // noWait
		nil,               // args
	); err != nil {
		return fmt.Errorf("Couldnt create updateInstances exchange  %v", err)
	}

	if err := consumeChannel.ExchangeBind(BROKER_NAME, "", "updateInstances", false, nil); err != nil {
		return fmt.Errorf("Couldnt bind to updateInstances exchange  %v", err)
	}

	go func(stream <-chan amqp.Delivery) {
		// start to listen from "broker" topic exchange
		for amqpMessage := range stream {
			sendMessageToClient(amqpMessage)
		}

		b.Close()

	}(stream)

	return nil
}

// sendMessageToClient takes an amqp messsage and delivers it to the related
// clients which are subscribed to the routing key
func sendMessageToClient(amqpMessage amqp.Delivery) {
	routingKey := amqpMessage.RoutingKey
	payloadsByte := utils.FilterInvalidUTF8(amqpMessage.Body)

	// We are sending multiple bodies for updateInstances exchange
	// so that there will be another operations, if exchange is not "updateInstances"
	// no need to add more overhead
	if amqpMessage.Exchange != "updateInstances" {
		payloadRaw := json.RawMessage(payloadsByte)
		processMessage(routingKey, &payloadRaw)
		return
	}

	// this part is only for updateInstances exchange
	var payloads []interface{}
	// unmarshal data to slice of interface
	if err := json.Unmarshal(payloadsByte, &payloads); err != nil {
		log.Error("Error while unmarshalling %v", err)
		log.Error("data %v", string(payloadsByte))
		log.Error("routingKey %v", routingKey)
		return
	}

	// range over the slice and send all of them to the same routingkey
	for _, payload := range payloads {
		payloadByte, err := json.Marshal(payload)
		if err != nil {
			log.Error("Error while marshalling %v", err)
			log.Error("data %v", string(payloadByte))
			log.Error("routingKey %v", routingKey)
			continue
		}
		payloadByteRaw := json.RawMessage(payloadByte)
		processMessage(routingKey, &payloadByteRaw)
	}
}

// processMessage gets routingKey and a payload for sending them to the client
// Gets subscription bindings from global routeMap
func processMessage(routingKey string, payload interface{}) {
	pos := strings.IndexRune(routingKey, '.') // skip first dot, since we want at least two components to always include the secret
	for pos != -1 && pos < len(routingKey) {
		index := strings.IndexRune(routingKey[pos+1:], '.')
		pos += index + 1
		if index == -1 {
			pos = len(routingKey)
		}
		routingKeyPrefix := routingKey[:pos]
		globalMapMutex.Lock()

		if routes, ok := routeMap[routingKeyPrefix]; ok {
			routes.Each(func(sessionId interface{}) bool {
				if routeSession, ok := sessionsMap[sessionId.(string)]; ok {
					sendToClient(routeSession, routingKey, &payload)
				}
				return true
			})
		}
		globalMapMutex.Unlock()
	}
}

// startSockJS starts a new HTTPS listener that implies the SockJS protocol.
func (b *Broker) startSockJS() {
	service := sockjs.NewService(
		conf.Client.StaticFilesBaseUrl+"/js/sock.js",
		10*time.Minute,
		b.sockjsSession,
	)
	defer service.Close()

	service.MaxReceivedPerSecond = 50
	service.ErrorHandler = log.LogError

	// TODO use http.Mux instead of sockjs.Mux.
	mux := &sockjs.Mux{
		Handlers: map[string]http.Handler{
			"/subscribe": service,
			"/buildnumber": http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				w.Header().Set("Content-Type", "text/plain")
				w.Write([]byte(strconv.Itoa(conf.BuildNumber)))
			}),
		},
	}

	server := &http.Server{Handler: mux}

	var err error
	b.listener, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP(b.Config.IP), Port: b.Config.Port})
	if err != nil {
		log.Fatal(err)
	}

	if b.Config.CertFile != "" {
		cert, err := tls.LoadX509KeyPair(b.Config.CertFile, b.Config.KeyFile)
		if err != nil {
			log.Fatal(err)
		}
		b.listener = tls.NewListener(b.listener, &tls.Config{
			NextProtos:   []string{"http/1.1"},
			Certificates: []tls.Certificate{cert},
		})
	}

	// signal that we are ready now
	close(b.ready)

	lastErrorTime := time.Now()
	for {
		err := server.Serve(b.listener)
		if err != nil {
			// comes when the broker is closed with Close() method. This error
			// is defined in net/net.go as "var errClosing", unfortunaly it's
			// not exported.
			if strings.Contains(err.Error(), "use of closed network connection") {
				return
			}

			log.Warning("Server error: %v", err)
			if time.Now().Sub(lastErrorTime) < time.Second {
				log.Fatal(nil)
			}
			lastErrorTime = time.Now()
		}
	}

}

// sockjsSession is called for every client connection and handles all the
// message trafic for a single client connection.
func (b *Broker) sockjsSession(session *sockjs.Session) {
	client, err := NewClient(session, b)
	if err != nil {
		log.Critical("Couldnt create client %v", err)
		return
	}

	sessionGaugeEnd := client.gaugeStart()

	defer sessionGaugeEnd()
	defer client.Close()

	err = client.ControlChannel.Publish(b.Config.AuthAllExchange, "broker.clientConnected", false, false, amqp.Publishing{Body: []byte(client.SocketId)})
	if err != nil {
		log.Critical("Couldnt publish to control channel %v", err)
	}

	sendToClient(session, "broker.connected", client.SocketId)

	for data := range session.ReceiveChan {
		if data == nil || session.Closed {
			break
		}

		client.handleSessionMessage(data)
	}
}

// sendToClient sends the given payload back to the client. It attachs the
// routintKey along with the payload. It closes the session if sending fails.
func sendToClient(session *sockjs.Session, routingKey string, payload interface{}) {
	var message struct {
		RoutingKey string      `json:"routingKey"`
		Payload    interface{} `json:"payload"`
	}
	message.RoutingKey = routingKey
	message.Payload = payload
	if !session.Send(message) {
		session.Close()
		log.Warning("Dropped session because of broker to client buffer overflow. %v", session.Tag)
	}
}
<commit_msg>Broker: make logging one line<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"koding/kontrol/kontrolhelper"
	"koding/tools/amqputil"
	"koding/tools/config"
	"koding/tools/lifecycle"
	"koding/tools/logger"
	"koding/tools/sockjs"
	"koding/tools/utils"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/fatih/set"
	"github.com/streadway/amqp"
)

const BROKER_NAME = "broker"

var (
	conf *config.Config
	log  = logger.New(BROKER_NAME)

	// routeMap holds the subscription list/set for any given routing key
	routeMap = make(map[string]*set.Set)

	// sessionsMap holds sessions with their socketIds
	sessionsMap = make(map[string]*sockjs.Session)

	globalMapMutex sync.Mutex

	changeClientsGauge          = lifecycle.CreateClientsGauge()
	changeNewClientsGauge       = logger.CreateCounterGauge("newClients", logger.NoUnit, true)
	changeWebsocketClientsGauge = logger.CreateCounterGauge("websocketClients", logger.NoUnit, false)

	flagProfile      = flag.String("c", "", "Configuration profile from file")
	flagBrokerDomain = flag.String("a", "", "Send kontrol a custom domain istead of os.Hostname")
	flagKontrolUUID  = flag.String("u", "", "Enable Kontrol mode")
	flagBrokerType   = flag.String("b", "broker", "Define broker type. Available: broker and brokerKite. B")
	flagDebug        = flag.Bool("d", false, "Debug mode")
)

// Broker is a router/multiplexer that routes messages coming from a SockJS
// server to an AMQP exchange and vice versa. Broker basically listens to
// client messages (Koding users) from the SockJS server. The message is
// either passed to the appropriate exchange or a response is sent back to the
// client. Each message has an "action" field that defines how to act for a
// received message.
type Broker struct {
	Config            *config.Broker
	Hostname          string
	ServiceUniqueName string
	AuthAllExchange   string
	PublishConn       *amqp.Connection
	ConsumeConn       *amqp.Connection

	// Accepts SockJS connections
	listener net.Listener

	// Closed when SockJS server is ready to acccept connections
	ready chan struct{}
}

// NewBroker returns a new Broker instance with ServiceUniqueName and Hostname
// prepopulated. After creating a Broker instance, one has to call
// broker.Run() or broker.Start() to start the broker instance and call
// broker.Close() for a graceful stop.
func NewBroker() *Broker {
	// returns os.Hostname() if config.BrokerDomain is empty, otherwise it just
	// returns config.BrokerDomain back
	brokerHostname := kontrolhelper.CustomHostname(*flagBrokerDomain)
	sanitizedHostname := strings.Replace(brokerHostname, ".", "_", -1)
	serviceUniqueName := BROKER_NAME + "|" + sanitizedHostname

	return &Broker{
		Hostname:          brokerHostname,
		ServiceUniqueName: serviceUniqueName,
		ready:             make(chan struct{}),
	}
}

func main() {
	flag.Parse()
	if *flagProfile == "" {
		log.Fatal("Please specify profile via -c. Aborting.")
	}

	conf = config.MustConfig(*flagProfile)
	broker := NewBroker()

	switch *flagBrokerType {
	case "brokerKite":
		broker.Config = &conf.BrokerKite
	case "premiumBrokerKite":
		broker.Config = &conf.PremiumBrokerKite
	default:
		broker.Config = &conf.Broker
	}

	// update broker name
	log = logger.New(broker.Config.Name)
	var logLevel logger.Level
	if *flagDebug {
		logLevel = logger.DEBUG
	} else {
		logLevel = logger.GetLoggingLevelFromConfig(BROKER_NAME, *flagProfile)
	}

	log.SetLevel(logLevel)
	broker.Run()
}

// Run starts the broker.
func (b *Broker) Run() {
	// sets the maximum number of CPUs that can be executing simultaneously
	runtime.GOMAXPROCS(runtime.NumCPU())

	lifecycle.Startup(BROKER_NAME, false)
	logger.RunGaugesLoop(log)

	// Register broker to kontrol
	if err := b.registerToKontrol(); err != nil {
		log.Critical("Couldnt register to kontrol, stopping... %v", err)
		return
	}

	// Create AMQP exchanges/queues/bindings
	if err := b.startAMQP(); err != nil {
		log.Critical("Couldnt create amqp bindings, stopping... %v", err)
		return
	}

	// start listening/serving socket server
	b.startSockJS() // blocking
}

// Start is like Run() but waits until the SockJS listener is ready to be
// used.
func (b *Broker) Start() {
	go b.Run()
	<-b.ready
}

// Close close all amqp connections and closes the SockJS server listener
func (b *Broker) Close() {
	b.PublishConn.Close()
	b.ConsumeConn.Close()
	b.listener.Close()
}

// registerToKontrol registers the broker to KontrolDaemon. This is needed to
// populate a list of brokers and show them to the client. The list is
// available at: https://koding.com/-/services/broker?all
func (b *Broker) registerToKontrol() error {
	if err := kontrolhelper.RegisterToKontrol(
		conf,
		b.Config.Name,
		b.Config.Name, // servicGenericName
		b.ServiceUniqueName,
		*flagKontrolUUID,
		b.Hostname,
		b.Config.Port,
	); err != nil {
		return err
	}
	return nil
}

// startAMQP setups the the neccesary publisher and consumer connections for
// the broker broker.
func (b *Broker) startAMQP() error {
	b.PublishConn = amqputil.CreateConnection(conf, b.Config.Name)
	b.ConsumeConn = amqputil.CreateConnection(conf, b.Config.Name)
	consumeChannel := amqputil.CreateChannel(b.ConsumeConn)
	presenceQueue := amqputil.JoinPresenceExchange(
		consumeChannel,      // channel
		"services-presence", // exchange
		b.Config.Name,       // serviceType
		b.Config.Name,       // serviceGenericName
		b.ServiceUniqueName, // serviceUniqueName
		false,               // loadBalancing
	)

	go func() {
		sigusr1Channel := make(chan os.Signal)
		signal.Notify(sigusr1Channel, syscall.SIGUSR1)
		<-sigusr1Channel
		consumeChannel.QueueDelete(presenceQueue, false, false, false)
	}()

	stream := amqputil.DeclareBindConsumeQueue(consumeChannel, "topic", b.Config.Name, "#", false)

	if err := consumeChannel.ExchangeDeclare(
		"updateInstances", // name
		"fanout",          // kind
		false,             // durable
		false,             // autoDelete
		false,             // internal
		false,             // noWait
		nil,               // args
	); err != nil {
		return fmt.Errorf("Couldnt create updateInstances exchange  %v", err)
	}

	if err := consumeChannel.ExchangeBind(BROKER_NAME, "", "updateInstances", false, nil); err != nil {
		return fmt.Errorf("Couldnt bind to updateInstances exchange  %v", err)
	}

	go func(stream <-chan amqp.Delivery) {
		// start to listen from "broker" topic exchange
		for amqpMessage := range stream {
			sendMessageToClient(amqpMessage)
		}

		b.Close()

	}(stream)

	return nil
}

// sendMessageToClient takes an amqp messsage and delivers it to the related
// clients which are subscribed to the routing key
func sendMessageToClient(amqpMessage amqp.Delivery) {
	routingKey := amqpMessage.RoutingKey
	payloadsByte := utils.FilterInvalidUTF8(amqpMessage.Body)

	// We are sending multiple bodies for updateInstances exchange
	// so that there will be another operations, if exchange is not "updateInstances"
	// no need to add more overhead
	if amqpMessage.Exchange != "updateInstances" {
		payloadRaw := json.RawMessage(payloadsByte)
		processMessage(routingKey, &payloadRaw)
		return
	}

	// this part is only for updateInstances exchange
	var payloads []interface{}
	// unmarshal data to slice of interface
	if err := json.Unmarshal(payloadsByte, &payloads); err != nil {
		log.Error("Error while unmarshalling:%v data:%v routingKey:%v", err, string(payloadsByte), routingKey)
		return
	}

	// range over the slice and send all of them to the same routingkey
	for _, payload := range payloads {
		payloadByte, err := json.Marshal(payload)
		if err != nil {
			log.Error("Error while marshalling:%v data:%v routingKey:%v", err, string(payloadByte), routingKey)
			continue
		}
		payloadByteRaw := json.RawMessage(payloadByte)
		processMessage(routingKey, &payloadByteRaw)
	}
}

// processMessage gets routingKey and a payload for sending them to the client
// Gets subscription bindings from global routeMap
func processMessage(routingKey string, payload interface{}) {
	pos := strings.IndexRune(routingKey, '.') // skip first dot, since we want at least two components to always include the secret
	for pos != -1 && pos < len(routingKey) {
		index := strings.IndexRune(routingKey[pos+1:], '.')
		pos += index + 1
		if index == -1 {
			pos = len(routingKey)
		}
		routingKeyPrefix := routingKey[:pos]
		globalMapMutex.Lock()

		if routes, ok := routeMap[routingKeyPrefix]; ok {
			routes.Each(func(sessionId interface{}) bool {
				if routeSession, ok := sessionsMap[sessionId.(string)]; ok {
					sendToClient(routeSession, routingKey, &payload)
				}
				return true
			})
		}
		globalMapMutex.Unlock()
	}
}

// startSockJS starts a new HTTPS listener that implies the SockJS protocol.
func (b *Broker) startSockJS() {
	service := sockjs.NewService(
		conf.Client.StaticFilesBaseUrl+"/js/sock.js",
		10*time.Minute,
		b.sockjsSession,
	)
	defer service.Close()

	service.MaxReceivedPerSecond = 50
	service.ErrorHandler = log.LogError

	// TODO use http.Mux instead of sockjs.Mux.
	mux := &sockjs.Mux{
		Handlers: map[string]http.Handler{
			"/subscribe": service,
			"/buildnumber": http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				w.Header().Set("Content-Type", "text/plain")
				w.Write([]byte(strconv.Itoa(conf.BuildNumber)))
			}),
		},
	}

	server := &http.Server{Handler: mux}

	var err error
	b.listener, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP(b.Config.IP), Port: b.Config.Port})
	if err != nil {
		log.Fatal(err)
	}

	if b.Config.CertFile != "" {
		cert, err := tls.LoadX509KeyPair(b.Config.CertFile, b.Config.KeyFile)
		if err != nil {
			log.Fatal(err)
		}
		b.listener = tls.NewListener(b.listener, &tls.Config{
			NextProtos:   []string{"http/1.1"},
			Certificates: []tls.Certificate{cert},
		})
	}

	// signal that we are ready now
	close(b.ready)

	lastErrorTime := time.Now()
	for {
		err := server.Serve(b.listener)
		if err != nil {
			// comes when the broker is closed with Close() method. This error
			// is defined in net/net.go as "var errClosing", unfortunaly it's
			// not exported.
			if strings.Contains(err.Error(), "use of closed network connection") {
				return
			}

			log.Warning("Server error: %v", err)
			if time.Now().Sub(lastErrorTime) < time.Second {
				log.Fatal(nil)
			}
			lastErrorTime = time.Now()
		}
	}

}

// sockjsSession is called for every client connection and handles all the
// message trafic for a single client connection.
func (b *Broker) sockjsSession(session *sockjs.Session) {
	client, err := NewClient(session, b)
	if err != nil {
		log.Critical("Couldnt create client %v", err)
		return
	}

	sessionGaugeEnd := client.gaugeStart()

	defer sessionGaugeEnd()
	defer client.Close()

	err = client.ControlChannel.Publish(b.Config.AuthAllExchange, "broker.clientConnected", false, false, amqp.Publishing{Body: []byte(client.SocketId)})
	if err != nil {
		log.Critical("Couldnt publish to control channel %v", err)
	}

	sendToClient(session, "broker.connected", client.SocketId)

	for data := range session.ReceiveChan {
		if data == nil || session.Closed {
			break
		}

		client.handleSessionMessage(data)
	}
}

// sendToClient sends the given payload back to the client. It attachs the
// routintKey along with the payload. It closes the session if sending fails.
func sendToClient(session *sockjs.Session, routingKey string, payload interface{}) {
	var message struct {
		RoutingKey string      `json:"routingKey"`
		Payload    interface{} `json:"payload"`
	}
	message.RoutingKey = routingKey
	message.Payload = payload
	if !session.Send(message) {
		session.Close()
		log.Warning("Dropped session because of broker to client buffer overflow. %v", session.Tag)
	}
}
<|endoftext|>


<commit_before>package models

import "labix.org/v2/mgo/bson"

type Tag struct {
  Id     bson.ObjectId `bson:"_id" json:"-"`
  Title  string        `bson:"title"`
  Slug   string        `bson:"slug"`
  Group  string        `bson:"group"`
  Type   string        `bson:"type,omitempty"`
  Counts TagCount      `bson:"counts"`
  Meta   Meta          `bson:"meta"`
}

type TagCount struct {
  Followers int `bson:"followers"`
  Following int `bson:"following"`
  Post      int `bson:"post,omitempty"`
  Tagged    int `bson:"tagged"`
}
<commit_msg>Moderation: Tag.Type is changed to Status<commit_after>package models

import "labix.org/v2/mgo/bson"

type Tag struct {
  Id     bson.ObjectId `bson:"_id" json:"-"`
  Title  string        `bson:"title"`
  Slug   string        `bson:"slug"`
  Group  string        `bson:"group"`
  Status string        `bson:"status,omitempty"`
  Counts TagCount      `bson:"counts"`
  Meta   Meta          `bson:"meta"`
}

type TagCount struct {
  Followers int `bson:"followers"`
  Following int `bson:"following"`
  Post      int `bson:"post,omitempty"`
  Tagged    int `bson:"tagged"`
}
<|endoftext|>


<commit_before>// package baseline contains functions to gather the current baseline and
// write them to GCS.
package baseline

import (
	"go.skia.org/infra/go/tiling"
	"go.skia.org/infra/golden/go/expstorage"
	"go.skia.org/infra/golden/go/types"
)

// BaseLine maps test names to a set of digests with their label.
// Test names are the names of individual tests, e.g. GMs and digests are
// hashes that uniquely identify an output image.
// This is used as the export format of baseline.
type BaseLine map[string]types.TestClassification

// add adds a test/digest pair to the baseline.
func (b BaseLine) add(testName, digest string) {
	if (testName == "") || (digest == types.MISSING_DIGEST) {
		return
	}
	if found, ok := b[testName]; ok {
		found[digest] = types.POSITIVE
	} else {
		b[testName] = types.TestClassification{digest: types.POSITIVE}
	}
}

// CommitableBaseLine captures the data necessary to verify test results on the
// commit queue.
type CommitableBaseLine struct {
	// Commit is the commit for which this baseline was collected.
	Commit *tiling.Commit `json:"commmit"`

	// Master captures the baseline of the current commit.
	Master BaseLine `json:"master"`

	// ChangeLists captures baselines for pending commits. These baselines have
	// been added by running baselines trybots and are commited to the master
	// baseline when the CL lands.
	ChangeLists map[string]BaseLine `json:"changeLists"`
}

// GetBaseline calculates the master baseline for the given configuration of
// expectations and the given tile. The commit of the baseline is last commit
// in tile.
func GetBaseline(exps *expstorage.Expectations, tile *tiling.Tile) *CommitableBaseLine {
	masterBaseline := BaseLine{}
	for _, trace := range tile.Traces {
		gTrace := trace.(*types.GoldenTrace)
		testName := gTrace.Params_[types.PRIMARY_KEY_FIELD]
		digest := gTrace.LastDigest()
		if exps.Classification(testName, digest) == types.POSITIVE {
			masterBaseline.add(testName, digest)
		}
	}

	ret := &CommitableBaseLine{
		Commit:      tile.Commits[tile.LastCommitIndex()],
		Master:      masterBaseline,
		ChangeLists: map[string]BaseLine{},
	}
	return ret
}
<commit_msg>[gold] Fix typo in baseline output<commit_after>// package baseline contains functions to gather the current baseline and
// write them to GCS.
package baseline

import (
	"go.skia.org/infra/go/tiling"
	"go.skia.org/infra/golden/go/expstorage"
	"go.skia.org/infra/golden/go/types"
)

// BaseLine maps test names to a set of digests with their label.
// Test names are the names of individual tests, e.g. GMs and digests are
// hashes that uniquely identify an output image.
// This is used as the export format of baseline.
type BaseLine map[string]types.TestClassification

// add adds a test/digest pair to the baseline.
func (b BaseLine) add(testName, digest string) {
	if (testName == "") || (digest == types.MISSING_DIGEST) {
		return
	}
	if found, ok := b[testName]; ok {
		found[digest] = types.POSITIVE
	} else {
		b[testName] = types.TestClassification{digest: types.POSITIVE}
	}
}

// CommitableBaseLine captures the data necessary to verify test results on the
// commit queue.
type CommitableBaseLine struct {
	// Commit is the commit for which this baseline was collected.
	Commit *tiling.Commit `json:"commit"`

	// Master captures the baseline of the current commit.
	Master BaseLine `json:"master"`

	// ChangeLists captures baselines for pending commits. These baselines have
	// been added by running baselines trybots and are commited to the master
	// baseline when the CL lands.
	ChangeLists map[string]BaseLine `json:"changeLists"`
}

// GetBaseline calculates the master baseline for the given configuration of
// expectations and the given tile. The commit of the baseline is last commit
// in tile.
func GetBaseline(exps *expstorage.Expectations, tile *tiling.Tile) *CommitableBaseLine {
	masterBaseline := BaseLine{}
	for _, trace := range tile.Traces {
		gTrace := trace.(*types.GoldenTrace)
		testName := gTrace.Params_[types.PRIMARY_KEY_FIELD]
		digest := gTrace.LastDigest()
		if exps.Classification(testName, digest) == types.POSITIVE {
			masterBaseline.add(testName, digest)
		}
	}

	ret := &CommitableBaseLine{
		Commit:      tile.Commits[tile.LastCommitIndex()],
		Master:      masterBaseline,
		ChangeLists: map[string]BaseLine{},
	}
	return ret
}
<|endoftext|>


<commit_before>// Package card provides the /cards APIs
package card

import (
	"errors"
	"fmt"

	stripe "github.com/stripe/stripe-go"
	"github.com/stripe/stripe-go/form"
)

const (
	BrandUnknown stripe.CardBrand = "Unknown"
	Visa         stripe.CardBrand = "Visa"
	Amex         stripe.CardBrand = "American Express"
	MasterCard   stripe.CardBrand = "MasterCard"
	Discover     stripe.CardBrand = "Discover"
	JCB          stripe.CardBrand = "JCB"
	DinersClub   stripe.CardBrand = "Diners Club"

	Pass      stripe.Verification = "pass"
	Fail      stripe.Verification = "fail"
	Unchecked stripe.Verification = "unchecked"

	Credit         stripe.CardFunding = "credit"
	Debit          stripe.CardFunding = "debit"
	Prepaid        stripe.CardFunding = "prepaid"
	FundingUnknown stripe.CardFunding = "unknown"
)

// Client is used to invoke /cards APIs.
type Client struct {
	B   stripe.Backend
	Key string
}

// New POSTs new cards either for a customer or recipient.
// For more details see https://stripe.com/docs/api#create_card.
func New(params *stripe.CardParams) (*stripe.Card, error) {
	return getC().New(params)
}

func (c Client) New(params *stripe.CardParams) (*stripe.Card, error) {
	if params == nil {
		return nil, errors.New("params should not be nil")
	}

	body := &form.Values{}

	// Note that we call this special append method instead of the standard one
	// from the form package. We should not use form's because doing so will
	// include some parameters that are undesirable here.
	params.AppendToAsCardSourceOrExternalAccount(body, nil)

	card := &stripe.Card{}
	var err error

	if len(params.Account) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/accounts/%v/external_accounts", params.Account), c.Key, body, &params.Params, card)
	} else if len(params.Customer) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/customers/%v/cards", params.Customer), c.Key, body, &params.Params, card)
	} else if len(params.Recipient) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/recipients/%v/cards", params.Recipient), c.Key, body, &params.Params, card)
	} else {
		err = errors.New("Invalid card params: either account, customer or recipient need to be set")
	}

	return card, err
}

// Get returns the details of a card.
// For more details see https://stripe.com/docs/api#retrieve_card.
func Get(id string, params *stripe.CardParams) (*stripe.Card, error) {
	return getC().Get(id, params)
}

func (c Client) Get(id string, params *stripe.CardParams) (*stripe.Card, error) {
	if params == nil {
		return nil, errors.New("params should not be nil")
	}

	var body *form.Values
	var commonParams *stripe.Params

	if params != nil {
		commonParams = &params.Params
		body = &form.Values{}
		form.AppendTo(body, params)
	}

	card := &stripe.Card{}
	var err error

	if len(params.Account) > 0 {
		err = c.B.Call("GET", fmt.Sprintf("/accounts/%v/external_accounts/%v", params.Account, id), c.Key, body, commonParams, card)
	} else if len(params.Customer) > 0 {
		err = c.B.Call("GET", fmt.Sprintf("/customers/%v/cards/%v", params.Customer, id), c.Key, body, commonParams, card)
	} else if len(params.Recipient) > 0 {
		err = c.B.Call("GET", fmt.Sprintf("/recipients/%v/cards/%v", params.Recipient, id), c.Key, body, commonParams, card)
	} else {
		err = errors.New("Invalid card params: either account, customer or recipient need to be set")
	}

	return card, err
}

// Update updates a card's properties.
// For more details see	https://stripe.com/docs/api#update_card.
func Update(id string, params *stripe.CardParams) (*stripe.Card, error) {
	return getC().Update(id, params)
}

func (c Client) Update(id string, params *stripe.CardParams) (*stripe.Card, error) {
	if params == nil {
		return nil, errors.New("params should not be nil")
	}

	body := &form.Values{}
	form.AppendTo(body, params)

	card := &stripe.Card{}
	var err error

	if len(params.Account) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/accounts/%v/external_accounts/%v", params.Account, id), c.Key, body, &params.Params, card)
	} else if len(params.Customer) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/customers/%v/cards/%v", params.Customer, id), c.Key, body, &params.Params, card)
	} else if len(params.Recipient) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/recipients/%v/cards/%v", params.Recipient, id), c.Key, body, &params.Params, card)
	} else {
		err = errors.New("Invalid card params: either account, customer or recipient need to be set")
	}

	return card, err
}

// Del removes a card.
// For more details see https://stripe.com/docs/api#delete_card.
func Del(id string, params *stripe.CardParams) (*stripe.Card, error) {
	return getC().Del(id, params)
}

func (c Client) Del(id string, params *stripe.CardParams) (*stripe.Card, error) {
	if params == nil {
		return nil, errors.New("params should not be nil")
	}

	var body *form.Values
	var commonParams *stripe.Params

	if params != nil {
		body = &form.Values{}

		form.AppendTo(body, params)
		commonParams = &params.Params
	}

	card := &stripe.Card{}
	var err error

	if len(params.Account) > 0 {
		err = c.B.Call("DELETE", fmt.Sprintf("/accounts/%v/external_accounts/%v", params.Account, id), c.Key, body, commonParams, card)
	} else if len(params.Customer) > 0 {
		err = c.B.Call("DELETE", fmt.Sprintf("/customers/%v/cards/%v", params.Customer, id), c.Key, body, commonParams, card)
	} else if len(params.Recipient) > 0 {
		err = c.B.Call("DELETE", fmt.Sprintf("/recipients/%v/cards/%v", params.Recipient, id), c.Key, body, commonParams, card)
	} else {
		err = errors.New("Invalid card params: either account, customer or recipient need to be set")
	}

	return card, err
}

// List returns a list of cards.
// For more details see https://stripe.com/docs/api#list_cards.
func List(params *stripe.CardListParams) *Iter {
	return getC().List(params)
}

func (c Client) List(params *stripe.CardListParams) *Iter {
	body := &form.Values{}
	var lp *stripe.ListParams
	var p *stripe.Params

	if params != nil {
		form.AppendTo(body, params)
		lp = &params.ListParams
		p = params.ToParams()
	}

	return &Iter{stripe.GetIter(lp, body, func(b *form.Values) ([]interface{}, stripe.ListMeta, error) {
		list := &stripe.CardList{}
		var err error

		if params == nil {
			return nil, list.ListMeta, errors.New("params should not be nil")
		}

		if len(params.Account) > 0 {
			err = c.B.Call("GET", fmt.Sprintf("/accounts/%v/external_accounts", params.Account), c.Key, b, p, list)
		} else if len(params.Customer) > 0 {
			err = c.B.Call("GET", fmt.Sprintf("/customers/%v/cards", params.Customer), c.Key, b, p, list)
		} else if len(params.Recipient) > 0 {
			err = c.B.Call("GET", fmt.Sprintf("/recipients/%v/cards", params.Recipient), c.Key, b, p, list)
		} else {
			err = errors.New("Invalid card params: either account, customer or recipient need to be set")
		}

		ret := make([]interface{}, len(list.Values))
		for i, v := range list.Values {
			ret[i] = v
		}

		return ret, list.ListMeta, err
	})}
}

// Iter is an iterator for lists of Cards.
// The embedded Iter carries methods with it;
// see its documentation for details.
type Iter struct {
	*stripe.Iter
}

// Card returns the most recent Card
// visited by a call to Next.
func (i *Iter) Card() *stripe.Card {
	return i.Current().(*stripe.Card)
}

func getC() Client {
	return Client{stripe.GetBackend(stripe.APIBackend), stripe.Key}
}
<commit_msg>Now that we have `nil` check, remove the other guard<commit_after>// Package card provides the /cards APIs
package card

import (
	"errors"
	"fmt"

	stripe "github.com/stripe/stripe-go"
	"github.com/stripe/stripe-go/form"
)

const (
	BrandUnknown stripe.CardBrand = "Unknown"
	Visa         stripe.CardBrand = "Visa"
	Amex         stripe.CardBrand = "American Express"
	MasterCard   stripe.CardBrand = "MasterCard"
	Discover     stripe.CardBrand = "Discover"
	JCB          stripe.CardBrand = "JCB"
	DinersClub   stripe.CardBrand = "Diners Club"

	Pass      stripe.Verification = "pass"
	Fail      stripe.Verification = "fail"
	Unchecked stripe.Verification = "unchecked"

	Credit         stripe.CardFunding = "credit"
	Debit          stripe.CardFunding = "debit"
	Prepaid        stripe.CardFunding = "prepaid"
	FundingUnknown stripe.CardFunding = "unknown"
)

// Client is used to invoke /cards APIs.
type Client struct {
	B   stripe.Backend
	Key string
}

// New POSTs new cards either for a customer or recipient.
// For more details see https://stripe.com/docs/api#create_card.
func New(params *stripe.CardParams) (*stripe.Card, error) {
	return getC().New(params)
}

func (c Client) New(params *stripe.CardParams) (*stripe.Card, error) {
	if params == nil {
		return nil, errors.New("params should not be nil")
	}

	body := &form.Values{}

	// Note that we call this special append method instead of the standard one
	// from the form package. We should not use form's because doing so will
	// include some parameters that are undesirable here.
	params.AppendToAsCardSourceOrExternalAccount(body, nil)

	card := &stripe.Card{}
	var err error

	if len(params.Account) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/accounts/%v/external_accounts", params.Account), c.Key, body, &params.Params, card)
	} else if len(params.Customer) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/customers/%v/cards", params.Customer), c.Key, body, &params.Params, card)
	} else if len(params.Recipient) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/recipients/%v/cards", params.Recipient), c.Key, body, &params.Params, card)
	} else {
		err = errors.New("Invalid card params: either account, customer or recipient need to be set")
	}

	return card, err
}

// Get returns the details of a card.
// For more details see https://stripe.com/docs/api#retrieve_card.
func Get(id string, params *stripe.CardParams) (*stripe.Card, error) {
	return getC().Get(id, params)
}

func (c Client) Get(id string, params *stripe.CardParams) (*stripe.Card, error) {
	if params == nil {
		return nil, errors.New("params should not be nil")
	}

	var body *form.Values
	var commonParams *stripe.Params

	if params != nil {
		commonParams = &params.Params
		body = &form.Values{}
		form.AppendTo(body, params)
	}

	card := &stripe.Card{}
	var err error

	if len(params.Account) > 0 {
		err = c.B.Call("GET", fmt.Sprintf("/accounts/%v/external_accounts/%v", params.Account, id), c.Key, body, commonParams, card)
	} else if len(params.Customer) > 0 {
		err = c.B.Call("GET", fmt.Sprintf("/customers/%v/cards/%v", params.Customer, id), c.Key, body, commonParams, card)
	} else if len(params.Recipient) > 0 {
		err = c.B.Call("GET", fmt.Sprintf("/recipients/%v/cards/%v", params.Recipient, id), c.Key, body, commonParams, card)
	} else {
		err = errors.New("Invalid card params: either account, customer or recipient need to be set")
	}

	return card, err
}

// Update updates a card's properties.
// For more details see	https://stripe.com/docs/api#update_card.
func Update(id string, params *stripe.CardParams) (*stripe.Card, error) {
	return getC().Update(id, params)
}

func (c Client) Update(id string, params *stripe.CardParams) (*stripe.Card, error) {
	if params == nil {
		return nil, errors.New("params should not be nil")
	}

	body := &form.Values{}
	form.AppendTo(body, params)

	card := &stripe.Card{}
	var err error

	if len(params.Account) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/accounts/%v/external_accounts/%v", params.Account, id), c.Key, body, &params.Params, card)
	} else if len(params.Customer) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/customers/%v/cards/%v", params.Customer, id), c.Key, body, &params.Params, card)
	} else if len(params.Recipient) > 0 {
		err = c.B.Call("POST", fmt.Sprintf("/recipients/%v/cards/%v", params.Recipient, id), c.Key, body, &params.Params, card)
	} else {
		err = errors.New("Invalid card params: either account, customer or recipient need to be set")
	}

	return card, err
}

// Del removes a card.
// For more details see https://stripe.com/docs/api#delete_card.
func Del(id string, params *stripe.CardParams) (*stripe.Card, error) {
	return getC().Del(id, params)
}

func (c Client) Del(id string, params *stripe.CardParams) (*stripe.Card, error) {
	if params == nil {
		return nil, errors.New("params should not be nil")
	}

	var body *form.Values
	var commonParams *stripe.Params

	body = &form.Values{}
	form.AppendTo(body, params)
	commonParams = &params.Params

	card := &stripe.Card{}
	var err error

	if len(params.Account) > 0 {
		err = c.B.Call("DELETE", fmt.Sprintf("/accounts/%v/external_accounts/%v", params.Account, id), c.Key, body, commonParams, card)
	} else if len(params.Customer) > 0 {
		err = c.B.Call("DELETE", fmt.Sprintf("/customers/%v/cards/%v", params.Customer, id), c.Key, body, commonParams, card)
	} else if len(params.Recipient) > 0 {
		err = c.B.Call("DELETE", fmt.Sprintf("/recipients/%v/cards/%v", params.Recipient, id), c.Key, body, commonParams, card)
	} else {
		err = errors.New("Invalid card params: either account, customer or recipient need to be set")
	}

	return card, err
}

// List returns a list of cards.
// For more details see https://stripe.com/docs/api#list_cards.
func List(params *stripe.CardListParams) *Iter {
	return getC().List(params)
}

func (c Client) List(params *stripe.CardListParams) *Iter {
	body := &form.Values{}
	var lp *stripe.ListParams
	var p *stripe.Params

	if params != nil {
		form.AppendTo(body, params)
		lp = &params.ListParams
		p = params.ToParams()
	}

	return &Iter{stripe.GetIter(lp, body, func(b *form.Values) ([]interface{}, stripe.ListMeta, error) {
		list := &stripe.CardList{}
		var err error

		if params == nil {
			return nil, list.ListMeta, errors.New("params should not be nil")
		}

		if len(params.Account) > 0 {
			err = c.B.Call("GET", fmt.Sprintf("/accounts/%v/external_accounts", params.Account), c.Key, b, p, list)
		} else if len(params.Customer) > 0 {
			err = c.B.Call("GET", fmt.Sprintf("/customers/%v/cards", params.Customer), c.Key, b, p, list)
		} else if len(params.Recipient) > 0 {
			err = c.B.Call("GET", fmt.Sprintf("/recipients/%v/cards", params.Recipient), c.Key, b, p, list)
		} else {
			err = errors.New("Invalid card params: either account, customer or recipient need to be set")
		}

		ret := make([]interface{}, len(list.Values))
		for i, v := range list.Values {
			ret[i] = v
		}

		return ret, list.ListMeta, err
	})}
}

// Iter is an iterator for lists of Cards.
// The embedded Iter carries methods with it;
// see its documentation for details.
type Iter struct {
	*stripe.Iter
}

// Card returns the most recent Card
// visited by a call to Next.
func (i *Iter) Card() *stripe.Card {
	return i.Current().(*stripe.Card)
}

func getC() Client {
	return Client{stripe.GetBackend(stripe.APIBackend), stripe.Key}
}
<|endoftext|>


<commit_before>package parser

import (
	"bytes"
	"fmt"
	"path"

	"github.com/stephens2424/php/ast"
	"github.com/stephens2424/php/lexer"
	"github.com/stephens2424/php/token"
)

// Parser handles scanning through and parsing a PHP source string into an AST. It is configurable
// to have various types of debugging features.
type Parser struct {
	Debug       bool // Debug causes the parser to print all errors to stdout and relay any panic upon internal panic recovery.
	PrintTokens bool // PrintTokens causes the parser to print all tokens received from the lexer to stdout.
	MaxErrors   int  // Indicates the number of errors to allow before triggering a panic. The default is 10.
	FileSet     *ast.FileSet

	lexer      token.Stream
	previous   []token.Item
	idx        int
	current    token.Item
	errors     ParseErrorList
	parenLevel int

	file      *ast.File
	namespace *ast.Namespace
	scope     *ast.Scope

	currentCommentLines []token.Item
	currentCommentBlock *token.Item

	// this option exists to allow parser tests to pass while scope tests may be failing
	disableScoping bool

	instantiation bool
}

// NewParser readies a parser
func NewParser() *Parser {
	p := &Parser{
		idx:       -1,
		MaxErrors: 10,
		FileSet:   ast.NewFileSet(),
	}
	return p
}

// ParseErrorList is a list of ParseErrors.
type ParseErrorList []ParseError

// Error formats p into a string.
func (p ParseErrorList) Error() string {
	if len(p) == 0 {
		return ""
	}
	if len(p) == 1 {
		return p[0].Error()
	}
	buf := &bytes.Buffer{}
	for _, s := range p[:len(p)-1] {
		buf.WriteString(s.Error())
		buf.WriteString("\n")
	}
	buf.WriteString(p[len(p)-2].Error())
	return buf.String()
}

// ParseError represents an error found during parsing.
type ParseError struct {
	error
	Line, Column int
	File         *ast.File
}

func (p ParseError) Error() string {
	return fmt.Sprintf("%s:%d: %s", p.File.Name, p.Line, p.error)
}

func (p ParseError) String() string {
	return p.Error()
}

// Parse consumes the input string to produce an AST that represents it.
func (p *Parser) Parse(filepath, input string) (file *ast.File, err error) {
	file = &ast.File{Namespace: p.FileSet.GlobalNamespace, Name: path.Base(filepath)}
	p.file = file
	p.scope = p.FileSet.Scope
	p.namespace = p.FileSet.GlobalNamespace
	p.lexer = token.Subset(lexer.NewLexer(input), token.Significant)

	p.FileSet.Files[filepath] = p.file
	defer func() {
		if r := recover(); r != nil {
			err = append(ParseErrorList{errorf(p, "%s", r)}, p.errors...)
			if p.Debug {
				for _, err := range p.errors {
					fmt.Println(err)
				}
				panic(r)
			}
		}
	}()
	// expecting either token.HTML or token.PHPBegin
	p.file.Nodes = make([]ast.Node, 0, 1)
TokenLoop:
	for {
		p.next()
		switch p.current.Typ {
		case token.EOF:
			break TokenLoop
		default:
			n := p.parseNode()
			if n != nil {
				p.file.Nodes = append(p.file.Nodes, n)
			}
		}
	}
	if p.errors != nil {
		err = p.errors
	}
	return
}

func (p *Parser) parseNode() ast.Node {
	switch p.current.Typ {
	case token.HTML:
		return ast.Echo(ast.Literal{Type: ast.String, Value: p.current.Val})
	case token.PHPBegin:
		return nil
	case token.PHPEnd:
		return nil
	}
	return p.parseTopStmt()
}

func (p *Parser) next() {
	p.idx++
	if len(p.previous) <= p.idx {
		p.current = p.lexer.Next()
		if p.PrintTokens {
			fmt.Println(p.current)
		}
		p.previous = append(p.previous, p.current)
	} else {
		p.current = p.previous[p.idx]
	}

	switch p.current.Typ {
	case token.CommentLine:
		p.currentCommentLines = append(p.currentCommentLines, p.current)
		p.currentCommentBlock = nil
	case token.CommentBlock:
		p.currentCommentLines = nil
		p.currentCommentBlock = &p.current
	default:
		p.currentCommentLines = nil
		p.currentCommentBlock = nil
	}
}

func (p *Parser) backup() {
	p.idx--
	p.current = p.previous[p.idx]
}

func (p *Parser) peek() (i token.Item) {
	p.next()
	i = p.current
	p.backup()
	return
}

func (p *Parser) expectCurrent(i ...token.Token) {
	for _, Typ := range i {
		if p.current.Typ == Typ {
			return
		}
	}
	p.expected(i...)
}

func (p *Parser) expectAndNext(i ...token.Token) {
	defer p.next()
	for _, Typ := range i {
		if p.current.Typ == Typ {
			return
		}
	}
	p.expected(i...)
}

func (p *Parser) expect(i ...token.Token) {
	p.next()
	p.expectCurrent(i...)
}

func (p *Parser) expected(i ...token.Token) {
	p.errorf("Found %s, expected %s", p.current, i)
}

func (p *Parser) accept(i ...token.Token) bool {
	nextTyp := p.peek().Typ
	for _, Typ := range i {
		if nextTyp == Typ {
			p.next()
			return true
		}
	}
	return false
}

func (p *Parser) errorf(str string, args ...interface{}) {
	if len(p.errors) > p.MaxErrors {
		panic("too many errors")
	}
	p.errors = append(p.errors, errorf(p, str, args...))
}

func errorf(p *Parser, str string, args ...interface{}) ParseError {
	e := ParseError{error: fmt.Errorf(str, args...)}
	if p != nil {
		e.File = p.file
		e.Line = p.current.Begin.Line
	}
	return e
}

func (p *Parser) errorPrefix() string {
	return fmt.Sprintf("%d", p.current.Begin.Line)
}

func (p *Parser) parseNextExpression() ast.Expr {
	p.next()
	return p.parseExpression()
}
<commit_msg>adding a hacky way to cancel a running parse that has gone awry<commit_after>package parser

import (
	"bytes"
	"context"
	"fmt"
	"path"

	"github.com/stephens2424/php/ast"
	"github.com/stephens2424/php/lexer"
	"github.com/stephens2424/php/token"
)

// Parser handles scanning through and parsing a PHP source string into an AST. It is configurable
// to have various types of debugging features.
type Parser struct {
	Debug       bool // Debug causes the parser to print all errors to stdout and relay any panic upon internal panic recovery.
	PrintTokens bool // PrintTokens causes the parser to print all tokens received from the lexer to stdout.
	MaxErrors   int  // Indicates the number of errors to allow before triggering a panic. The default is 10.
	FileSet     *ast.FileSet

	lexer      token.Stream
	previous   []token.Item
	idx        int
	current    token.Item
	errors     ParseErrorList
	parenLevel int

	file      *ast.File
	namespace *ast.Namespace
	scope     *ast.Scope

	currentCommentLines []token.Item
	currentCommentBlock *token.Item

	// this option exists to allow parser tests to pass while scope tests may be failing
	disableScoping bool

	instantiation bool

	Ctx context.Context
}

// NewParser readies a parser
func NewParser() *Parser {
	p := &Parser{
		idx:       -1,
		MaxErrors: 10,
		FileSet:   ast.NewFileSet(),
	}
	return p
}

// ParseErrorList is a list of ParseErrors.
type ParseErrorList []ParseError

// Error formats p into a string.
func (p ParseErrorList) Error() string {
	if len(p) == 0 {
		return ""
	}
	if len(p) == 1 {
		return p[0].Error()
	}
	buf := &bytes.Buffer{}
	for _, s := range p[:len(p)-1] {
		buf.WriteString(s.Error())
		buf.WriteString("\n")
	}
	buf.WriteString(p[len(p)-2].Error())
	return buf.String()
}

// ParseError represents an error found during parsing.
type ParseError struct {
	error
	Line, Column int
	File         *ast.File
}

func (p ParseError) Error() string {
	return fmt.Sprintf("%s:%d: %s", p.File.Name, p.Line, p.error)
}

func (p ParseError) String() string {
	return p.Error()
}

// Parse consumes the input string to produce an AST that represents it.
func (p *Parser) Parse(filepath, input string) (file *ast.File, err error) {
	file = &ast.File{Namespace: p.FileSet.GlobalNamespace, Name: path.Base(filepath)}
	p.file = file
	p.scope = p.FileSet.Scope
	p.namespace = p.FileSet.GlobalNamespace
	p.lexer = token.Subset(lexer.NewLexer(input), token.Significant)

	p.FileSet.Files[filepath] = p.file
	defer func() {
		if r := recover(); r != nil {
			err = append(ParseErrorList{errorf(p, "%s", r)}, p.errors...)
			if p.Debug {
				for _, err := range p.errors {
					fmt.Println(err)
				}
				panic(r)
			}
		}
	}()
	// expecting either token.HTML or token.PHPBegin
	p.file.Nodes = make([]ast.Node, 0, 1)
TokenLoop:
	for {
		p.next()
		switch p.current.Typ {
		case token.EOF:
			break TokenLoop
		default:
			n := p.parseNode()
			if n != nil {
				p.file.Nodes = append(p.file.Nodes, n)
			}
		}
	}
	if p.errors != nil {
		err = p.errors
	}
	return
}

func (p *Parser) parseNode() ast.Node {
	switch p.current.Typ {
	case token.HTML:
		return ast.Echo(ast.Literal{Type: ast.String, Value: p.current.Val})
	case token.PHPBegin:
		return nil
	case token.PHPEnd:
		return nil
	}
	return p.parseTopStmt()
}

func (p *Parser) canceled() bool {
	if p.Ctx != nil {
		select {
		case <-p.Ctx.Done():
			return true
		default:
		}
	}
	return false
}

func (p *Parser) next() {
	if p.canceled() {
		panic("canceled")
	}

	p.idx++
	if len(p.previous) <= p.idx {
		p.current = p.lexer.Next()
		if p.PrintTokens {
			fmt.Println(p.current)
		}
		p.previous = append(p.previous, p.current)
	} else {
		p.current = p.previous[p.idx]
	}

	switch p.current.Typ {
	case token.CommentLine:
		p.currentCommentLines = append(p.currentCommentLines, p.current)
		p.currentCommentBlock = nil
	case token.CommentBlock:
		p.currentCommentLines = nil
		p.currentCommentBlock = &p.current
	default:
		p.currentCommentLines = nil
		p.currentCommentBlock = nil
	}
}

func (p *Parser) backup() {
	p.idx--
	p.current = p.previous[p.idx]
}

func (p *Parser) peek() (i token.Item) {
	p.next()
	i = p.current
	p.backup()
	return
}

func (p *Parser) expectCurrent(i ...token.Token) {
	for _, Typ := range i {
		if p.current.Typ == Typ {
			return
		}
	}
	p.expected(i...)
}

func (p *Parser) expectAndNext(i ...token.Token) {
	defer p.next()
	for _, Typ := range i {
		if p.current.Typ == Typ {
			return
		}
	}
	p.expected(i...)
}

func (p *Parser) expect(i ...token.Token) {
	p.next()
	p.expectCurrent(i...)
}

func (p *Parser) expected(i ...token.Token) {
	p.errorf("Found %s, expected %s", p.current, i)
}

func (p *Parser) accept(i ...token.Token) bool {
	nextTyp := p.peek().Typ
	for _, Typ := range i {
		if nextTyp == Typ {
			p.next()
			return true
		}
	}
	return false
}

func (p *Parser) errorf(str string, args ...interface{}) {
	if len(p.errors) > p.MaxErrors {
		panic("too many errors")
	}
	p.errors = append(p.errors, errorf(p, str, args...))
}

func errorf(p *Parser, str string, args ...interface{}) ParseError {
	e := ParseError{error: fmt.Errorf(str, args...)}
	if p != nil {
		e.File = p.file
		e.Line = p.current.Begin.Line
	}
	return e
}

func (p *Parser) errorPrefix() string {
	return fmt.Sprintf("%d", p.current.Begin.Line)
}

func (p *Parser) parseNextExpression() ast.Expr {
	p.next()
	return p.parseExpression()
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/nsf/termbox-go"
	"time"
	"os/user"
	"strconv"
	"strings"
	utils "github.com/nerorevenge/go-samayam/samayUtils"
	parse "github.com/nerorevenge/go-samayam/parseUtils"
	file "github.com/nerorevenge/go-samayam/fileUtils"
	draw "github.com/nerorevenge/go-samayam/drawUtils"
)

// constants
const (
	HSPACE = 1
	HLEN =5
	VSPACE = 2
	VLEN =5
	EXPMAX = 4
	DIRECTORY = ".go-samayam-data"
	FILE = "data.gob"
)

type Insert struct {
	x,y int
	buffer string

}

type Task struct {
	Index int
	TaskString string
	Start time.Time
	End time.Time
	Len int
	Hours int
	Minutes int
	Seconds int
}
// soon to be replaced by linked list
type TaskTree struct {
	Tree []Task
}

func (t *TaskTree) AddTo(x string){
	e := len(t.Tree)
	t.Tree = append(t.Tree,Task{Index:e,TaskString:x,Start:time.Now()})
}

func (t *TaskTree) DeleteFrom(x int){
	e := len(t.Tree)
	if x <= e-1{
		t.Tree = append(t.Tree[:x],t.Tree[x+1:]...) // this part is responsible for the deletion

		for i,_ := range(t.Tree){
			t.Tree[i].Index = i
		}
	}
}

func (t *TaskTree) Edit(index int, newTask string){
	e := len(t.Tree)
	if index <= e-1{
		 t.Tree[index].TaskString = newTask
		}
}

func ( t *Task) DrawTask (x,y,padding int){

	timeStart := []string{}
	timeStart = append(timeStart,[]string{" START "," ----- "}...)
	timeStart = append(timeStart,utils.Formatez(t.Start)...)

	s := [][]string{[]string{strconv.Itoa(t.Index)},[]string{t.TaskString},timeStart}

	if t.End.IsZero(){

		// calculate the time difference compared to time.Now()
		temp := time.Now()
		b:= temp.Sub(t.Start)
		hours := int(b.Hours())
		minutes :=  int(b.Minutes())-60*int(b.Hours())
		seconds := int(b.Seconds())-(3600*hours+60*minutes)

		//------------------------------------------------------

		interval := []string{}
		interval = append(interval,[]string{" INTERVAL "," ----- "}...)
		temp1 := []string{"Seconds :"+strconv.Itoa(seconds), "Minutes :"+strconv.Itoa(minutes), "Hours   :"+strconv.Itoa(hours)}
		interval = append(interval,temp1...)
		s = append(s,interval)
	}else{
		interval := []string{}
		interval = append(interval,[]string{" INTERVAL "," ----- "}...)
		temp1 := []string{"Seconds :"+strconv.Itoa(t.Seconds), "Minutes :"+strconv.Itoa(t.Minutes), "Hours   :"+strconv.Itoa(t.Hours)}
		interval = append(interval,temp1...)
		s = append(s,interval)

		timeStop := []string{}
		timeStop = append(timeStop,[]string{" STOP "," ----- "}...)
		timeStop = append(timeStop,utils.Formatez(t.End)...)
		s = append(s,timeStop)

	}

	endStringArray := utils.CustomFunction(s)
	draw.StringBox(endStringArray,x,y,padding )
	t.Len = len(endStringArray)+2*padding
}

func (t* TaskTree) DrawTree(start int){

	//length := len(t.tree)
	yCounter := 0

	counter := 0
	for i:=start;;i=(i+1)%len(t.Tree){

		if counter > EXPMAX-1 || counter > len(t.Tree)-1 {
			break
		}
		box_x := HSPACE + HLEN
		box_y := VSPACE + yCounter
		t.Tree[i].DrawTask(box_x,box_y,1)
		yCounter += t.Tree[i].Len
		draw.Horizontal(HSPACE,box_y+1,HLEN)
		if counter>0 {
			draw.Vertical(HSPACE,box_y+1-VLEN,t.Tree[i].Len)
		}
		counter++
	}

}

var mainTree TaskTree

func WithinRange (x int) bool {
		if x < len(mainTree.Tree){
			return true
		}
		return false
	}

func act(xs []string, destination string) {

	switch xs[0] {
		case "ADD":
			mainTree.AddTo(strings.Join(xs[1:]," "))
		case "DELETE":
			a ,_:= strconv.Atoi(xs[1])
			mainTree.DeleteFrom(a)
		case "EDIT":
			a, _:=strconv.Atoi(xs[1])
			if !WithinRange(a){
				break
			}
			mainTree.Edit(a,xs[2])
		case "STOP":
			a, _:=strconv.Atoi(xs[1])
			if !WithinRange(a){
				break
			}
			mainTree.Tree[a].End = time.Now()
			b:= mainTree.Tree[a].End.Sub(mainTree.Tree[a].Start)
			mainTree.Tree[a].Hours = int(b.Hours())
			mainTree.Tree[a].Minutes =  int(b.Minutes())-60*int(b.Hours())
			d := mainTree.Tree[a]
			mainTree.Tree[a].Seconds = int(b.Seconds())-(3600*d.Hours+60*d.Minutes)

		case "RESTART":
			a, _:=strconv.Atoi(xs[1])
			if !WithinRange(a){
				break
			}
			var b time.Time
			mainTree.Tree[a].Start = time.Now()
			mainTree.Tree[a].End = b

	}
		file.Put(destination,mainTree)
}

// log file functions and associated variables

func main(){

	errit := termbox.Init()
	defer termbox.Close()
	screenW,screenH := termbox.Size()

	if errit != nil {
		panic(" Trouble somewhere")
	} else {

		file.Check(DIRECTORY,FILE)

		startIndex := 0

		x,_ := user.Current()
		destination := x.HomeDir+"/"+DIRECTORY+"/"+FILE
		file.Get(destination,&mainTree)

		commandbox := draw.BOX{Xstart:HSPACE,Ystart:screenH-VSPACE-3,Width:screenW-HSPACE-1,Height:3}
		ogg := Insert{x:HSPACE+3+len("COMMAND :"),y:screenH-VSPACE-2,buffer:""}

		//----------------- dance of functions starts here--------------------------------------------

		go func(){
			for {
				//termbox.Clear(draw.FG,draw.BG)
				atb := time.Now()
				toDisplay := atb.Format("Jan 2 15:04:05pm ")
				draw.String(toDisplay,screenW-len(toDisplay),VSPACE-2)

				draw.String("COMMAND : ",HSPACE+2,screenH-VSPACE-2)
				draw.String(" [ Press i to enter commands ][ Press h for help ][ Press z to quit ] ",HSPACE+1,screenH-1)

				mainTree.DrawTree(startIndex)
				commandbox.Box()
				termbox.Flush()
				time.Sleep(time.Second)
			}
		}()

		for  {
			termbox.Flush()
			g := termbox.PollEvent()

			if g.Ch == 'z'{
				break
			} else if g.Ch == 'h' {
				termbox.Clear(draw.FG,draw.BG)
				draw.String(" [ Press any button to exit ] ",HSPACE+1,screenH-1)
				draw.String("  ( ADD taskString) || ( DELETE INDEX) || ( EDIT INDEX taskString  )||(STOP INDEX) || ( RESTART INDEX )",HSPACE,int(screenH/2))
				termbox.Flush()
				termbox.PollEvent()
			}else if g.Ch == 'i'{
				for {

					g :=  termbox.PollEvent()
					if  g.Key == termbox.KeyEnter {
						a:= parse.Tokenize(ogg.buffer)
						ogg.buffer = ""
						if parse.Validate(a){
							act(a,destination)
						}
						break
					}else if g.Key == termbox.KeySpace{
							ogg.buffer+=" "
					}else {
						ogg.buffer+=string(g.Ch)
						draw.String(ogg.buffer,ogg.x,ogg.y)
						termbox.Flush()
					}
				    }
			}else if g.Key == termbox.KeyArrowUp {
				if  startIndex > 0 {
					startIndex= (startIndex-1)%len(mainTree.Tree)
				} else {
					startIndex = len(mainTree.Tree)-1
				}
			}else if g.Key == termbox.KeyArrowDown {
				startIndex= (startIndex+1)%len(mainTree.Tree)
			}

			termbox.Clear(draw.FG,draw.BG)
		}
	}

}

<commit_msg>fixed help screen issues due to go-routine mischief<commit_after>package main

import (
	"github.com/nsf/termbox-go"
	"time"
	"os/user"
	"strconv"
	"strings"
	utils "github.com/nerorevenge/go-samayam/samayUtils"
	parse "github.com/nerorevenge/go-samayam/parseUtils"
	file "github.com/nerorevenge/go-samayam/fileUtils"
	draw "github.com/nerorevenge/go-samayam/drawUtils"
)

// constants
const (
	HSPACE = 1
	HLEN =5
	VSPACE = 2
	VLEN =5
	EXPMAX = 4
	DIRECTORY = ".go-samayam-data"
	FILE = "data.gob"
)

type Insert struct {
	x,y int
	buffer string

}

type Task struct {
	Index int
	TaskString string
	Start time.Time
	End time.Time
	Len int
	Hours int
	Minutes int
	Seconds int
}
// soon to be replaced by linked list
type TaskTree struct {
	Tree []Task
}

func (t *TaskTree) AddTo(x string){
	e := len(t.Tree)
	t.Tree = append(t.Tree,Task{Index:e,TaskString:x,Start:time.Now()})
}

func (t *TaskTree) DeleteFrom(x int){
	e := len(t.Tree)
	if x <= e-1{
		t.Tree = append(t.Tree[:x],t.Tree[x+1:]...) // this part is responsible for the deletion

		for i,_ := range(t.Tree){
			t.Tree[i].Index = i
		}
	}
}

func (t *TaskTree) Edit(index int, newTask string){
	e := len(t.Tree)
	if index <= e-1{
		 t.Tree[index].TaskString = newTask
		}
}

func ( t *Task) DrawTask (x,y,padding int){

	timeStart := []string{}
	timeStart = append(timeStart,[]string{" START "," ----- "}...)
	timeStart = append(timeStart,utils.Formatez(t.Start)...)

	s := [][]string{[]string{strconv.Itoa(t.Index)},[]string{t.TaskString},timeStart}

	if t.End.IsZero(){

		// calculate the time difference compared to time.Now()
		temp := time.Now()
		b:= temp.Sub(t.Start)
		hours := int(b.Hours())
		minutes :=  int(b.Minutes())-60*int(b.Hours())
		seconds := int(b.Seconds())-(3600*hours+60*minutes)

		//------------------------------------------------------

		interval := []string{}
		interval = append(interval,[]string{" INTERVAL "," ----- "}...)
		temp1 := []string{"Seconds :"+strconv.Itoa(seconds), "Minutes :"+strconv.Itoa(minutes), "Hours   :"+strconv.Itoa(hours)}
		interval = append(interval,temp1...)
		s = append(s,interval)
	}else{
		interval := []string{}
		interval = append(interval,[]string{" INTERVAL "," ----- "}...)
		temp1 := []string{"Seconds :"+strconv.Itoa(t.Seconds), "Minutes :"+strconv.Itoa(t.Minutes), "Hours   :"+strconv.Itoa(t.Hours)}
		interval = append(interval,temp1...)
		s = append(s,interval)

		timeStop := []string{}
		timeStop = append(timeStop,[]string{" STOP "," ----- "}...)
		timeStop = append(timeStop,utils.Formatez(t.End)...)
		s = append(s,timeStop)

	}

	endStringArray := utils.CustomFunction(s)
	draw.StringBox(endStringArray,x,y,padding )
	t.Len = len(endStringArray)+2*padding
}

func (t* TaskTree) DrawTree(start int){

	//length := len(t.tree)
	yCounter := 0

	counter := 0
	for i:=start;;i=(i+1)%len(t.Tree){

		if counter > EXPMAX-1 || counter > len(t.Tree)-1 {
			break
		}
		box_x := HSPACE + HLEN
		box_y := VSPACE + yCounter
		t.Tree[i].DrawTask(box_x,box_y,1)
		yCounter += t.Tree[i].Len
		draw.Horizontal(HSPACE,box_y+1,HLEN)
		if counter>0 {
			draw.Vertical(HSPACE,box_y+1-VLEN,t.Tree[i].Len)
		}
		counter++
	}

}

var mainTree TaskTree

func WithinRange (x int) bool {
		if x < len(mainTree.Tree){
			return true
		}
		return false
	}

func act(xs []string, destination string) {

	switch xs[0] {
		case "ADD":
			mainTree.AddTo(strings.Join(xs[1:]," "))
		case "DELETE":
			a ,_:= strconv.Atoi(xs[1])
			mainTree.DeleteFrom(a)
		case "EDIT":
			a, _:=strconv.Atoi(xs[1])
			if !WithinRange(a){
				break
			}
			mainTree.Edit(a,xs[2])
		case "STOP":
			a, _:=strconv.Atoi(xs[1])
			if !WithinRange(a){
				break
			}
			mainTree.Tree[a].End = time.Now()
			b:= mainTree.Tree[a].End.Sub(mainTree.Tree[a].Start)
			mainTree.Tree[a].Hours = int(b.Hours())
			mainTree.Tree[a].Minutes =  int(b.Minutes())-60*int(b.Hours())
			d := mainTree.Tree[a]
			mainTree.Tree[a].Seconds = int(b.Seconds())-(3600*d.Hours+60*d.Minutes)

		case "RESTART":
			a, _:=strconv.Atoi(xs[1])
			if !WithinRange(a){
				break
			}
			var b time.Time
			mainTree.Tree[a].Start = time.Now()
			mainTree.Tree[a].End = b

	}
		file.Put(destination,mainTree)
}

// log file functions and associated variables

func main(){

	errit := termbox.Init()
	defer termbox.Close()
	screenW,screenH := termbox.Size()

	if errit != nil {
		panic(" Trouble somewhere")
	} else {

		file.Check(DIRECTORY,FILE)

		startIndex := 0

		x,_ := user.Current()
		destination := x.HomeDir+"/"+DIRECTORY+"/"+FILE
		file.Get(destination,&mainTree)

		commandbox := draw.BOX{Xstart:HSPACE,Ystart:screenH-VSPACE-3,Width:screenW-HSPACE-1,Height:3}
		ogg := Insert{x:HSPACE+3+len("COMMAND :"),y:screenH-VSPACE-2,buffer:""}

		// various channels

		hideUnhide := make(chan int,1)

		//----------------- dance of functions starts here--------------------------------------------

		go func(){
			for {
				//termbox.Clear(draw.FG,draw.BG)
				atb := time.Now()
				toDisplay := atb.Format("Jan 2 15:04:05pm ")
				draw.String(toDisplay,screenW-len(toDisplay),VSPACE-2)
				termbox.Flush()
				time.Sleep(time.Second)
			}
		}()

		go func(){

			for {
				select {

				case <- hideUnhide:
					<-hideUnhide // blocking action
				default:
					draw.String("COMMAND : ",HSPACE+2,screenH-VSPACE-2)
					draw.String(" [ Press i to enter commands ][ Press h for help ][ Press z to quit ] ",HSPACE+1,screenH-1)
					mainTree.DrawTree(startIndex)
					commandbox.Box()
					termbox.Flush()
					time.Sleep(100*time.Millisecond)

				}
			}
		}()

		for  {
			termbox.Flush()
			g := termbox.PollEvent()

			if g.Ch == 'z'{
				break
			} else if g.Ch == 'h' {
				termbox.Clear(draw.FG,draw.BG) // clears the screen to display options
				hideUnhide <- 3 // the value here doesn't matter

				draw.String(" [ Press any button to exit ] ",HSPACE+1,screenH-1)
				draw.String("  ( ADD taskString) || ( DELETE INDEX) || ( EDIT INDEX taskString  )||(STOP INDEX) || ( RESTART INDEX )",HSPACE,int(screenH/2))
				termbox.Flush()
				termbox.PollEvent()

				hideUnhide <-3

			}else if g.Ch == 'i'{
				for {

					g :=  termbox.PollEvent()
					if  g.Key == termbox.KeyEnter {
						a:= parse.Tokenize(ogg.buffer)
						ogg.buffer = ""
						if parse.Validate(a){
							act(a,destination)
						}
						break
					}else if g.Key == termbox.KeySpace{
							ogg.buffer+=" "
					}else {
						ogg.buffer+=string(g.Ch)
						draw.String(ogg.buffer,ogg.x,ogg.y)
						termbox.Flush()
					}
				    }
			}else if g.Key == termbox.KeyArrowUp {
				if  startIndex > 0 {
					startIndex= (startIndex-1)%len(mainTree.Tree)
				} else {
					startIndex = len(mainTree.Tree)-1
				}
			}else if g.Key == termbox.KeyArrowDown {
				startIndex= (startIndex+1)%len(mainTree.Tree)
			}

			termbox.Clear(draw.FG,draw.BG)
		}
	}

}

<|endoftext|>


<commit_before>package main

import (
	"github.com/nsf/termbox-go"
	"time"
	"os/user"
	"strconv"
	"fmt"
	"strings"
	utils "github.com/nerorevenge/go-samayam/samayUtils"
	parse "github.com/nerorevenge/go-samayam/parseUtils"
	file "github.com/nerorevenge/go-samayam/fileUtils"
	draw "github.com/nerorevenge/go-samayam/drawUtils"
)

// constants
const (
	H_SPACE = 1
	H_LEN =5
	V_SPACE = 2
	V_LEN =5
	EXPERIMENTAL_MAX = 4
	DIRECTORY = ".go-samayam-data"
	FILE = "data.gob"
)

type INSERT struct {
	x,y int
	buffer string

}

type TASK struct {
	Index int
	Task string
	Start time.Time
	End time.Time
	Len int
}
// soon to be replaced by linked list
type TASK_TREE struct {
	Tree []TASK
}

func (t *TASK_TREE) add_to(x string){
	e := len(t.Tree)
	t.Tree = append(t.Tree,TASK{Index:e,Task:x,Start:time.Now()})
}

func (t *TASK_TREE) deleteFrom(x int){
	e := len(t.Tree)
	if x <= e-1{
		t.Tree = append(t.Tree[:x],t.Tree[x+1:]...)

		for i,_ := range(t.Tree){
			t.Tree[i].Index = i
		}
	}
}

func (t *TASK_TREE) edit(index int, newTask string){
	e := len(t.Tree)
	if index <= e-1{
		 t.Tree[index].Task = newTask
		}
}

func ( t *TASK) draw_task (x,y,padding int){

	time_start := []string{}
	time_start = append(time_start,[]string{" START "," ----- "}...)
	time_start = append(time_start,utils.Formatez(t.Start)...)

	s := [][]string{[]string{strconv.Itoa(t.Index)},[]string{t.Task},time_start}

	end_string_array := utils.CustomFunction(s)
	draw.StringBox(end_string_array,x,y,padding )
	t.Len = len(end_string_array)+2*padding
}

func (t* TASK_TREE) DrawTree(start int){

	//length := len(t.tree)
	yCounter := 0

	counter := 0
	for i:=start;i<len(t.Tree);i++{

		if counter > EXPERIMENTAL_MAX-1 {
			break
		}
		box_x := H_SPACE + H_LEN
		box_y := V_SPACE + yCounter
		t.Tree[i].draw_task(box_x,box_y,1)
		yCounter += t.Tree[i].Len
		draw.Horizontal(H_SPACE,box_y+1,H_LEN)
		if i>start {
			draw.Vertical(H_SPACE,box_y+1-V_LEN,t.Tree[i].Len)
		}
		counter++
	}

}

var main_tree TASK_TREE

func act(xs []string, destination string) {
	switch xs[0] {
		case "ADD":
			main_tree.add_to(strings.Join(xs[1:]," "))
			file.Put(destination,main_tree)
		case "DELETE":
			a ,_:= strconv.Atoi(xs[1])
			main_tree.deleteFrom(a)
			file.Put(destination,main_tree)
		case "EDIT":
			a, _:=strconv.Atoi(xs[1])
			main_tree.edit(a,xs[2])
	}
}

// log file functions and associated variables

func main(){

	errit := termbox.Init()
	defer termbox.Close()
	screen_w,screen_h := termbox.Size()

	if errit != nil {
		panic(" Trouble somewhere")
	} else {
		//x := BOX{width:20,x_start:3,y_start:3,height:20}
		//x.draw_mainbox()
		file.Check(DIRECTORY,FILE)

		start_index := 0

		x,_ := user.Current()
		destination := x.HomeDir+"/"+DIRECTORY+"/"+FILE
		file.Get(destination,&main_tree)
		fmt.Println(main_tree.Tree)
		for  {
			main_tree.DrawTree(start_index)

			commandbox := draw.BOX{X_start:H_SPACE,Y_start:screen_h-V_SPACE-3,Width:screen_w-H_SPACE-1,Height:3}
			commandbox.Box()
			draw.String("COMMAND : ",H_SPACE+2,screen_h-V_SPACE-2)
			draw.String(" [ Press i to enter commands ][ Press h for help ][ Press z to quit ] ",H_SPACE+1,screen_h-1)
			termbox.Flush()
			g := termbox.PollEvent()
			ogg := INSERT{x:H_SPACE+2+len("COMMAND :"),y:screen_h-V_SPACE-2,buffer:""}
			if g.Ch == 'z'{
				break
			} else if g.Ch == 'i'{
				for {

					g :=  termbox.PollEvent()
					if  g.Key == termbox.KeyEnter {
						a:= parse.Tokenize(ogg.buffer)
						if parse.Validate(a){
							act(a,destination)
						}
						break
					}else if g.Key == termbox.KeySpace{
							ogg.buffer+=" "
					}else {
						ogg.buffer+=string(g.Ch)
						draw.String(ogg.buffer,ogg.x,ogg.y)
						termbox.Flush()
					}
				    }
			}else if g.Key == termbox.KeyArrowDown {
				start_index= (start_index+1)%len(main_tree.Tree)

			}
			termbox.Clear(draw.FG,draw.BG)
		}
	}

}

<commit_msg> added functions such as STOP,RESTART<commit_after>package main

import (
	"github.com/nsf/termbox-go"
	"time"
	"os/user"
	"strconv"
	"fmt"
	"strings"
	utils "github.com/nerorevenge/go-samayam/samayUtils"
	parse "github.com/nerorevenge/go-samayam/parseUtils"
	file "github.com/nerorevenge/go-samayam/fileUtils"
	draw "github.com/nerorevenge/go-samayam/drawUtils"
)

// constants
const (
	H_SPACE = 1
	H_LEN =5
	V_SPACE = 2
	V_LEN =5
	EXPERIMENTAL_MAX = 4
	DIRECTORY = ".go-samayam-data"
	FILE = "data.gob"
)

type INSERT struct {
	x,y int
	buffer string

}

type TASK struct {
	Index int
	Task string
	Start time.Time
	End time.Time
	Len int
	Hours int
	Minutes int
	Seconds int
}
// soon to be replaced by linked list
type TASK_TREE struct {
	Tree []TASK
}

func (t *TASK_TREE) add_to(x string){
	e := len(t.Tree)
	t.Tree = append(t.Tree,TASK{Index:e,Task:x,Start:time.Now()})
}

func (t *TASK_TREE) deleteFrom(x int){
	e := len(t.Tree)
	if x <= e-1{
		t.Tree = append(t.Tree[:x],t.Tree[x+1:]...)

		for i,_ := range(t.Tree){
			t.Tree[i].Index = i
		}
	}
}

func (t *TASK_TREE) edit(index int, newTask string){
	e := len(t.Tree)
	if index <= e-1{
		 t.Tree[index].Task = newTask
		}
}

func ( t *TASK) stop_task (x,y,padding int){

	time_start := []string{}
	time_start = append(time_start,[]string{" START "," ----- "}...)
	time_start = append(time_start,utils.Formatez(t.Start)...)

	s := [][]string{[]string{strconv.Itoa(t.Index)},[]string{t.Task},time_start}

	end_string_array := utils.CustomFunction(s)
	draw.StringBox(end_string_array,x,y,padding )
	t.Len = len(end_string_array)+2*padding
}

func ( t *TASK) draw_task (x,y,padding int){

	time_start := []string{}
	time_start = append(time_start,[]string{" START "," ----- "}...)
	time_start = append(time_start,utils.Formatez(t.Start)...)

	s := [][]string{[]string{strconv.Itoa(t.Index)},[]string{t.Task},time_start}

	if !t.End.IsZero(){
		time_stop := []string{}
		time_stop = append(time_stop,[]string{" STOP "," ----- "}...)
		time_stop = append(time_stop,utils.Formatez(t.End)...)
		s = append(s,time_stop)

		interval := []string{}
		interval = append(interval,[]string{" INTERVAL "," ----- "}...)
		temp := []string{"Seconds :"+strconv.Itoa(t.Seconds), "Minutes :"+strconv.Itoa(t.Minutes), "Hours   :"+strconv.Itoa(t.Hours)}
		interval = append(interval,temp...)
		s = append(s,interval)
	}

	end_string_array := utils.CustomFunction(s)
	draw.StringBox(end_string_array,x,y,padding )
	t.Len = len(end_string_array)+2*padding
}

func (t* TASK_TREE) DrawTree(start int){

	//length := len(t.tree)
	yCounter := 0

	counter := 0
	for i:=start;i<len(t.Tree);i++{

		if counter > EXPERIMENTAL_MAX-1 {
			break
		}
		box_x := H_SPACE + H_LEN
		box_y := V_SPACE + yCounter
		t.Tree[i].draw_task(box_x,box_y,1)
		yCounter += t.Tree[i].Len
		draw.Horizontal(H_SPACE,box_y+1,H_LEN)
		if i>start {
			draw.Vertical(H_SPACE,box_y+1-V_LEN,t.Tree[i].Len)
		}
		counter++
	}

}

var main_tree TASK_TREE

func act(xs []string, destination string) {
	switch xs[0] {
		case "ADD":
			main_tree.add_to(strings.Join(xs[1:]," "))
		case "DELETE":
			a ,_:= strconv.Atoi(xs[1])
			main_tree.deleteFrom(a)
		case "EDIT":
			a, _:=strconv.Atoi(xs[1])
			main_tree.edit(a,xs[2])
		case "STOP":
			a, _:=strconv.Atoi(xs[1])
			main_tree.Tree[a].End = time.Now()
			b:= main_tree.Tree[a].End.Sub(main_tree.Tree[a].Start)
			main_tree.Tree[a].Hours = int(b.Hours())
			main_tree.Tree[a].Minutes =  int(b.Minutes())-60*int(b.Hours())
			d := main_tree.Tree[a]
			main_tree.Tree[a].Seconds = int(b.Seconds())-(3600*d.Hours+60*d.Minutes)

		case "RESTART":
			a, _:=strconv.Atoi(xs[1])
			var b time.Time
			main_tree.Tree[a].Start = time.Now()
			main_tree.Tree[a].End = b

	}
		file.Put(destination,main_tree)
}

// log file functions and associated variables

func main(){

	errit := termbox.Init()
	defer termbox.Close()
	screen_w,screen_h := termbox.Size()

	if errit != nil {
		panic(" Trouble somewhere")
	} else {
		//x := BOX{width:20,x_start:3,y_start:3,height:20}
		//x.draw_mainbox()
		file.Check(DIRECTORY,FILE)

		start_index := 0

		x,_ := user.Current()
		destination := x.HomeDir+"/"+DIRECTORY+"/"+FILE
		file.Get(destination,&main_tree)
		fmt.Println(main_tree.Tree)
		for  {
			main_tree.DrawTree(start_index)

			commandbox := draw.BOX{X_start:H_SPACE,Y_start:screen_h-V_SPACE-3,Width:screen_w-H_SPACE-1,Height:3}
			commandbox.Box()
			draw.String("COMMAND : ",H_SPACE+2,screen_h-V_SPACE-2)
			draw.String(" [ Press i to enter commands ][ Press h for help ][ Press z to quit ] ",H_SPACE+1,screen_h-1)
			termbox.Flush()
			g := termbox.PollEvent()
			ogg := INSERT{x:H_SPACE+2+len("COMMAND :"),y:screen_h-V_SPACE-2,buffer:""}
			if g.Ch == 'z'{
				break
			} else if g.Ch == 'i'{
				for {

					g :=  termbox.PollEvent()
					if  g.Key == termbox.KeyEnter {
						a:= parse.Tokenize(ogg.buffer)
						if parse.Validate(a){
							act(a,destination)
						}
						break
					}else if g.Key == termbox.KeySpace{
							ogg.buffer+=" "
					}else {
						ogg.buffer+=string(g.Ch)
						draw.String(ogg.buffer,ogg.x,ogg.y)
						termbox.Flush()
					}
				    }
			}else if g.Key == termbox.KeyArrowDown {
				start_index= (start_index+1)%len(main_tree.Tree)

			}
			termbox.Clear(draw.FG,draw.BG)
		}
	}

}

<|endoftext|>


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

package stackdriver_trace

import (
	"net/http"
	"code.cloudfoundry.org/lager"
	"gcp-service-broker/brokerapi/brokers/broker_base"
	"gcp-service-broker/brokerapi/brokers/models"
)

type StackdriverTraceBroker struct {
	Client    *http.Client
	ProjectId string
	Logger    lager.Logger
	broker_base.BrokerBase
}

type InstanceInformation struct {
}

// Creates a service account for Stackdriver Trace
func (b *StackdriverTraceBroker) Provision(instanceId string, details models.ProvisionDetails, plan models.PlanDetails) (models.ServiceInstanceDetails, error) {
	return models.ServiceInstanceDetails{}, nil
}

// Deletes the topic associated with the given instanceID
func (b *StackdriverTraceBroker) Deprovision(instanceID string, details models.DeprovisionDetails) error {
	return nil
}

func (b *StackdriverTraceBroker) Bind(instanceID, bindingID string, details models.BindDetails) (models.ServiceBindingCredentials, error) {
	if details.Parameters == nil {
		b.Logger.Info("the parameters are nil!")
		details.Parameters = make(map[string]interface{})
	}
	details.Parameters["role"] = "editor"
	return b.BrokerBase.Bind(instanceID, bindingID, details)
}
<commit_msg>narrow the trace role<commit_after>// Copyright the Service Broker Project Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
//

package stackdriver_trace

import (
	"net/http"
	"code.cloudfoundry.org/lager"
	"gcp-service-broker/brokerapi/brokers/broker_base"
	"gcp-service-broker/brokerapi/brokers/models"
)

type StackdriverTraceBroker struct {
	Client    *http.Client
	ProjectId string
	Logger    lager.Logger
	broker_base.BrokerBase
}

type InstanceInformation struct {
}

// Creates a service account for Stackdriver Trace
func (b *StackdriverTraceBroker) Provision(instanceId string, details models.ProvisionDetails, plan models.PlanDetails) (models.ServiceInstanceDetails, error) {
	return models.ServiceInstanceDetails{}, nil
}

// Deletes the topic associated with the given instanceID
func (b *StackdriverTraceBroker) Deprovision(instanceID string, details models.DeprovisionDetails) error {
	return nil
}

func (b *StackdriverTraceBroker) Bind(instanceID, bindingID string, details models.BindDetails) (models.ServiceBindingCredentials, error) {
	if details.Parameters == nil {
		b.Logger.Info("the parameters are nil!")
		details.Parameters = make(map[string]interface{})
	}
	details.Parameters["role"] = "cloudtrace.agent"
	return b.BrokerBase.Bind(instanceID, bindingID, details)
}
<|endoftext|>