<commit_before>/*
Copyright 2015 Juniper Networks, Inc. All rights reserved.

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 app

import (
	"time"

	"github.com/golang/glog"
	flag "github.com/spf13/pflag"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"

	"github.com/Juniper/contrail-kubernetes/pkg/network"
)

type Config struct {
	KubeUrl      string
	ResyncPeriod time.Duration
}

type NetworkManager struct {
	config Config

	Client     *client.Client
	Controller network.NetworkController

	PodStore    cache.Store
	PodInformer *framework.Controller

	NamespaceStore    cache.Store
	NamespaceInformer *framework.Controller

	RCStore    cache.Store
	RCInformer *framework.Controller

	ServiceStore    cache.Store
	ServiceInformer *framework.Controller

	Shutdown chan struct{}
}

func NewNetworkManager() *NetworkManager {
	manager := new(NetworkManager)
	manager.config = Config{
		KubeUrl:      "http://localhost:8080",
		ResyncPeriod: time.Minute,
	}
	manager.Shutdown = make(chan struct{})
	return manager
}

func (m *NetworkManager) AddFlags(fs *flag.FlagSet) {
	fs.StringVar(&m.config.KubeUrl, "master", m.config.KubeUrl,
		"Kubernetes API endpoint")
}

func (m *NetworkManager) start(args []string) {
	config := &client.Config{
		Host: m.config.KubeUrl,
	}
	var err error
	m.Client, err = client.New(config)
	if err != nil {
		glog.Fatalf("Invalid API configuratin: %v", err)
	}

	m.Controller = network.NewNetworkFactory().Create(m.Client, args)

	m.PodStore, m.PodInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			m.Client,
			string(api.ResourcePods),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.Pod{},
		m.config.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				m.Controller.AddPod(obj.(*api.Pod))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				m.Controller.UpdatePod(
					oldObj.(*api.Pod), newObj.(*api.Pod))
			},
			DeleteFunc: func(obj interface{}) {
				if pod, ok := obj.(*api.Pod); ok {
					m.Controller.DeletePod(pod)
				}
			},
		},
	)

	// m.NamespaceStore, m.NamespaceInformer = framework.NewInformer(
	// 	cache.NewListWatchFromClient(
	// 		m.Client,
	// 		"namespaces",
	// 		api.NamespaceAll,
	// 		fields.Everything(),
	// 	),
	// 	&api.Namespace{},
	// 	m.config.ResyncPeriod,
	// 	framework.ResourceEventHandlerFuncs{
	// 		AddFunc: func(obj interface{}) {
	// 			m.Controller.AddNamespace(
	// 				obj.(*api.Namespace))
	// 		},
	// 		UpdateFunc: func(oldObj, newObj interface{}) {
	// 			m.Controller.UpdateNamespace(
	// 				oldObj.(*api.Namespace),
	// 				newObj.(*api.Namespace))
	// 		},
	// 		DeleteFunc: func(obj interface{}) {
	// 			if namespace, ok := obj.(*api.Namespace); ok {
	// 				m.Controller.DeleteNamespace(namespace)
	// 			}
	// 		},
	// 	},
	// )

	m.RCStore, m.RCInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			m.Client,
			string(api.ResourceReplicationControllers),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.ReplicationController{},
		m.config.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				m.Controller.AddReplicationController(
					obj.(*api.ReplicationController))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				m.Controller.UpdateReplicationController(
					oldObj.(*api.ReplicationController),
					newObj.(*api.ReplicationController))
			},
			DeleteFunc: func(obj interface{}) {
				if rc, ok := obj.(*api.ReplicationController); ok {
					m.Controller.DeleteReplicationController(rc)
				}
			},
		},
	)

	m.ServiceStore, m.ServiceInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			m.Client,
			string(api.ResourceServices),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.Service{},
		m.config.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				m.Controller.AddService(
					obj.(*api.Service))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				m.Controller.UpdateService(
					oldObj.(*api.Service),
					newObj.(*api.Service))
			},
			DeleteFunc: func(obj interface{}) {
				if service, ok := obj.(*api.Service); ok {
					m.Controller.DeleteService(service)
				}
			},
		},
	)

	m.Controller.SetPodStore(m.PodStore)
	m.Controller.SetNamespaceStore(m.NamespaceStore)
	m.Controller.SetReplicationControllerStore(m.RCStore)
	m.Controller.SetServiceStore(m.ServiceStore)
}

func (m *NetworkManager) Run(args []string) error {
	m.start(args)
	go m.PodInformer.Run(m.Shutdown)
	// go m.NamespaceInformer.Run(m.Shutdown)
	go m.RCInformer.Run(m.Shutdown)
	go m.ServiceInformer.Run(m.Shutdown)
	go m.Controller.Run(m.Shutdown)
	select {}
}
<commit_msg>Uncomment namespace support<commit_after>/*
Copyright 2015 Juniper Networks, Inc. All rights reserved.

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 app

import (
	"time"

	"github.com/golang/glog"
	flag "github.com/spf13/pflag"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"

	"github.com/Juniper/contrail-kubernetes/pkg/network"
)

type Config struct {
	KubeUrl      string
	ResyncPeriod time.Duration
}

type NetworkManager struct {
	config Config

	Client     *client.Client
	Controller network.NetworkController

	PodStore    cache.Store
	PodInformer *framework.Controller

	NamespaceStore    cache.Store
	NamespaceInformer *framework.Controller

	RCStore    cache.Store
	RCInformer *framework.Controller

	ServiceStore    cache.Store
	ServiceInformer *framework.Controller

	Shutdown chan struct{}
}

func NewNetworkManager() *NetworkManager {
	manager := new(NetworkManager)
	manager.config = Config{
		KubeUrl:      "http://localhost:8080",
		ResyncPeriod: time.Minute,
	}
	manager.Shutdown = make(chan struct{})
	return manager
}

func (m *NetworkManager) AddFlags(fs *flag.FlagSet) {
	fs.StringVar(&m.config.KubeUrl, "master", m.config.KubeUrl,
		"Kubernetes API endpoint")
}

func (m *NetworkManager) start(args []string) {
	config := &client.Config{
		Host: m.config.KubeUrl,
	}
	var err error
	m.Client, err = client.New(config)
	if err != nil {
		glog.Fatalf("Invalid API configuratin: %v", err)
	}

	m.Controller = network.NewNetworkFactory().Create(m.Client, args)

	m.PodStore, m.PodInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			m.Client,
			string(api.ResourcePods),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.Pod{},
		m.config.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				m.Controller.AddPod(obj.(*api.Pod))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				m.Controller.UpdatePod(
					oldObj.(*api.Pod), newObj.(*api.Pod))
			},
			DeleteFunc: func(obj interface{}) {
				if pod, ok := obj.(*api.Pod); ok {
					m.Controller.DeletePod(pod)
				}
			},
		},
	)

	m.NamespaceStore, m.NamespaceInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			m.Client,
			"namespaces",
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.Namespace{},
		m.config.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				m.Controller.AddNamespace(
					obj.(*api.Namespace))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				m.Controller.UpdateNamespace(
					oldObj.(*api.Namespace),
					newObj.(*api.Namespace))
			},
			DeleteFunc: func(obj interface{}) {
				if namespace, ok := obj.(*api.Namespace); ok {
					m.Controller.DeleteNamespace(namespace)
				}
			},
		},
	)

	m.RCStore, m.RCInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			m.Client,
			string(api.ResourceReplicationControllers),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.ReplicationController{},
		m.config.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				m.Controller.AddReplicationController(
					obj.(*api.ReplicationController))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				m.Controller.UpdateReplicationController(
					oldObj.(*api.ReplicationController),
					newObj.(*api.ReplicationController))
			},
			DeleteFunc: func(obj interface{}) {
				if rc, ok := obj.(*api.ReplicationController); ok {
					m.Controller.DeleteReplicationController(rc)
				}
			},
		},
	)

	m.ServiceStore, m.ServiceInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			m.Client,
			string(api.ResourceServices),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.Service{},
		m.config.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				m.Controller.AddService(
					obj.(*api.Service))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				m.Controller.UpdateService(
					oldObj.(*api.Service),
					newObj.(*api.Service))
			},
			DeleteFunc: func(obj interface{}) {
				if service, ok := obj.(*api.Service); ok {
					m.Controller.DeleteService(service)
				}
			},
		},
	)

	m.Controller.SetPodStore(m.PodStore)
	m.Controller.SetNamespaceStore(m.NamespaceStore)
	m.Controller.SetReplicationControllerStore(m.RCStore)
	m.Controller.SetServiceStore(m.ServiceStore)
}

func (m *NetworkManager) Run(args []string) error {
	m.start(args)
	go m.PodInformer.Run(m.Shutdown)
	go m.NamespaceInformer.Run(m.Shutdown)
	go m.RCInformer.Run(m.Shutdown)
	go m.ServiceInformer.Run(m.Shutdown)
	go m.Controller.Run(m.Shutdown)
	select {}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Juniper Networks, Inc. All rights reserved.

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 app

import (
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	"github.com/golang/glog"

	"github.com/Juniper/contrail-kubernetes/pkg/network"
)

type NetworkManager struct {
	Client     *client.Client
	Controller network.NetworkController

	ResyncPeriod time.Duration

	PodStore    cache.Store
	PodInformer *framework.Controller

	NamespaceStore    cache.Store
	NamespaceInformer *framework.Controller

	RCStore    cache.Store
	RCInformer *framework.Controller

	ServiceStore    cache.Store
	ServiceInformer *framework.Controller

	Shutdown chan struct{}
}

func NewNetworkManager() *NetworkManager {
	config := &client.Config{
		Host: "http://localhost:8080",
	}
	manager := new(NetworkManager)
	var err error
	manager.Client, err = client.New(config)
	if err != nil {
		glog.Fatalf("Invalid API configuratin: %v", err)
	}

	manager.Controller = network.NewNetworkFactory(manager.Client).Create()
	manager.Shutdown = make(chan struct{})
	manager.ResyncPeriod = time.Minute

	manager.PodStore, manager.PodInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			manager.Client,
			string(api.ResourcePods),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.Pod{},
		manager.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				manager.Controller.AddPod(obj.(*api.Pod))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				manager.Controller.UpdatePod(
					oldObj.(*api.Pod), newObj.(*api.Pod))
			},
			DeleteFunc: func(obj interface{}) {
				manager.Controller.DeletePod(obj.(*api.Pod))
			},
		},
	)
	manager.Controller.SetPodStore(&manager.PodStore)

	manager.NamespaceStore, manager.NamespaceInformer =
		framework.NewInformer(
			cache.NewListWatchFromClient(
				manager.Client,
				"namespaces",
				api.NamespaceAll,
				fields.Everything(),
			),
			&api.Namespace{},
			manager.ResyncPeriod,
			framework.ResourceEventHandlerFuncs{
				AddFunc: func(obj interface{}) {
					manager.Controller.AddNamespace(
						obj.(*api.Namespace))
				},
				UpdateFunc: func(oldObj, newObj interface{}) {
					manager.Controller.UpdateNamespace(
						oldObj.(*api.Namespace),
						newObj.(*api.Namespace))
				},
				DeleteFunc: func(obj interface{}) {
					manager.Controller.DeleteNamespace(
						obj.(*api.Namespace))
				},
			},
		)
	manager.Controller.SetNamespaceStore(&manager.NamespaceStore)

	manager.RCStore, manager.RCInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			manager.Client,
			string(api.ResourceReplicationControllers),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.ReplicationController{},
		manager.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				manager.Controller.AddReplicationController(
					obj.(*api.ReplicationController))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				manager.Controller.UpdateReplicationController(
					oldObj.(*api.ReplicationController),
					newObj.(*api.ReplicationController))
			},
			DeleteFunc: func(obj interface{}) {
				manager.Controller.DeleteReplicationController(
					obj.(*api.ReplicationController))
			},
		},
	)
	manager.Controller.SetReplicationControllerStore(&manager.RCStore)

	manager.ServiceStore, manager.ServiceInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			manager.Client,
			string(api.ResourceServices),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.Service{},
		manager.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				manager.Controller.AddService(
					obj.(*api.Service))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				manager.Controller.UpdateService(
					oldObj.(*api.Service),
					newObj.(*api.Service))
			},
			DeleteFunc: func(obj interface{}) {
				manager.Controller.DeleteService(
					obj.(*api.Service))
			},
		},
	)
	manager.Controller.SetServiceStore(&manager.ServiceStore)

	return manager
}

func (m *NetworkManager) Run(_ []string) error {
	go m.PodInformer.Run(m.Shutdown)
	go m.NamespaceInformer.Run(m.Shutdown)
	go m.RCInformer.Run(m.Shutdown)
	go m.ServiceInformer.Run(m.Shutdown)
	select {}
}
<commit_msg>Run controller<commit_after>/*
Copyright 2015 Juniper Networks, Inc. All rights reserved.

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 app

import (
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	"github.com/golang/glog"

	"github.com/Juniper/contrail-kubernetes/pkg/network"
)

type NetworkManager struct {
	Client     *client.Client
	Controller network.NetworkController

	ResyncPeriod time.Duration

	PodStore    cache.Store
	PodInformer *framework.Controller

	NamespaceStore    cache.Store
	NamespaceInformer *framework.Controller

	RCStore    cache.Store
	RCInformer *framework.Controller

	ServiceStore    cache.Store
	ServiceInformer *framework.Controller

	Shutdown chan struct{}
}

func NewNetworkManager() *NetworkManager {
	config := &client.Config{
		Host: "http://localhost:8080",
	}
	manager := new(NetworkManager)
	var err error
	manager.Client, err = client.New(config)
	if err != nil {
		glog.Fatalf("Invalid API configuratin: %v", err)
	}

	manager.Controller = network.NewNetworkFactory(manager.Client).Create()
	manager.Shutdown = make(chan struct{})
	manager.ResyncPeriod = time.Minute

	manager.PodStore, manager.PodInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			manager.Client,
			string(api.ResourcePods),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.Pod{},
		manager.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				manager.Controller.AddPod(obj.(*api.Pod))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				manager.Controller.UpdatePod(
					oldObj.(*api.Pod), newObj.(*api.Pod))
			},
			DeleteFunc: func(obj interface{}) {
				manager.Controller.DeletePod(obj.(*api.Pod))
			},
		},
	)
	manager.Controller.SetPodStore(&manager.PodStore)

	manager.NamespaceStore, manager.NamespaceInformer =
		framework.NewInformer(
			cache.NewListWatchFromClient(
				manager.Client,
				"namespaces",
				api.NamespaceAll,
				fields.Everything(),
			),
			&api.Namespace{},
			manager.ResyncPeriod,
			framework.ResourceEventHandlerFuncs{
				AddFunc: func(obj interface{}) {
					manager.Controller.AddNamespace(
						obj.(*api.Namespace))
				},
				UpdateFunc: func(oldObj, newObj interface{}) {
					manager.Controller.UpdateNamespace(
						oldObj.(*api.Namespace),
						newObj.(*api.Namespace))
				},
				DeleteFunc: func(obj interface{}) {
					manager.Controller.DeleteNamespace(
						obj.(*api.Namespace))
				},
			},
		)
	manager.Controller.SetNamespaceStore(&manager.NamespaceStore)

	manager.RCStore, manager.RCInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			manager.Client,
			string(api.ResourceReplicationControllers),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.ReplicationController{},
		manager.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				manager.Controller.AddReplicationController(
					obj.(*api.ReplicationController))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				manager.Controller.UpdateReplicationController(
					oldObj.(*api.ReplicationController),
					newObj.(*api.ReplicationController))
			},
			DeleteFunc: func(obj interface{}) {
				manager.Controller.DeleteReplicationController(
					obj.(*api.ReplicationController))
			},
		},
	)
	manager.Controller.SetReplicationControllerStore(&manager.RCStore)

	manager.ServiceStore, manager.ServiceInformer = framework.NewInformer(
		cache.NewListWatchFromClient(
			manager.Client,
			string(api.ResourceServices),
			api.NamespaceAll,
			fields.Everything(),
		),
		&api.Service{},
		manager.ResyncPeriod,
		framework.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				manager.Controller.AddService(
					obj.(*api.Service))
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				manager.Controller.UpdateService(
					oldObj.(*api.Service),
					newObj.(*api.Service))
			},
			DeleteFunc: func(obj interface{}) {
				manager.Controller.DeleteService(
					obj.(*api.Service))
			},
		},
	)
	manager.Controller.SetServiceStore(&manager.ServiceStore)

	return manager
}

func (m *NetworkManager) Run(_ []string) error {
	go m.PodInformer.Run(m.Shutdown)
	go m.NamespaceInformer.Run(m.Shutdown)
	go m.RCInformer.Run(m.Shutdown)
	go m.ServiceInformer.Run(m.Shutdown)
	go m.Controller.Run(m.Shutdown)
	select {}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"errors"
	"fmt"
	"os"
	"reflect"
	"strconv"
)

// TODO: Write tests!
func main() {
	// Test 02
	//textColumn := []string{"One", "Two", "Three"}
	//intColumn := []int{1, 2, 3}
	//c1 := Column{}
	//c1.fillColumn(textColumn)
	//c2 := Column{}
	//c2.fillColumn(intColumn)
	//df := DataFrame{
	//columns:  []Column{c1, c2},
	//nCols:    2,
	//nRows:    3,
	//colnames: []string{"Text", "Ints"},
	//}
	//fmt.Println(df)

	// Test 01
	//in := `A,B,C,D
	//1,2,3,4
	//5,6,7,8`
	//df := DataFrame{}
	//r := csv.NewReader(strings.NewReader(in))
	//records, err := r.ReadAll()
	//if err != nil {
	//panic(err)
	//}
	//err = df.loadAndParse(records, []string{"string", "int", "string", "int"})
	//if err != nil {
	//panic(err)
	//}

	//for _, v := range df.columns {
	//fmt.Println(v)
	//}
	//fmt.Println(df)

	// Test 03
	df := DataFrame{}
	csvfile, err := os.Open("example.csv")
	if err != nil {
		fmt.Println(err)
		return
	}
	r := csv.NewReader(csvfile)
	records, err := r.ReadAll()
	if err != nil {
		fmt.Println(err)
		return
	}
	df.loadData(records)
	fmt.Println(df)
}

// DataFrame Definition
// ====================
type DataFrame struct {
	columns  map[string]Column
	colNames []string
	nCols    int
	nRows    int
}

// DataFrame Methods
// =================
//func (df *DataFrame) loadAndParse(records [][]string, types []string) error {
//err := df.loadData(records)
//if err != nil {
//return err
//}
//if df.nCols != len(types) {
//return errors.New("Number of columns different from number of types")
//}
//for k, v := range df.columns {
//v.parseType(types[k])
//df.columns[k].colType = types[k]
//}
//return nil
//}

func (df DataFrame) subsetColumns(columns []string) (DataFrame, error) {
	newDf := DataFrame{}
	return newDf, nil
}

func (df *DataFrame) loadData(records [][]string) error {
	// Get DataFrame dimensions
	nRows := len(records) - 1
	if nRows <= 0 {
		return errors.New("Empty dataframe")
	}
	nCols := len(records[0])

	// Generate a virtual df to store the temporary values
	newDf := DataFrame{
		columns:  make(map[string]Column),
		nRows:    nRows,
		nCols:    nCols,
		colNames: records[0],
	}

	for j := 0; j < nCols; j++ {
		col := []string{}
		for i := 1; i < nRows+1; i++ {
			col = append(col, records[i][j])
		}
		column := Column{}
		column.maxCharLength = len(records[0][j])
		column.fillColumn(col)
		newDf.columns[records[0][j]] = column
	}
	*df = newDf
	return nil
}

//func (df DataFrame) colnames() (colnames []string) {
//for _, v := range df.columns {
//colnames = append(colnames, v.colName)
//}
//return
//}

// TODO: Truncate output for the same tabular format?
func (df DataFrame) String() (str string) {
	addPadding := func(s string, nchar int) string {
		for {
			if len(s) >= nchar {
				return s
			}
			s += " "
		}
	}
	colnames := df.colNames
	if len(colnames) != 0 {
		str += "   "
		for _, v := range colnames {
			str += addPadding(v, df.columns[v].maxCharLength)
			str += "  "
		}
		str += "\n"
		str += "\n"
	}
	for i := 0; i < df.nRows; i++ {
		str += strconv.Itoa(i+1) + ": "
		for _, v := range colnames {
			str += addPadding(fmt.Sprint(df.columns[v].row[i]), df.columns[v].maxCharLength)
			str += "  "
		}
		str += "\n"
	}
	return str
}

// Column Definition
// =================
type Column struct {
	row           []interface{}
	colType       string
	maxCharLength int
}

// Column Methods
// ==============
func (c Column) String() string {
	return fmt.Sprint(c.row)
}

func (c *Column) parseType(t string) error {
	var newRows interface{}
	switch t {
	case "int":
		newRows = []int{}
	case "float":
		newRows = []float64{}
	case "string":
		newRows = []string{}
	}
	for _, v := range c.row {
		r := fmt.Sprint(v)
		switch t {
		case "int":
			i, err := strconv.Atoi(r)
			if err != nil {
				return err
			}
			newRows = append(newRows.([]int), i)
		case "float":
			i, err := strconv.ParseFloat(r, 64)
			if err != nil {
				return err
			}
			newRows = append(newRows.([]float64), i)
		case "string":
			newRows = append(newRows.([]string), r)
		}
	}
	c.fillColumn(newRows)
	return nil
}

// TODO: Should this return an error?
func (c *Column) fillColumn(values interface{}) {
	switch reflect.TypeOf(values).Kind() {
	case reflect.Slice:
		s := reflect.ValueOf(values)
		for i := 0; i < s.Len(); i++ {
			c.row = append(c.row, s.Index(i).Interface())
			c.colType = fmt.Sprint(s.Index(i).Type())
			rowStr := fmt.Sprint(s.Index(i).Interface())
			if len(rowStr) > c.maxCharLength {
				c.maxCharLength = len(rowStr)
			}
		}
	}
}
<commit_msg>Reimplemented type parsing with the alternative column model<commit_after>package main

import (
	"encoding/csv"
	"errors"
	"fmt"
	"os"
	"reflect"
	"strconv"
)

// TODO: Write tests!
func main() {
	// Test 02
	//textColumn := []string{"One", "Two", "Three"}
	//intColumn := []int{1, 2, 3}
	//c1 := Column{}
	//c1.fillColumn(textColumn)
	//c2 := Column{}
	//c2.fillColumn(intColumn)
	//df := DataFrame{
	//columns:  []Column{c1, c2},
	//nCols:    2,
	//nRows:    3,
	//colnames: []string{"Text", "Ints"},
	//}
	//fmt.Println(df)

	// Test 01
	//in := `A,B,C,D
	//1,2,3,4
	//5,6,7,8`
	//df := DataFrame{}
	//r := csv.NewReader(strings.NewReader(in))
	//records, err := r.ReadAll()
	//if err != nil {
	//panic(err)
	//}
	//err = df.loadAndParse(records, []string{"string", "int", "string", "int"})
	//if err != nil {
	//panic(err)
	//}

	//for _, v := range df.columns {
	//fmt.Println(v)
	//}
	//fmt.Println(df)

	// Test 03
	df := DataFrame{}
	csvfile, err := os.Open("example.csv")
	if err != nil {
		fmt.Println(err)
		return
	}
	r := csv.NewReader(csvfile)
	records, err := r.ReadAll()
	if err != nil {
		fmt.Println(err)
		return
	}
	//df.loadData(records)
	err = df.loadAndParse(records, []string{"string", "int", "string", "int", "int", "int", "int", "int", "int", "int"})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(df)
}

// DataFrame Definition
// ====================
type DataFrame struct {
	columns  map[string]Column
	colnames []string
	nCols    int
	nRows    int
}

// DataFrame Methods
// =================
func (df *DataFrame) loadAndParse(records [][]string, types []string) error {
	err := df.loadData(records)
	if err != nil {
		return err
	}
	if df.nCols != len(types) {
		return errors.New("Number of columns different from number of types")
	}
	for k, v := range df.colnames {
		col := df.columns[v]
		col.parseType(types[k])
		col.colType = types[k]
		df.columns[v] = col
	}
	return nil
}

func (df DataFrame) subsetColumns(columns []string) (DataFrame, error) {
	newDf := DataFrame{}
	return newDf, nil
}

func (df *DataFrame) loadData(records [][]string) error {
	// Get DataFrame dimensions
	nRows := len(records) - 1
	if nRows <= 0 {
		return errors.New("Empty dataframe")
	}
	nCols := len(records[0])

	// Generate a virtual df to store the temporary values
	newDf := DataFrame{
		columns:  make(map[string]Column),
		nRows:    nRows,
		nCols:    nCols,
		colnames: records[0],
	}

	for j := 0; j < nCols; j++ {
		col := []string{}
		for i := 1; i < nRows+1; i++ {
			col = append(col, records[i][j])
		}
		column := Column{}
		column.maxCharLength = len(records[0][j])
		column.fillColumn(col)
		newDf.columns[records[0][j]] = column
	}
	*df = newDf
	return nil
}

func (df DataFrame) String() (str string) {
	addPadding := func(s string, nchar int) string {
		for {
			if len(s) >= nchar {
				return s
			}
			s += " "
		}
	}
	if len(df.colnames) != 0 {
		str += "   "
		for _, v := range df.colnames {
			str += addPadding(v, df.columns[v].maxCharLength)
			str += "  "
		}
		str += "\n"
		str += "\n"
	}
	for i := 0; i < df.nRows; i++ {
		str += strconv.Itoa(i+1) + ": "
		for _, v := range df.colnames {
			str += addPadding(fmt.Sprint(df.columns[v].row[i]), df.columns[v].maxCharLength)
			str += "  "
		}
		str += "\n"
	}
	return str
}

// Column Definition
// =================
type Column struct {
	row           []interface{}
	colType       string
	maxCharLength int
}

// Column Methods
// ==============
func (c Column) String() string {
	return fmt.Sprint(c.row)
}

func (c *Column) parseType(t string) error {
	var newRows interface{}
	switch t {
	case "int":
		newRows = []int{}
	case "float":
		newRows = []float64{}
	case "string":
		newRows = []string{}
	}
	for _, v := range c.row {
		r := fmt.Sprint(v)
		switch t {
		case "int":
			i, err := strconv.Atoi(r)
			if err != nil {
				return err
			}
			newRows = append(newRows.([]int), i)
		case "float":
			i, err := strconv.ParseFloat(r, 64)
			if err != nil {
				return err
			}
			newRows = append(newRows.([]float64), i)
		case "string":
			newRows = append(newRows.([]string), r)
		}
	}
	c.fillColumn(newRows)
	return nil
}

// TODO: Should this return an error?
func (c *Column) fillColumn(values interface{}) {
	switch reflect.TypeOf(values).Kind() {
	case reflect.Slice:
		s := reflect.ValueOf(values)
		c.row = make([]interface{}, 0)
		for i := 0; i < s.Len(); i++ {
			c.row = append(c.row, s.Index(i).Interface())
			c.colType = fmt.Sprint(s.Index(i).Type())
			rowStr := fmt.Sprint(s.Index(i).Interface())
			if len(rowStr) > c.maxCharLength {
				c.maxCharLength = len(rowStr)
			}
		}
	}
}
<|endoftext|>


<commit_before>package gopisysfs

import (
	"os"
	"time"

	"golang.org/x/sys/unix"
)

func monitorData(valf *os.File, data chan<- Event, killer <-chan bool) {

	// This is run inside a goroutine

	defer func() {
		info("GPIO Monitor %v killing\n", valf.Name())
		close(data)
		valf.Close()
	}()
	// create a buffer to read the values in to.
	buff := make([]byte, 0, 10)

	timeout := 500 * time.Millisecond
	timeoutTs := unix.NsecToTimespec(int64(timeout))
	pollspec := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN | unix.POLLPRI | unix.POLLERR}}

	count := 0
	for {
		count++
		info("GPIO Monitor %v looping: %v\n", valf.Name(), count)
		select {
		case <-killer:
			// normal shut down
			return
		default:
			// keep on moving ... nothing to do here.
		}

		if reseek {
			reseek = false
		}

		// wait up to some period for data to be there....
		state, err := unix.Ppoll(pollspec, &timeoutTs, nil)
		if err != nil {
			info("GPIO Monitor %v terminating: %v\n", valf.Name(), err)
			return
		}

		if state > 0 {

			// data to read....
			info("GPIO Monitor %v polled OK: %v\n", valf.Name(), state)

			stamp := time.Now()
			n, err := valf.Read(buff)
			if err != nil {
				info("GPIO Monitor %v terminating: %v\n", valf.Name(), err)
				return
			}
			// reset it for next read
			if _, err := valf.Seek(0); err != nil {
				info("GPIO Monitor %v terminating: %v\n", valf.Name(), err)
				return
			}

			val = string(buff[:n]) == "1"
			event := Event{val, stamp}
			select {
			case send <- event:
				info("GPIO Monitor %v sending: %v\n", valf.Name(), event)
			case <-killer:
				// normal shut down
				return
			default:
				info("GPIO Monitor %v terminating: send receive channel overflow\n", valf.Name())
				return
			}
		} else {
			info("GPIO Monitor %v polled Timeout\n", valf.Name())
		}

	}

}

func buildMonitor(fname string, buffersize int) (<-chan Event, func(), error) {

	// open the value file, we will need the file descriptor
	valf, err := os.Open(p.value)
	if err != nil {
		return nil, nil, err
	}

	killer := make(chan bool, 1)
	killfn := func() {
		select {
		case killer <- true:
		default:
		}
	}

	data := make(chan Event, buffersize)

	go monitorData(valf, data, killer)

	return data, killdfn, nil

}
<commit_msg>Work compile errors<commit_after>package gopisysfs

import (
	"os"
	"time"

	"golang.org/x/sys/unix"
)

func monitorData(valf *os.File, data chan<- Event, killer <-chan bool) {

	// This is run inside a goroutine

	defer func() {
		info("GPIO Monitor %v killing\n", valf.Name())
		close(data)
		valf.Close()
	}()
	// create a buffer to read the values in to.
	buff := make([]byte, 0, 10)

	timeout := 500 * time.Millisecond
	timeoutTs := unix.NsecToTimespec(int64(timeout))
	pollspec := []unix.PollFd{{Fd: int32(valf.Fd()), Events: unix.POLLIN | unix.POLLPRI | unix.POLLERR}}

	count := 0
	for {
		count++
		info("GPIO Monitor %v looping: %v\n", valf.Name(), count)
		select {
		case <-killer:
			// normal shut down
			return
		default:
			// keep on moving ... nothing to do here.
		}

		// wait up to some period for data to be there....
		state, err := unix.Ppoll(pollspec, &timeoutTs, nil)
		if err != nil {
			info("GPIO Monitor %v terminating: %v\n", valf.Name(), err)
			return
		}

		if state > 0 {

			// data to read....
			info("GPIO Monitor %v polled OK: %v\n", valf.Name(), state)

			stamp := time.Now()
			n, err := valf.Read(buff)
			if err != nil {
				info("GPIO Monitor %v terminating: %v\n", valf.Name(), err)
				return
			}
			// reset it for next read
			if _, err := valf.Seek(0, 0); err != nil {
				info("GPIO Monitor %v terminating: %v\n", valf.Name(), err)
				return
			}

			val := string(buff[:n]) == "1"
			event := Event{val, stamp}
			select {
			case data <- event:
				info("GPIO Monitor %v sending: %v\n", valf.Name(), event)
			case <-killer:
				// normal shut down
				return
			default:
				info("GPIO Monitor %v terminating: send receive channel overflow\n", valf.Name())
				return
			}
		} else {
			info("GPIO Monitor %v polled Timeout\n", valf.Name())
		}

	}

}

func buildMonitor(fname string, buffersize int) (<-chan Event, func(), error) {

	// open the value file, we will need the file descriptor
	valf, err := os.Open(p.value)
	if err != nil {
		return nil, nil, err
	}

	killer := make(chan bool, 1)
	killfn := func() {
		select {
		case killer <- true:
		default:
		}
	}

	data := make(chan Event, buffersize)

	go monitorData(valf, data, killer)

	return data, killfn, nil

}
<|endoftext|>


<commit_before>package main

//Most code on this page is from http://reprage.com/post/using-golang-to-connect-raspberrypi-and-arduino/

import (
	"bytes"
	"encoding/binary"
	"errors"
	"github.com/huin/goserial"
	"io"
	"io/ioutil"
	"log"
	"strings"
)

var c = &goserial.Config{}
var s io.ReadWriteCloser

//We init the usb connection only once, at boot time.
func init() {
	// Find the device that represents the arduino serial
	// connection.
	c = &goserial.Config{Name: findArduino(), Baud: 9600}
	log.Printf("the USB port the Arduino service will use is %v\n", findArduino())
	s, _ = goserial.OpenPort(c)

}

//rduino converts the string command (on/off) to the one leter command
// the arduino board expects. And call sendArduinoCommand
func arduinoDo(command string, value int) error {
	return sendArduinoCommand(command, uint32(value), s) //u for up, d for down
}

// findArduino looks for the file that represents the Arduino
// serial connection. Returns the fully qualified path to the
// device if we are able to find a likely candidate for an
// Arduino, otherwise an empty string if unable to find
// something that 'looks' like an Arduino device.
func findArduino() string {
	contents, _ := ioutil.ReadDir("/dev")

	// Look for what is mostly likely the Arduino device
	for _, f := range contents {
		if strings.Contains(f.Name(), "tty.usbserial") ||
			strings.Contains(f.Name(), "ttyUSB") ||
			strings.Contains(f.Name(), "ttyACM") {
			return "/dev/" + f.Name()
		}
	}

	// Have not been able to find a USB device that 'looks'
	// like an Arduino.
	return ""
}

// sendArduinoCommand transmits a new command over the nominated serial
// port to the arduino. Returns an error on failure. Each command is
// identified by a single byte and may take one argument (a float).
func sendArduinoCommand(command string, argument uint32, serialPort io.ReadWriteCloser) error {
	if serialPort == nil {
		return errors.New("No serial port to talk to the Arduino.")
	}

	// Package argument for transmission
	value := new(bytes.Buffer)
	err := binary.Write(value, binary.LittleEndian, argument)
	if err != nil {
		return err
	}

	// Transmit command and argument down the pipe.
	for _, v := range [][]byte{[]byte(command), value.Bytes()} {
		_, err = serialPort.Write(v)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Send correct command structure to the arduino<commit_after>package main

//Most code on this page is from http://reprage.com/post/using-golang-to-connect-raspberrypi-and-arduino/

import (
	"errors"
	"fmt"
	"github.com/huin/goserial"
	"io"
	"io/ioutil"
	"log"
	"strings"
)

var c = &goserial.Config{}
var s io.ReadWriteCloser

//We init the usb connection only once, at boot time.
func init() {
	// Find the device that represents the arduino serial
	// connection.
	c = &goserial.Config{Name: findArduino(), Baud: 9600}
	log.Printf("the USB port the Arduino service will use is %v\n", findArduino())
	s, _ = goserial.OpenPort(c)

}

//rduino converts the string command (on/off) to the one leter command
// the arduino board expects. And call sendArduinoCommand
func arduinoDo(command string, value int) error {
	return sendArduinoCommand(command, uint32(value), s) //u for up, d for down
}

// findArduino looks for the file that represents the Arduino
// serial connection. Returns the fully qualified path to the
// device if we are able to find a likely candidate for an
// Arduino, otherwise an empty string if unable to find
// something that 'looks' like an Arduino device.
func findArduino() string {
	contents, _ := ioutil.ReadDir("/dev")

	// Look for what is mostly likely the Arduino device
	for _, f := range contents {
		if strings.Contains(f.Name(), "tty.usbserial") ||
			strings.Contains(f.Name(), "ttyUSB") ||
			strings.Contains(f.Name(), "ttyACM") {
			return "/dev/" + f.Name()
		}
	}

	// Have not been able to find a USB device that 'looks'
	// like an Arduino.
	return ""
}

// sendArduinoCommand transmits a new command over the nominated serial
// port to the arduino. Returns an error on failure. Each command is
// identified by a single byte and may take one argument (a float).
func sendArduinoCommand(command string, argument uint32, serialPort io.ReadWriteCloser) error {
	if serialPort == nil {
		return errors.New("No serial port to talk to the Arduino.")
	}

	// Package argument for transmission
	// value := new(bytes.Buffer)
	// err := binary.Write(value, binary.LittleEndian, argument)
	// if err != nil {
	// 	return err
	// }

	cmd := fmt.Sprintf("%s %+v", command, argument)

	// Transmit command and argument down the pipe.
	for _, v := range [][]byte{[]byte(cmd)} {
		_, err := serialPort.Write(v)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"errors"
	"log"
	"os"
	"os/signal"
)

func main() {
	lgr := log.New(os.Stderr, "grace: ", 0)

	err := run()
	if err != nil {
		lgr.Printf("%v", err)
		os.Exit(1)
	}

}

func run() error {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	defer stop()

	numbers := make(chan int)

	go func() {
		var i int
		for {
			select {
			case <-ctx.Done():
				break
			default:
				numbers <- i
				i++
			}
		}
		close(numbers)
		println("generator: ", i)
	}()

	go func() {
		last := 0
		for n := range numbers {
			if n > 0 && n != last+1 {
				println(n, last)
			}
			last = n
		}
		println("producer: ", last)
	}()

	<-ctx.Done()

	err := ctx.Err()
	if errors.Is(err, context.Canceled) {
		return nil
	}

	return err
}
<commit_msg>grace: add runProducer<commit_after>package main

import (
	"context"
	"errors"
	"log"
	"os"
	"os/signal"
)

func main() {
	lgr := log.New(os.Stderr, "grace: ", 0)

	err := run()
	if err != nil {
		lgr.Printf("%v", err)
		os.Exit(1)
	}

}

func run() error {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	defer stop()

	numbers := make(chan int)

	go func() {
		var i int
		for {
			select {
			case <-ctx.Done():
				break
			default:
				numbers <- i
				i++
			}
		}
		close(numbers)
		println("generator: ", i)
	}()

	go runProducer(ctx, numbers)

	<-ctx.Done()

	err := ctx.Err()
	if errors.Is(err, context.Canceled) {
		return nil
	}

	return err
}

func runProducer(ctx context.Context, numbers <-chan int) {
	last := 0
	for n := range numbers {
		if n > 0 && n != last+1 {
			println(n, last)
		}
		last = n
	}
	println("producer: ", last)
}
<|endoftext|>


<commit_before>package main

import (
	"poliskarta/helperfunctions"
	"strings"
)

//Used to filter out Europe road names, like "E6", "E22"
var europeRoads []string

// var arrayOfTitles []string

//Used to include common words in names of places
//separated by space, like "Jörgens trappa", "Anna Lindhs plats"
var validWordsForPlaces []string

//Used to filter out words for roads followed by numbers,
//like "Lv 598", "väg 112" and the like
var invalidWordsForRoads []string

//Rule 1:
func Rule1(description string) []string {
	fillEuropeRoads()
	fillValidWordsForPlaces()
	fillInvalidWordsForRoads()

	//Split on spaces - descWords = array
	descWords := strings.Split(description, " ")
	trimmedDescWords := helperfunctions.TrimSpacesFromArray(descWords)

	//The resulting array of words after filtering
	placeWords := []string{}

	//Loop through the array of words
	for i := 1; i < len(trimmedDescWords); i++ {

		currentWord := trimmedDescWords[i]

		//Go to the next word in the array if the previous word had a "." in the end
		if strings.HasSuffix(trimmedDescWords[i-1], ".") {
			continue
		}

		//Check if current word is part of the invalid road-words
		if helperfunctions.StringInSlice(currentWord, invalidWordsForRoads) && currentWordNotLastWordInArray(i, trimmedDescWords) {
			nextWordInArray := trimmedDescWords[i+1]
			helperfunctions.TrimSuffixesFromWord(&nextWordInArray, ".", ",")

			//Check if next word is number, if so: add it
			if helperfunctions.WordIsNumber(nextWordInArray) {
				placeWords = append(placeWords, nextWordInArray)
				continue
			}
		}

		//Check if the word starts with uppercase and is NOT a europe road
		if helperfunctions.StartsWithUppercase(currentWord) && !helperfunctions.StringInSliceIgnoreCase(currentWord, europeRoads) {
			helperfunctions.TrimSuffixesFromWord(&currentWord, ".", ",")
			placeWords = append(placeWords, currentWord)
		}
	}

	return placeWords
}
func fillEuropeRoads() {
	europeRoads = []string{"E4", "E6", "E10", "E12", "E14", "E16", "E18", "E22", "E45", "E65", "E", "Lv"}
}

func fillValidWordsForPlaces() {
	validWordsForPlaces = []string{"väg", "gränd", "plats", "gata", "led", "torg", "park", "trappa", "trappor", "bro", "gångbro", "allé", "alle", "aveny", "plan", "kaj", "hamn", "strand", "stig", "backe", "kajen", "hamnen", "holme", "holmar", "dockan", "parkväg", "byväg", "byaväg", "gård", "stråket", "tvärgata", "gårdar", "parkgata", "idrottsväg", "broväg", "vägen", "stationsgata", "hamngata", "bangårdsgata", "fätåg", "kyrkogata", "hage", "stråket", "ö", "träsk", "flygplats", "industriväg", "trappgata", "kärr"}
}

func fillInvalidWordsForRoads() {
	invalidWordsForRoads = []string{"väg", "Lv", "Länsväg", "länsväg"}
}

func currentWordNotLastWordInArray(index int, strings []string) bool {
	return index < len(strings)-1
}
<commit_msg>Changed var name<commit_after>package main

import (
	"poliskarta/helperfunctions"
	"strings"
)

//Used to filter out Europe road names, like "E6", "E22"
var europeRoads []string

// var arrayOfTitles []string

//Used to include common words in names of places
//separated by space, like "Jörgens trappa", "Anna Lindhs plats"
var validWordsForPlaces []string

//Used to filter out words for roads followed by numbers,
//like "Lv 598", "väg 112" and the like
var invalidWordsForRoads []string

//Rule 1:
func Rule1(description string) []string {
	fillEuropeRoads()
	fillValidWordsForPlaces()
	fillInvalidWordsForRoads()

	//Split on spaces - descWords = array
	descWords := strings.Split(description, " ")
	descWords = helperfunctions.TrimSpacesFromArray(descWords)

	//The resulting array of words after filtering
	placeWords := []string{}

	//Loop through the array of words
	for i := 1; i < len(descWords); i++ {

		currentWord := descWords[i]

		//Skip iteration if the previous word had a "." in the end
		if strings.HasSuffix(descWords[i-1], ".") {
			continue
		}

		//Check if current word is part of the invalid road-words
		if helperfunctions.StringInSlice(currentWord, invalidWordsForRoads) && currentWordNotLastWordInArray(i, descWords) {
			nextWordInArray := descWords[i+1]
			helperfunctions.TrimSuffixesFromWord(&nextWordInArray, ".", ",")

			//Check if next word is number, if so: add it
			if helperfunctions.WordIsNumber(nextWordInArray) {
				placeWords = append(placeWords, nextWordInArray)
				continue
			}
		}

		//Check if current word starts with uppercase and is NOT europe road
		if helperfunctions.StartsWithUppercase(currentWord) && !helperfunctions.StringInSliceIgnoreCase(currentWord, europeRoads) {
			helperfunctions.TrimSuffixesFromWord(&currentWord, ".", ",")
			placeWords = append(placeWords, currentWord)
		}
	}

	return placeWords
}
func fillEuropeRoads() {
	europeRoads = []string{"E4", "E6", "E10", "E12", "E14", "E16", "E18", "E22", "E45", "E65", "E", "Lv"}
}

func fillValidWordsForPlaces() {
	validWordsForPlaces = []string{"väg", "gränd", "plats", "gata", "led", "torg", "park", "trappa", "trappor", "bro", "gångbro", "allé", "alle", "aveny", "plan", "kaj", "hamn", "strand", "stig", "backe", "kajen", "hamnen", "holme", "holmar", "dockan", "parkväg", "byväg", "byaväg", "gård", "stråket", "tvärgata", "gårdar", "parkgata", "idrottsväg", "broväg", "vägen", "stationsgata", "hamngata", "bangårdsgata", "fätåg", "kyrkogata", "hage", "stråket", "ö", "träsk", "flygplats", "industriväg", "trappgata", "kärr"}
}

func fillInvalidWordsForRoads() {
	invalidWordsForRoads = []string{"väg", "Lv", "Länsväg", "länsväg"}
}

func currentWordNotLastWordInArray(index int, strings []string) bool {
	return index < len(strings)-1
}
<|endoftext|>


<commit_before>package hawk

import (
	"crypto/hmac"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/base64"
	"hash"
	"net"
	"net/url"
	"strconv"
	"strings"
)

const headerVersion = 1

type AuthType int

const (
	AuthHeader AuthType = iota
	AuthResponse
	AuthBewit
)

type Mac struct {
	Type       AuthType
	Credential Credential
	Uri        string
	Method     string
	Option     Option
}

func (m *Mac) String() (string, error) {
	digest, err := m.digest()
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(digest), nil
}

func (m *Mac) digest() ([]byte, error) {
	h := getHash(m.Credential.Alg)

	mac := hmac.New(h, []byte(m.Credential.Key))
	ns, err := m.nomarized()
	if err != nil {
		return nil, err
	}
	mac.Write([]byte(ns))

	return mac.Sum(nil), nil
}

func (m *Mac) nomarized() (string, error) {
	return nomarized(m.Type, m.Uri, m.Method, m.Option)
}

func nomarized(authType AuthType, uri string, method string, option Option) (string, error) {
	u, err := url.Parse(uri)
	if err != nil {
		return "", err
	}

	host := u.Host
	_, port, _ := net.SplitHostPort(u.Host)
	if port == "" {
		switch u.Scheme {
		case "http":
			port = "80"
		case "https":
			port = "443"
		}
	}
	path := u.Path

	header := "hawk" + "." + strconv.Itoa(headerVersion) + "." + authType.String()

	ns := header + "\n" +
		strconv.FormatInt(option.TimeStamp, 10) + "\n" +
		option.Nonce + "\n" +
		strings.ToUpper(method) + "\n" +
		strings.ToLower(path) + "\n" +
		host + "\n" +
		port + "\n" +
		option.Hash + "\n" +
		option.Ext + "\n"

	return ns, nil
}

func getHash(alg Alg) func() hash.Hash {
	switch alg {
	case SHA256:
		return sha256.New
	case SHA512:
		return sha512.New
	default:
		return sha256.New
	}
}
<commit_msg>Implemented TsMac<commit_after>package hawk

import (
	"crypto/hmac"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/base64"
	"hash"
	"net"
	"net/url"
	"strconv"
	"strings"
)

const headerVersion = 1

type AuthType int

const (
	AuthHeader AuthType = iota
	AuthResponse
	AuthBewit
)

type Mac struct {
	Type       AuthType
	Credential Credential
	Uri        string
	Method     string
	Option     Option
}

type TsMac struct {
	TimeStamp  int64
	Credential Credential
}

func (m *Mac) String() (string, error) {
	digest, err := m.digest()
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(digest), nil
}

func (m *Mac) digest() ([]byte, error) {
	h := getHash(m.Credential.Alg)

	mac := hmac.New(h, []byte(m.Credential.Key))
	ns, err := m.nomarized()
	if err != nil {
		return nil, err
	}
	mac.Write([]byte(ns))

	return mac.Sum(nil), nil
}

func (m *Mac) nomarized() (string, error) {
	return nomarized(m.Type, m.Uri, m.Method, m.Option)
}

func (tm *TsMac) String() string {
	digest := tm.digest()

	return base64.StdEncoding.EncodeToString(digest)
}

func (tm *TsMac) digest() []byte {
	h := getHash(tm.Credential.Alg)

	mac := hmac.New(h, []byte(tm.Credential.Key))
	ns := "hawk." + strconv.Itoa(headerVersion) + ".ts" + "\n" + strconv.FormatInt(tm.TimeStamp, 10) + "\n"
	mac.Write([]byte(ns))

	return mac.Sum(nil)
}

func nomarized(authType AuthType, uri string, method string, option Option) (string, error) {
	u, err := url.Parse(uri)
	if err != nil {
		return "", err
	}

	host := u.Host
	_, port, _ := net.SplitHostPort(u.Host)
	if port == "" {
		switch u.Scheme {
		case "http":
			port = "80"
		case "https":
			port = "443"
		}
	}
	path := u.Path

	header := "hawk" + "." + strconv.Itoa(headerVersion) + "." + authType.String()

	ns := header + "\n" +
		strconv.FormatInt(option.TimeStamp, 10) + "\n" +
		option.Nonce + "\n" +
		strings.ToUpper(method) + "\n" +
		strings.ToLower(path) + "\n" +
		host + "\n" +
		port + "\n" +
		option.Hash + "\n" +
		option.Ext + "\n"

	return ns, nil
}

func getHash(alg Alg) func() hash.Hash {
	switch alg {
	case SHA256:
		return sha256.New
	case SHA512:
		return sha512.New
	default:
		return sha256.New
	}
}
<|endoftext|>


<commit_before>package controller

import (
	"github.com/golang/glog"
	"github.com/pkg/errors"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	coreinformers "k8s.io/client-go/informers/core/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"

	"fmt"

	"kubevirt.io/containerized-data-importer/pkg/common"
)

const (
	// AnnEndpoint provides a const for our PVC endpoint annotation
	AnnEndpoint = "cdi.kubevirt.io/storage.import.endpoint"
	// AnnSecret provides a const for our PVC secretName annotation
	AnnSecret = "cdi.kubevirt.io/storage.import.secretName"
	// AnnImportPod provides a const for our PVC importPodName annotation
	AnnImportPod = "cdi.kubevirt.io/storage.import.importPodName"
	//LabelImportPvc is a pod label used to find the import pod that was created by the relevant PVC
	LabelImportPvc = "cdi.kubevirt.io/storage.import.importPvcName"
)

// ImportController represents a CDI Import Controller
type ImportController struct {
	Controller
}

type importPodEnvVar struct {
	ep, secretName string
}

var podEnvVar importPodEnvVar

// NewImportController sets up an Import Controller, and returns a pointer to
// the newly created Import Controller
func NewImportController(client kubernetes.Interface,
	pvcInformer coreinformers.PersistentVolumeClaimInformer,
	podInformer coreinformers.PodInformer,
	image string,
	pullPolicy string,
	verbose string) *ImportController {
	c := &ImportController{
		Controller: *NewController(client, pvcInformer, podInformer, image, pullPolicy, verbose),
	}
	return c
}

func (ic *ImportController) findImportPodFromCache(pvc *v1.PersistentVolumeClaim) (*v1.Pod, error) {
	selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{LabelImportPvc: pvc.Name}})
	if err != nil {
		return nil, err
	}

	podList, err := ic.podLister.Pods(pvc.Namespace).List(selector)
	if err != nil {
		return nil, err
	}

	if len(podList) == 0 {
		return nil, nil
	} else if len(podList) > 1 {
		return nil, errors.Errorf("multiple pods found for import PVC %s/%s", pvc.Namespace, pvc.Name)
	}
	return podList[0], nil
}

// Create the importer pod based the pvc. The endpoint and optional secret are available to
// the importer pod as env vars. The pvc is checked (again) to ensure that we are not already
// processing this pvc, which would result in multiple importer pods for the same pvc.
func (ic *ImportController) processPvcItem(pvc *v1.PersistentVolumeClaim) error {
	// find import Pod
	pod, err := ic.findImportPodFromCache(pvc)
	if err != nil {
		return err
	}
	pvcKey, err := cache.MetaNamespaceKeyFunc(pvc)
	if err != nil {
		return err
	}

	// Pod must be controlled by this PVC
	if pod != nil && !metav1.IsControlledBy(pod, pvc) {
		return errors.Errorf("found pod %s/%s not owned by pvc %s/%s", pod.Namespace, pod.Name, pvc.Namespace, pvc.Name)
	}

	// expectations prevent us from creating multiple pods. An expectation forces
	// us to observe a pod's creation in the cache.
	needsSync := ic.podExpectations.SatisfiedExpectations(pvcKey)

	// make sure not to reprocess a PVC that has already completed successfully,
	// even if the pod no longer exists
	previousPhase, exists := pvc.ObjectMeta.Annotations[AnnPodPhase]
	if exists && (previousPhase == string(v1.PodSucceeded)) {
		needsSync = false
	}
	if pod == nil && needsSync {
		podEnvVar.ep, err = getEndpoint(pvc)
		if err != nil {
			return err
		}
		podEnvVar.secretName, err = getSecretName(ic.clientset, pvc)
		if err != nil {
			return err
		}
		if podEnvVar.secretName == "" {
			glog.V(2).Infof("no secret will be supplied to endpoint %q\n", podEnvVar.ep)
		}
		// all checks passed, let's create the importer pod!
		ic.expectPodCreate(pvcKey)
		pod, err = CreateImporterPod(ic.clientset, ic.image, ic.verbose, ic.pullPolicy, podEnvVar, pvc)
		if err != nil {
			ic.observePodCreate(pvcKey)
			return err
		}
		return nil
	}

	// update pvc with importer pod name and optional cdi label
	anno := map[string]string{}
	if pod != nil {
		anno[AnnImportPod] = string(pod.Name)
		anno[AnnPodPhase] = string(pod.Status.Phase)
		//this is for a case where the import container is failing and the restartPolicy is OnFailure. In such case
		//the pod phase is "Running" although the container state is Waiting. When the container recovers, its state
		//changes back to "Running".
		if pod.Status.ContainerStatuses != nil && pod.Status.ContainerStatuses[0].State.Waiting != nil {
			anno[AnnPodPhase] = string(v1.PodFailed)
		}

		if pod.Status.Phase == "Succeeded" {
			dReq := podDeleteRequest{
				namespace: pod.Namespace,
				podName:   pod.Name,
				podLister: ic.Controller.podLister,
				k8sClient: ic.Controller.clientset,
			}
			// just use defer here so we make sure our pvc updates get written prior to actual deletion
			defer deletePod(dReq)
		}
	}

	var lab map[string]string
	if !checkIfLabelExists(pvc, common.CDILabelKey, common.CDILabelValue) {
		lab = map[string]string{common.CDILabelKey: common.CDILabelValue}
	}

	pvc, err = updatePVC(ic.clientset, pvc, anno, lab)
	if err != nil {
		return errors.WithMessage(err, "could not update pvc %q annotation and/or label")
	}
	return nil
}

func (ic *ImportController) expectPodCreate(pvcKey string) {
	ic.podExpectations.ExpectCreations(pvcKey, 1)
}

//ProcessNextPvcItem ...
func (ic *ImportController) ProcessNextPvcItem() bool {
	key, shutdown := ic.queue.Get()
	if shutdown {
		return false
	}
	defer ic.queue.Done(key)

	err := ic.syncPvc(key.(string))
	if err != nil { // processPvcItem errors may not have been logged so log here
		glog.Errorf("error processing pvc %q: %v", key, err)
		return true
	}
	return ic.forgetKey(key, fmt.Sprintf("ProcessNextPvcItem: processing pvc %q completed", key))
}

func (ic *ImportController) syncPvc(key string) error {
	pvc, exists, err := ic.pvcFromKey(key)
	if err != nil {
		return err
	} else if !exists {
		ic.podExpectations.DeleteExpectations(key)
	}

	if pvc == nil {
		return nil
	}
	//check if AnnoEndPoint annotation exists
	if !checkPVC(pvc, AnnEndpoint) {
		return nil
	}
	glog.V(3).Infof("ProcessNextPvcItem: next pvc to process: %s\n", key)
	return ic.processPvcItem(pvc)
}

//Run is being called from cdi-controller (cmd)
func (ic *ImportController) Run(threadiness int, stopCh <-chan struct{}) error {
	ic.Controller.run(threadiness, stopCh, ic)
	return nil
}

func (ic *ImportController) runPVCWorkers() {
	for ic.ProcessNextPvcItem() {
	}
}
<commit_msg>change the import controller not to have global parameter #504<commit_after>package controller

import (
	"github.com/golang/glog"
	"github.com/pkg/errors"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	coreinformers "k8s.io/client-go/informers/core/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"

	"fmt"

	"kubevirt.io/containerized-data-importer/pkg/common"
)

const (
	// AnnEndpoint provides a const for our PVC endpoint annotation
	AnnEndpoint = "cdi.kubevirt.io/storage.import.endpoint"
	// AnnSecret provides a const for our PVC secretName annotation
	AnnSecret = "cdi.kubevirt.io/storage.import.secretName"
	// AnnImportPod provides a const for our PVC importPodName annotation
	AnnImportPod = "cdi.kubevirt.io/storage.import.importPodName"
	//LabelImportPvc is a pod label used to find the import pod that was created by the relevant PVC
	LabelImportPvc = "cdi.kubevirt.io/storage.import.importPvcName"
)

// ImportController represents a CDI Import Controller
type ImportController struct {
	Controller
}

type importPodEnvVar struct {
	ep, secretName string
}

// NewImportController sets up an Import Controller, and returns a pointer to
// the newly created Import Controller
func NewImportController(client kubernetes.Interface,
	pvcInformer coreinformers.PersistentVolumeClaimInformer,
	podInformer coreinformers.PodInformer,
	image string,
	pullPolicy string,
	verbose string) *ImportController {
	c := &ImportController{
		Controller: *NewController(client, pvcInformer, podInformer, image, pullPolicy, verbose),
	}
	return c
}

func (ic *ImportController) findImportPodFromCache(pvc *v1.PersistentVolumeClaim) (*v1.Pod, error) {
	selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{LabelImportPvc: pvc.Name}})
	if err != nil {
		return nil, err
	}

	podList, err := ic.podLister.Pods(pvc.Namespace).List(selector)
	if err != nil {
		return nil, err
	}

	if len(podList) == 0 {
		return nil, nil
	} else if len(podList) > 1 {
		return nil, errors.Errorf("multiple pods found for import PVC %s/%s", pvc.Namespace, pvc.Name)
	}
	return podList[0], nil
}

// Create the importer pod based the pvc. The endpoint and optional secret are available to
// the importer pod as env vars. The pvc is checked (again) to ensure that we are not already
// processing this pvc, which would result in multiple importer pods for the same pvc.
func (ic *ImportController) processPvcItem(pvc *v1.PersistentVolumeClaim) error {
	// find import Pod
	pod, err := ic.findImportPodFromCache(pvc)
	if err != nil {
		return err
	}
	pvcKey, err := cache.MetaNamespaceKeyFunc(pvc)
	if err != nil {
		return err
	}

	// Pod must be controlled by this PVC
	if pod != nil && !metav1.IsControlledBy(pod, pvc) {
		return errors.Errorf("found pod %s/%s not owned by pvc %s/%s", pod.Namespace, pod.Name, pvc.Namespace, pvc.Name)
	}

	// expectations prevent us from creating multiple pods. An expectation forces
	// us to observe a pod's creation in the cache.
	needsSync := ic.podExpectations.SatisfiedExpectations(pvcKey)

	// make sure not to reprocess a PVC that has already completed successfully,
	// even if the pod no longer exists
	previousPhase, exists := pvc.ObjectMeta.Annotations[AnnPodPhase]
	if exists && (previousPhase == string(v1.PodSucceeded)) {
		needsSync = false
	}
	if pod == nil && needsSync {
		var podEnvVar importPodEnvVar

		podEnvVar.ep, err = getEndpoint(pvc)
		if err != nil {
			return err
		}
		podEnvVar.secretName, err = getSecretName(ic.clientset, pvc)
		if err != nil {
			return err
		}
		if podEnvVar.secretName == "" {
			glog.V(2).Infof("no secret will be supplied to endpoint %q\n", podEnvVar.ep)
		}
		// all checks passed, let's create the importer pod!
		ic.expectPodCreate(pvcKey)
		pod, err = CreateImporterPod(ic.clientset, ic.image, ic.verbose, ic.pullPolicy, podEnvVar, pvc)
		if err != nil {
			ic.observePodCreate(pvcKey)
			return err
		}
		return nil
	}

	// update pvc with importer pod name and optional cdi label
	anno := map[string]string{}
	if pod != nil {
		anno[AnnImportPod] = string(pod.Name)
		anno[AnnPodPhase] = string(pod.Status.Phase)
		//this is for a case where the import container is failing and the restartPolicy is OnFailure. In such case
		//the pod phase is "Running" although the container state is Waiting. When the container recovers, its state
		//changes back to "Running".
		if pod.Status.ContainerStatuses != nil && pod.Status.ContainerStatuses[0].State.Waiting != nil {
			anno[AnnPodPhase] = string(v1.PodFailed)
		}

		if pod.Status.Phase == "Succeeded" {
			dReq := podDeleteRequest{
				namespace: pod.Namespace,
				podName:   pod.Name,
				podLister: ic.Controller.podLister,
				k8sClient: ic.Controller.clientset,
			}
			// just use defer here so we make sure our pvc updates get written prior to actual deletion
			defer deletePod(dReq)
		}
	}

	var lab map[string]string
	if !checkIfLabelExists(pvc, common.CDILabelKey, common.CDILabelValue) {
		lab = map[string]string{common.CDILabelKey: common.CDILabelValue}
	}

	pvc, err = updatePVC(ic.clientset, pvc, anno, lab)
	if err != nil {
		return errors.WithMessage(err, "could not update pvc %q annotation and/or label")
	}
	return nil
}

func (ic *ImportController) expectPodCreate(pvcKey string) {
	ic.podExpectations.ExpectCreations(pvcKey, 1)
}

//ProcessNextPvcItem ...
func (ic *ImportController) ProcessNextPvcItem() bool {
	key, shutdown := ic.queue.Get()
	if shutdown {
		return false
	}
	defer ic.queue.Done(key)

	err := ic.syncPvc(key.(string))
	if err != nil { // processPvcItem errors may not have been logged so log here
		glog.Errorf("error processing pvc %q: %v", key, err)
		return true
	}
	return ic.forgetKey(key, fmt.Sprintf("ProcessNextPvcItem: processing pvc %q completed", key))
}

func (ic *ImportController) syncPvc(key string) error {
	pvc, exists, err := ic.pvcFromKey(key)
	if err != nil {
		return err
	} else if !exists {
		ic.podExpectations.DeleteExpectations(key)
	}

	if pvc == nil {
		return nil
	}
	//check if AnnoEndPoint annotation exists
	if !checkPVC(pvc, AnnEndpoint) {
		return nil
	}
	glog.V(3).Infof("ProcessNextPvcItem: next pvc to process: %s\n", key)
	return ic.processPvcItem(pvc)
}

//Run is being called from cdi-controller (cmd)
func (ic *ImportController) Run(threadiness int, stopCh <-chan struct{}) error {
	ic.Controller.run(threadiness, stopCh, ic)
	return nil
}

func (ic *ImportController) runPVCWorkers() {
	for ic.ProcessNextPvcItem() {
	}
}
<|endoftext|>


<commit_before>package chef

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "reflect"
    "testing"
)

var (
    testGroupJSON = "test/group.json"
)

func TestGroupFromJSONDecoder(t *testing.T) {
    if file, err := os.Open(testGroupJSON); err != nil {
        t.Error("Unexpected error '", err, "' during os.Open on", testGroupJSON)
    } else {
        dec := json.NewDecoder(file)
        var g Group
        if err := dec.Decode(&g); err == io.EOF {
            log.Println(g)
        } else if err != nil {
            log.Fatal(err)
        }
    }
}

// TODO: Break out these method tests into separate test functions.
func TestGroupsService_Methods(t *testing.T) {
    setup()
    defer teardown()

    // Set up our HTTP routes.
    // FIXME: We should return HTTP response codes as defined by the Chef API so we can test for them.
    mux.HandleFunc("/groups", func(w http.ResponseWriter, r *http.Request) {
        switch {
        case r.Method == "GET":
            fmt.Fprintf(w, `["group1", "group2"]`)
        case r.Method == "POST":
            fmt.Fprintf(w, `{ "uri": "http://localhost:4545/groups/group3" }`)
        }
    })

    mux.HandleFunc("/groups/group3", func(w http.ResponseWriter, r *http.Request) {
        switch {
        // TODO: Add true test for PUT, updating an existing value.
        case r.Method == "GET" || r.Method == "PUT":
            fmt.Fprintf(w, `{
                "name": "group3",
                "groupname": "group3",
                "orgname": "Test Org, LLC",
                "actors": ["tester"],
                "clients": ["tester"],
                "groups": ["nested-group"]
            }`)
        case r.Method == "DELETE":
        }
    })

    // Test list
    groups, err := client.Groups.List()
    if err != nil {
        t.Errorf("Groups.List returned error: %v", err)
    }

    listWant := []string{"group1", "group2"}

    if !reflect.DeepEqual(groups, listWant) {
        t.Errorf("Groups.List returned %+v, want %+v", groups, listWant)
    }

    // test Get
    group, err := client.Groups.Get("group3")
    if err != nil {
        t.Errorf("Groups.Get returned error: %v", err)
    }

    var wantGroup Group
    wantGroup.Name =  "group3"
    wantGroup.GroupName = "group3"
    wantGroup.OrgName = "Test Org, LLC"
    wantGroup.Actors = []string{"tester"}
    wantGroup.Clients = []string{"tester"}
    wantGroup.Groups = []string{"nested-group"}
    if !reflect.DeepEqual(group, wantGroup) {
        t.Errorf("Groups.Get returned %+v, want %+v", group, wantGroup)
    }

    // test Create
    res, err := client.Groups.Create(wantGroup)
    if err != nil {
        t.Errorf("Groups.Create returned error: %s", err.Error())
    }

    createResult := &GroupResult{"http://localhost:4545/groups/group3"}
    if !reflect.DeepEqual(createResult, res) {
        t.Errorf("Groups.Post returned %+v, want %+v", res, createResult)
    }

    // test Update
    updateRes, err := client.Groups.Update(group)
    if err != nil {
        t.Errorf("Groups.Update returned error", err)
    }

    if !reflect.DeepEqual(updateRes, group) {
        t.Errorf("Groups.Update returned %+v, want %+v", updateRes, group)
    }

    // test Delete
    err = client.Groups.Delete(group.Name)
    if err != nil {
        t.Errorf("Groups.Delete returned error", err)
    }
}
<commit_msg>Update the group tests<commit_after>package chef

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "reflect"
    "testing"
)

var (
    testGroupJSON = "test/group.json"
)

func TestGroupFromJSONDecoder(t *testing.T) {
    if file, err := os.Open(testGroupJSON); err != nil {
        t.Error("Unexpected error '", err, "' during os.Open on", testGroupJSON)
    } else {
        dec := json.NewDecoder(file)
        var g Group
        if err := dec.Decode(&g); err == io.EOF {
            log.Println(g)
        } else if err != nil {
            log.Fatal(err)
        }
    }
}

// TODO: Break out these method tests into separate test functions.
func TestGroupsService_Methods(t *testing.T) {
    setup()
    defer teardown()

    // Set up our HTTP routes.
    // FIXME: We should return HTTP response codes as defined by the Chef API so we can test for them.
    mux.HandleFunc("/groups", func(w http.ResponseWriter, r *http.Request) {
        switch {
        case r.Method == "GET":
            fmt.Fprintf(w, `{"group1": "https://url/for/group1", "group2": "https://url/for/group2"}`)
        case r.Method == "POST":
            fmt.Fprintf(w, `{ "uri": "http://localhost:4545/groups/group3" }`)
        }
    })

    mux.HandleFunc("/groups/group3", func(w http.ResponseWriter, r *http.Request) {
        switch {
        // TODO: Add true test for PUT, updating an existing value.
        case r.Method == "GET" || r.Method == "PUT":
            fmt.Fprintf(w, `{
                "name": "group3",
                "groupname": "group3",
                "orgname": "Test Org, LLC",
                "actors": ["tester"],
                "clients": ["tester"],
                "groups": ["nested-group"]
            }`)
        case r.Method == "DELETE":
        }
    })

    // Test list
    groups, err := client.Groups.List()
    if err != nil {
        t.Errorf("Groups.List returned error: %v", err)
    }

    listWant := map[string]string{ "group1": "https://url/for/group1", "group2": "https://url/for/group2"}

    if !reflect.DeepEqual(groups, listWant) {
        t.Errorf("Groups.List returned %+v, want %+v", groups, listWant)
    }

    // test Get
    group, err := client.Groups.Get("group3")
    if err != nil {
        t.Errorf("Groups.Get returned error: %v", err)
    }

    var wantGroup Group
    wantGroup.Name =  "group3"
    wantGroup.GroupName = "group3"
    wantGroup.OrgName = "Test Org, LLC"
    wantGroup.Actors = []string{"tester"}
    wantGroup.Clients = []string{"tester"}
    wantGroup.Groups = []string{"nested-group"}
    if !reflect.DeepEqual(group, wantGroup) {
        t.Errorf("Groups.Get returned %+v, want %+v", group, wantGroup)
    }

    // test Create
    res, err := client.Groups.Create(wantGroup)
    if err != nil {
        t.Errorf("Groups.Create returned error: %s", err.Error())
    }

    createResult := &GroupResult{"http://localhost:4545/groups/group3"}
    if !reflect.DeepEqual(createResult, res) {
        t.Errorf("Groups.Post returned %+v, want %+v", res, createResult)
    }

    // test Update
    updateRes, err := client.Groups.Update(group)
    if err != nil {
        t.Errorf("Groups.Update returned error: %v", err)
    }

    if !reflect.DeepEqual(updateRes, group) {
        t.Errorf("Groups.Update returned %+v, want %+v", updateRes, group)
    }

    // test Delete
    err = client.Groups.Delete(group.Name)
    if err != nil {
        t.Errorf("Groups.Delete returned error: %v", err)
    }
}
<|endoftext|>


<commit_before>package gui

import (
	"io/ioutil"
	"log"
	"strings"

	"github.com/felixangell/phi-editor/cfg"
	"github.com/felixangell/strife"
	"github.com/veandco/go-sdl2/sdl"
	"github.com/vinzmay/go-rope"
)

var (
	timer        int64 = 0
	reset_timer  int64 = 0
	should_draw  bool  = true
	should_flash bool
)

// TODO: allow font setting or whatever

type Buffer struct {
	BaseComponent
	font     *strife.Font
	contents []*rope.Rope
	curs     *Cursor
	cfg      *cfg.TomlConfig
}

func NewBuffer(conf *cfg.TomlConfig) *Buffer {
	config := conf
	if config == nil {
		config = cfg.NewDefaultConfig()
	}

	buffContents := []*rope.Rope{}
	buff := &Buffer{
		contents: buffContents,
		curs:     &Cursor{},
		cfg:      config,
	}

	{
		contents, err := ioutil.ReadFile(cfg.CONFIG_FULL_PATH)
		if err != nil {
			panic(err)
		}

		lines := strings.Split(string(contents), "\n")
		for _, line := range lines {
			buff.appendLine(line)
		}
	}

	return buff
}

func (b *Buffer) OnDispose() {

}

func (b *Buffer) OnInit() {}

func (b *Buffer) appendLine(val string) {
	b.contents = append(b.contents, rope.New(val))

	// because we've added a new line
	// we have to set the x to the start
	b.curs.x = 0
}

func (b *Buffer) insertRune(r rune) {
	log.Println("Inserting rune ", r, " into current line at ", b.curs.x, ":", b.curs.y)
	log.Println("Line before insert> ", b.contents[b.curs.y])

	b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(r))
	b.curs.move(1, 0)
}

func (b *Buffer) processTextInput(r rune) bool {
	b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(r))
	b.curs.move(1, 0)

	// we don't need to match braces
	// let's not continue any further
	if !b.cfg.Editor.Match_Braces {
		return true
	}

	matchingPair := int(r)

	// the offset in the ASCII Table is +2 for { and for [
	// but its +1 for parenthesis (
	offset := 2

	switch r {
	case '(':
		offset = 1
		fallthrough
	case '{':
		fallthrough
	case '[':
		matchingPair += offset
		b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(rune(matchingPair)))
	}

	return true
}

// processes a key press. returns if there
// was a key that MODIFIED the buffer.
func (b *Buffer) processActionKey(key int) bool {
	switch key {
	case sdl.K_RETURN:
		initial_x := b.curs.x
		prevLineLen := b.contents[b.curs.y].Len()

		var newRope *rope.Rope
		if initial_x < prevLineLen && initial_x > 0 {
			// we're not at the end of the line, but we're not at
			// the start, i.e. we're SPLITTING the line
			left, right := b.contents[b.curs.y].Split(initial_x)
			newRope = right
			b.contents[b.curs.y] = left
		} else if initial_x == 0 {
			// we're at the start of a line, so we want to
			// shift the line down and insert an empty line
			// above it!
			b.contents = append(b.contents, new(rope.Rope))      // grow
			copy(b.contents[b.curs.y+1:], b.contents[b.curs.y:]) // shift
			b.contents[b.curs.y] = new(rope.Rope)                // set
			b.curs.move(0, 1)
			return true
		} else {
			// we're at the end of a line
			newRope = new(rope.Rope)
		}

		b.curs.move(0, 1)
		for x := 0; x < initial_x; x++ {
			// TODO(Felix): there's a bug here where
			// this doesn't account for the rendered x
			// position when we use tabs as tabs and not spaces
			b.curs.move(-1, 0)
		}

		b.contents = append(b.contents, nil)
		copy(b.contents[b.curs.y+1:], b.contents[b.curs.y:])
		b.contents[b.curs.y] = newRope
		return true
	case sdl.K_BACKSPACE:
		if b.curs.x > 0 {
			offs := -1
			if !b.cfg.Editor.Tabs_Are_Spaces {
				if b.contents[b.curs.y].Index(b.curs.x) == '\t' {
					offs = int(-b.cfg.Editor.Tab_Size)
				}
			} else if b.cfg.Editor.Hungry_Backspace && b.curs.x >= int(b.cfg.Editor.Tab_Size) {
				// cut out the last {TAB_SIZE} amount of characters
				// and check em
				tabSize := int(b.cfg.Editor.Tab_Size)
				lastTabSizeChars := b.contents[b.curs.y].Substr(b.curs.x+1-tabSize, tabSize).String()
				if strings.Compare(lastTabSizeChars, b.makeTab()) == 0 {
					// delete {TAB_SIZE} amount of characters
					// from the cursors x pos
					for i := 0; i < int(b.cfg.Editor.Tab_Size); i++ {
						b.contents[b.curs.y] = b.contents[b.curs.y].Delete(b.curs.x, 1)
						b.curs.move(-1, 0)
					}
					break
				}
			}

			b.contents[b.curs.y] = b.contents[b.curs.y].Delete(b.curs.x, 1)
			b.curs.moveRender(-1, 0, offs, 0)
		} else if b.curs.x == 0 && b.curs.y > 0 {
			// start of line, wrap to previous
			prevLineLen := b.contents[b.curs.y-1].Len()
			b.contents[b.curs.y-1] = b.contents[b.curs.y-1].Concat(b.contents[b.curs.y])
			b.contents = append(b.contents[:b.curs.y], b.contents[b.curs.y+1:]...)
			b.curs.move(prevLineLen, -1)
		}
		return true
	case sdl.K_RIGHT:
		currLineLength := b.contents[b.curs.y].Len()
		if b.curs.x >= currLineLength && b.curs.y < len(b.contents)-1 {
			// we're at the end of the line and we have
			// some lines after, let's wrap around
			b.curs.move(0, 1)
			b.curs.move(-currLineLength, 0)
		} else if b.curs.x < b.contents[b.curs.y].Len() {
			// we have characters to the right, let's move along
			b.curs.move(1, 0)
		}
		return true
	case sdl.K_LEFT:
		if b.curs.x == 0 && b.curs.y > 0 {
			b.curs.move(b.contents[b.curs.y-1].Len(), -1)

		} else if b.curs.x > 0 {
			b.curs.move(-1, 0)
		}
		return true
	case sdl.K_UP:
		if b.curs.y > 0 {
			offs := 0
			prevLineLen := b.contents[b.curs.y-1].Len()
			if b.curs.x > prevLineLen {
				offs = prevLineLen - b.curs.x
			}
			// TODO: offset should account for tabs
			b.curs.move(offs, -1)
		}
		return true
	case sdl.K_DOWN:
		if b.curs.y < len(b.contents)-1 {
			offs := 0
			nextLineLen := b.contents[b.curs.y+1].Len()
			if b.curs.x > nextLineLen {
				offs = nextLineLen - b.curs.x
			}
			// TODO: offset should account for tabs
			b.curs.move(offs, 1)
		}
		return true
	case sdl.K_TAB:
		if b.cfg.Editor.Tabs_Are_Spaces {
			// make an empty rune array of TAB_SIZE, cast to string
			// and insert it.
			b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, b.makeTab())
			b.curs.move(int(b.cfg.Editor.Tab_Size), 0)
		} else {
			b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string('\t'))
			// the actual position is + 1, but we make it
			// move by TAB_SIZE characters on the view.
			b.curs.moveRender(1, 0, int(b.cfg.Editor.Tab_Size), 0)
		}
		return true
	}

	return false
}

// TODO(Felix) this is really stupid
func (b *Buffer) makeTab() string {
	blah := []rune{}
	for i := 0; i < int(b.cfg.Editor.Tab_Size); i++ {
		blah = append(blah, ' ')
	}
	return string(blah)
}

func (b *Buffer) OnUpdate() bool {
	prev_x := b.curs.x
	prev_y := b.curs.y

	if strife.PollKeys() {
		keyCode := strife.PopKey()

		// try process this key input as an
		// action first
		actionPerformed := b.processActionKey(keyCode)
		if actionPerformed {
			return true
		}

		textEntered := b.processTextInput(rune(keyCode))
		if textEntered {
			return true
		}
	}

	// FIXME handle focus properly
	if b.inputHandler == nil {
		return false
	}

	if b.curs.x != prev_x || b.curs.y != prev_y {
		should_draw = true
		should_flash = false
		reset_timer = strife.CurrentTimeMillis()
	}

	if !should_flash && strife.CurrentTimeMillis()-reset_timer > b.cfg.Cursor.Reset_Delay {
		should_flash = true
	}

	if strife.CurrentTimeMillis()-timer > b.cfg.Cursor.Flash_Rate && (should_flash && b.cfg.Cursor.Flash) {
		timer = strife.CurrentTimeMillis()
		should_draw = !should_draw
	}

	return false
}

// dimensions of the last character we rendered
var last_w, last_h int
var lineIndex int = 0

func (b *Buffer) OnRender(ctx *strife.Renderer) {
	// BACKGROUND
	ctx.SetColor(strife.HexRGB(b.cfg.Theme.Background))
	ctx.Rect(b.x, b.y, b.w, b.h, strife.Fill)

	if b.cfg.Editor.Highlight_Line {
		ctx.SetColor(strife.Black) // highlight_line_col?
		ctx.Rect(b.x, b.y+b.curs.ry*last_h, b.w, last_h, strife.Fill)
	}

	// render the ol' cursor
	if should_draw && b.cfg.Cursor.Draw {
		cursorWidth := b.cfg.Cursor.GetCaretWidth()
		if cursorWidth == -1 {
			cursorWidth = last_w
		}

		ctx.SetColor(strife.HexRGB(b.cfg.Theme.Cursor)) // caret colour
		ctx.Rect(b.x+b.curs.rx*last_w, b.y+b.curs.ry*last_h, cursorWidth, last_h, strife.Fill)
	}

	source := b.contents
	if int(last_h) > 0 && int(b.h) != 0 {
		// work out how many lines can fit into
		// the buffer, and set the source to
		// slice the line buffer accordingly
		visibleLines := int(b.h) / int(last_h)
		if len(b.contents) > visibleLines {
			if lineIndex+visibleLines >= len(b.contents) {
				lineIndex = len(b.contents) - visibleLines
			}
			source = b.contents[lineIndex : lineIndex+visibleLines]
		}
	}

	var y_col int
	for _, rope := range source {
		// this is because if we had the following
		// text input:
		//
		// Foo
		// _			<-- underscore is a space!
		// Blah
		// and we delete that underscore... it causes
		// a panic because there are no characters in
		// the empty string!
		if rope.Len() == 0 {
			// even though the string is empty
			// we still need to offset it by a line
			y_col += 1
			continue
		}

		var x_col int
		for _, char := range rope.String() {
			switch char {
			case '\n':
				x_col = 0
				y_col += 1
				continue
			case '\t':
				x_col += b.cfg.Editor.Tab_Size
				continue
			}

			x_col += 1

			ctx.SetColor(strife.HexRGB(b.cfg.Theme.Foreground))

			// if we're currently over a character then set
			// the font colour to something else
			if b.curs.x+1 == x_col && b.curs.y == y_col && should_draw {
				ctx.SetColor(strife.Green)
			}

			last_w, last_h = ctx.String(string(char), b.x+((x_col-1)*last_w), b.y+(y_col*last_h))
		}

		y_col += 1
	}

}
<commit_msg>use theme cursor invert rather than fixed colour<commit_after>package gui

import (
	"io/ioutil"
	"log"
	"strings"

	"github.com/felixangell/phi-editor/cfg"
	"github.com/felixangell/strife"
	"github.com/veandco/go-sdl2/sdl"
	"github.com/vinzmay/go-rope"
)

var (
	timer        int64 = 0
	reset_timer  int64 = 0
	should_draw  bool  = true
	should_flash bool
)

// TODO: allow font setting or whatever

type Buffer struct {
	BaseComponent
	font     *strife.Font
	contents []*rope.Rope
	curs     *Cursor
	cfg      *cfg.TomlConfig
}

func NewBuffer(conf *cfg.TomlConfig) *Buffer {
	config := conf
	if config == nil {
		config = cfg.NewDefaultConfig()
	}

	buffContents := []*rope.Rope{}
	buff := &Buffer{
		contents: buffContents,
		curs:     &Cursor{},
		cfg:      config,
	}

	{
		contents, err := ioutil.ReadFile(cfg.CONFIG_FULL_PATH)
		if err != nil {
			panic(err)
		}

		lines := strings.Split(string(contents), "\n")
		for _, line := range lines {
			buff.appendLine(line)
		}
	}

	return buff
}

func (b *Buffer) OnDispose() {

}

func (b *Buffer) OnInit() {}

func (b *Buffer) appendLine(val string) {
	b.contents = append(b.contents, rope.New(val))

	// because we've added a new line
	// we have to set the x to the start
	b.curs.x = 0
}

func (b *Buffer) insertRune(r rune) {
	log.Println("Inserting rune ", r, " into current line at ", b.curs.x, ":", b.curs.y)
	log.Println("Line before insert> ", b.contents[b.curs.y])

	b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(r))
	b.curs.move(1, 0)
}

func (b *Buffer) processTextInput(r rune) bool {
	b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(r))
	b.curs.move(1, 0)

	// we don't need to match braces
	// let's not continue any further
	if !b.cfg.Editor.Match_Braces {
		return true
	}

	matchingPair := int(r)

	// the offset in the ASCII Table is +2 for { and for [
	// but its +1 for parenthesis (
	offset := 2

	switch r {
	case '(':
		offset = 1
		fallthrough
	case '{':
		fallthrough
	case '[':
		matchingPair += offset
		b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(rune(matchingPair)))
	}

	return true
}

// processes a key press. returns if there
// was a key that MODIFIED the buffer.
func (b *Buffer) processActionKey(key int) bool {
	switch key {
	case sdl.K_RETURN:
		initial_x := b.curs.x
		prevLineLen := b.contents[b.curs.y].Len()

		var newRope *rope.Rope
		if initial_x < prevLineLen && initial_x > 0 {
			// we're not at the end of the line, but we're not at
			// the start, i.e. we're SPLITTING the line
			left, right := b.contents[b.curs.y].Split(initial_x)
			newRope = right
			b.contents[b.curs.y] = left
		} else if initial_x == 0 {
			// we're at the start of a line, so we want to
			// shift the line down and insert an empty line
			// above it!
			b.contents = append(b.contents, new(rope.Rope))      // grow
			copy(b.contents[b.curs.y+1:], b.contents[b.curs.y:]) // shift
			b.contents[b.curs.y] = new(rope.Rope)                // set
			b.curs.move(0, 1)
			return true
		} else {
			// we're at the end of a line
			newRope = new(rope.Rope)
		}

		b.curs.move(0, 1)
		for x := 0; x < initial_x; x++ {
			// TODO(Felix): there's a bug here where
			// this doesn't account for the rendered x
			// position when we use tabs as tabs and not spaces
			b.curs.move(-1, 0)
		}

		b.contents = append(b.contents, nil)
		copy(b.contents[b.curs.y+1:], b.contents[b.curs.y:])
		b.contents[b.curs.y] = newRope
		return true
	case sdl.K_BACKSPACE:
		if b.curs.x > 0 {
			offs := -1
			if !b.cfg.Editor.Tabs_Are_Spaces {
				if b.contents[b.curs.y].Index(b.curs.x) == '\t' {
					offs = int(-b.cfg.Editor.Tab_Size)
				}
			} else if b.cfg.Editor.Hungry_Backspace && b.curs.x >= int(b.cfg.Editor.Tab_Size) {
				// cut out the last {TAB_SIZE} amount of characters
				// and check em
				tabSize := int(b.cfg.Editor.Tab_Size)
				lastTabSizeChars := b.contents[b.curs.y].Substr(b.curs.x+1-tabSize, tabSize).String()
				if strings.Compare(lastTabSizeChars, b.makeTab()) == 0 {
					// delete {TAB_SIZE} amount of characters
					// from the cursors x pos
					for i := 0; i < int(b.cfg.Editor.Tab_Size); i++ {
						b.contents[b.curs.y] = b.contents[b.curs.y].Delete(b.curs.x, 1)
						b.curs.move(-1, 0)
					}
					break
				}
			}

			b.contents[b.curs.y] = b.contents[b.curs.y].Delete(b.curs.x, 1)
			b.curs.moveRender(-1, 0, offs, 0)
		} else if b.curs.x == 0 && b.curs.y > 0 {
			// start of line, wrap to previous
			prevLineLen := b.contents[b.curs.y-1].Len()
			b.contents[b.curs.y-1] = b.contents[b.curs.y-1].Concat(b.contents[b.curs.y])
			b.contents = append(b.contents[:b.curs.y], b.contents[b.curs.y+1:]...)
			b.curs.move(prevLineLen, -1)
		}
		return true
	case sdl.K_RIGHT:
		currLineLength := b.contents[b.curs.y].Len()
		if b.curs.x >= currLineLength && b.curs.y < len(b.contents)-1 {
			// we're at the end of the line and we have
			// some lines after, let's wrap around
			b.curs.move(0, 1)
			b.curs.move(-currLineLength, 0)
		} else if b.curs.x < b.contents[b.curs.y].Len() {
			// we have characters to the right, let's move along
			b.curs.move(1, 0)
		}
		return true
	case sdl.K_LEFT:
		if b.curs.x == 0 && b.curs.y > 0 {
			b.curs.move(b.contents[b.curs.y-1].Len(), -1)

		} else if b.curs.x > 0 {
			b.curs.move(-1, 0)
		}
		return true
	case sdl.K_UP:
		if b.curs.y > 0 {
			offs := 0
			prevLineLen := b.contents[b.curs.y-1].Len()
			if b.curs.x > prevLineLen {
				offs = prevLineLen - b.curs.x
			}
			// TODO: offset should account for tabs
			b.curs.move(offs, -1)
		}
		return true
	case sdl.K_DOWN:
		if b.curs.y < len(b.contents)-1 {
			offs := 0
			nextLineLen := b.contents[b.curs.y+1].Len()
			if b.curs.x > nextLineLen {
				offs = nextLineLen - b.curs.x
			}
			// TODO: offset should account for tabs
			b.curs.move(offs, 1)
		}
		return true
	case sdl.K_TAB:
		if b.cfg.Editor.Tabs_Are_Spaces {
			// make an empty rune array of TAB_SIZE, cast to string
			// and insert it.
			b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, b.makeTab())
			b.curs.move(int(b.cfg.Editor.Tab_Size), 0)
		} else {
			b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string('\t'))
			// the actual position is + 1, but we make it
			// move by TAB_SIZE characters on the view.
			b.curs.moveRender(1, 0, int(b.cfg.Editor.Tab_Size), 0)
		}
		return true
	}

	return false
}

// TODO(Felix) this is really stupid
func (b *Buffer) makeTab() string {
	blah := []rune{}
	for i := 0; i < int(b.cfg.Editor.Tab_Size); i++ {
		blah = append(blah, ' ')
	}
	return string(blah)
}

func (b *Buffer) OnUpdate() bool {
	prev_x := b.curs.x
	prev_y := b.curs.y

	if strife.PollKeys() {
		keyCode := strife.PopKey()

		// try process this key input as an
		// action first
		actionPerformed := b.processActionKey(keyCode)
		if actionPerformed {
			return true
		}

		textEntered := b.processTextInput(rune(keyCode))
		if textEntered {
			return true
		}
	}

	// FIXME handle focus properly
	if b.inputHandler == nil {
		return false
	}

	if b.curs.x != prev_x || b.curs.y != prev_y {
		should_draw = true
		should_flash = false
		reset_timer = strife.CurrentTimeMillis()
	}

	if !should_flash && strife.CurrentTimeMillis()-reset_timer > b.cfg.Cursor.Reset_Delay {
		should_flash = true
	}

	if strife.CurrentTimeMillis()-timer > b.cfg.Cursor.Flash_Rate && (should_flash && b.cfg.Cursor.Flash) {
		timer = strife.CurrentTimeMillis()
		should_draw = !should_draw
	}

	return false
}

// dimensions of the last character we rendered
var last_w, last_h int
var lineIndex int = 0

func (b *Buffer) OnRender(ctx *strife.Renderer) {
	// BACKGROUND
	ctx.SetColor(strife.HexRGB(b.cfg.Theme.Background))
	ctx.Rect(b.x, b.y, b.w, b.h, strife.Fill)

	if b.cfg.Editor.Highlight_Line {
		ctx.SetColor(strife.Black) // highlight_line_col?
		ctx.Rect(b.x, b.y+b.curs.ry*last_h, b.w, last_h, strife.Fill)
	}

	// render the ol' cursor
	if should_draw && b.cfg.Cursor.Draw {
		cursorWidth := b.cfg.Cursor.GetCaretWidth()
		if cursorWidth == -1 {
			cursorWidth = last_w
		}

		ctx.SetColor(strife.HexRGB(b.cfg.Theme.Cursor)) // caret colour
		ctx.Rect(b.x+b.curs.rx*last_w, b.y+b.curs.ry*last_h, cursorWidth, last_h, strife.Fill)
	}

	source := b.contents
	if int(last_h) > 0 && int(b.h) != 0 {
		// work out how many lines can fit into
		// the buffer, and set the source to
		// slice the line buffer accordingly
		visibleLines := int(b.h) / int(last_h)
		if len(b.contents) > visibleLines {
			if lineIndex+visibleLines >= len(b.contents) {
				lineIndex = len(b.contents) - visibleLines
			}
			source = b.contents[lineIndex : lineIndex+visibleLines]
		}
	}

	var y_col int
	for _, rope := range source {
		// this is because if we had the following
		// text input:
		//
		// Foo
		// _			<-- underscore is a space!
		// Blah
		// and we delete that underscore... it causes
		// a panic because there are no characters in
		// the empty string!
		if rope.Len() == 0 {
			// even though the string is empty
			// we still need to offset it by a line
			y_col += 1
			continue
		}

		var x_col int
		for _, char := range rope.String() {
			switch char {
			case '\n':
				x_col = 0
				y_col += 1
				continue
			case '\t':
				x_col += b.cfg.Editor.Tab_Size
				continue
			}

			x_col += 1

			ctx.SetColor(strife.HexRGB(b.cfg.Theme.Foreground))

			// if we're currently over a character then set
			// the font colour to something else
			if b.curs.x+1 == x_col && b.curs.y == y_col && should_draw {
				ctx.SetColor(strife.HexRGB(b.cfg.Theme.Cursor_Invert))
			}

			last_w, last_h = ctx.String(string(char), b.x+((x_col-1)*last_w), b.y+(y_col*last_h))
		}

		y_col += 1
	}

}
<|endoftext|>