<commit_before>package service

import (
	"context"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/da4nik/swanager/config"
	"github.com/da4nik/swanager/core/entities"
	"github.com/da4nik/swanager/core/swarm/task"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/mount"
	"github.com/docker/docker/api/types/swarm"
	"github.com/docker/docker/client"
)

// StatusStruct represents service state
type StatusStruct struct {
	TaskID    string
	Node      string
	Status    string
	Timestamp time.Time
}

// SpecOptions service create params
type SpecOptions struct {
	Service     *entities.Service
	NetworkName string
	Index       uint64
}

// Create creates swarm service form Service entity
func Create(opts SpecOptions) (string, error) {
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	serviceSpec := getServiceSpec(opts)
	serviceCreateOptions := types.ServiceCreateOptions{}

	log().WithField("spec", fmt.Sprintf("%+v", serviceSpec)).Debug("Creating swarm service")

	responce, err := cli.ServiceCreate(context.Background(), serviceSpec, serviceCreateOptions)
	if err != nil {
		panic(err)
	}

	if len(responce.Warnings) > 0 {
		log().Debug("Warnings:")
		log().Debugf("%+v", responce.Warnings)
	}

	return responce.ID, nil
}

// Update - updates existing service
func Update(opts SpecOptions) error {
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	serviceSpec := getServiceSpec(opts)
	serviceUpdateOptions := types.ServiceUpdateOptions{}

	responce, err := cli.ServiceUpdate(context.Background(), opts.Service.NSName, swarm.Version{Index: opts.Index}, serviceSpec, serviceUpdateOptions)
	if err != nil {
		panic(err)
	}

	if len(responce.Warnings) > 0 {
		log().Debug("Warnings:")
		log().Debugf("%+v", responce.Warnings)
	}

	return nil
}

// Remove removes service
func Remove(service *entities.Service) error {
	log().Debugf("Removing service. %s", service.NSName)
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	err = cli.ServiceRemove(context.Background(), service.NSName)
	if err != nil {
		fmt.Println(err)
		return err
	}

	return err
}

// Inspect return service status
func Inspect(service *entities.Service) (*swarm.Service, error) {
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	serviceInspection, _, err := cli.ServiceInspectWithRaw(context.Background(), service.NSName)
	if err != nil {
		return nil, err
	}

	return &serviceInspection, nil
}

// Status returns service status
func Status(service *entities.Service) ([]StatusStruct, error) {
	tasks, err := task.ListFor(service.NSName)
	if err != nil {
		return nil, err
	}

	result := make([]StatusStruct, 0)
	for _, task := range *tasks {
		result = append(result, StatusStruct{
			TaskID:    task.ID,
			Node:      task.NodeID,
			Status:    string(task.Status.State),
			Timestamp: task.Status.Timestamp,
		})
	}
	return result, nil
}

func getServiceSpec(opts SpecOptions) swarm.ServiceSpec {
	opts.Service.LoadApplication()

	mounts := getServiceVolumes(opts.Service)

	containerSpec := swarm.ContainerSpec{
		Image:  opts.Service.Image,
		Mounts: mounts,
		Env:    prepareEnvVars(opts.Service),
	}

	updateConfig := swarm.UpdateConfig{
		Parallelism:     opts.Service.Parallelism,
		FailureAction:   "pause",
		MaxFailureRatio: 0.5,
	}

	return swarm.ServiceSpec{
		Annotations: swarm.Annotations{
			Name: opts.Service.NSName,
			Labels: map[string]string{
				"swanager_id":    opts.Service.ID,
				"application_id": opts.Service.Application.ID,
			},
		},
		TaskTemplate: swarm.TaskSpec{
			ContainerSpec: containerSpec,
			Networks: []swarm.NetworkAttachmentConfig{
				swarm.NetworkAttachmentConfig{Target: opts.NetworkName},
			},
		},
		Mode: swarm.ServiceMode{
			Replicated: &swarm.ReplicatedService{Replicas: opts.Service.Replicas},
		},
		UpdateConfig: &updateConfig,
		EndpointSpec: &swarm.EndpointSpec{
			Mode:  swarm.ResolutionModeVIP,
			Ports: preparePorts(opts.Service),
		},
	}
}

func getServiceVolumes(service *entities.Service) []mount.Mount {
	service.LoadApplication()

	result := make([]mount.Mount, 0)
	for _, vol := range service.Volumes {
		sourcePath := getMountPathPrefix() + vol
		os.MkdirAll(sourcePath, 0777)

		result = append(result, mount.Mount{
			Type:     mount.TypeBind,
			Source:   getMountPathPrefix() + vol,
			Target:   vol,
			ReadOnly: false,
		})
	}
	return result
}

// getServiceMounts returns mount struct based on image volumes
// func getServiceMounts(service *entities.Service) ([]mount.Mount, error) {
// 	result := make([]mount.Mount, 0)
// 	vols, err := image.Volumes(service.Image)
// 	if err != nil {
// 		return result, err
// 	}
//
// 	volumeOptions := mount.VolumeOptions{
// 		Labels: map[string]string{
// 			"application_id": service.Application.ID,
// 			"service_id":     service.ID,
// 		},
// 	}
//
// 	for _, vol := range *vols {
// 		result = append(result, mount.Mount{
// 			Type:          "bind",
// 			Source:        getMountPathPrefix() + vol,
// 			Target:        vol,
// 			VolumeOptions: &volumeOptions,
// 		})
// 	}
//
// 	return result, nil
// }

func prepareEnvVars(service *entities.Service) (vars []string) {
	for _, envVar := range service.EnvVariables {
		vars = append(vars, fmt.Sprintf("%s=%s", envVar.Name, envVar.Value))
	}
	return
}

func preparePorts(service *entities.Service) (ports []swarm.PortConfig) {

	for _, port := range service.PublishedPorts {
		ports = append(ports, swarm.PortConfig{
			Name:          "swanager_port",
			Protocol:      stringToProtocol(port.Protocol),
			TargetPort:    port.Internal,
			PublishedPort: port.External,
			PublishMode:   swarm.PortConfigPublishModeIngress,
		})
	}
	return
}

func stringToProtocol(protocol string) swarm.PortConfigProtocol {
	switch strings.ToLower(protocol) {
	case "udp":
		return swarm.PortConfigProtocolUDP
	}
	return swarm.PortConfigProtocolTCP
}

func getMountPathPrefix() string {
	return config.MountPathPrefix
}

func log() *logrus.Entry {
	return logrus.WithField("module", "swarm.service")
}
<commit_msg>Mount folders in folder, based on user id<commit_after>package service

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/da4nik/swanager/config"
	"github.com/da4nik/swanager/core/entities"
	"github.com/da4nik/swanager/core/swarm/task"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/mount"
	"github.com/docker/docker/api/types/swarm"
	"github.com/docker/docker/client"
)

// StatusStruct represents service state
type StatusStruct struct {
	TaskID    string
	Node      string
	Status    string
	Timestamp time.Time
}

// SpecOptions service create params
type SpecOptions struct {
	Service     *entities.Service
	NetworkName string
	Index       uint64
}

// Create creates swarm service form Service entity
func Create(opts SpecOptions) (string, error) {
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	serviceSpec := getServiceSpec(opts)
	serviceCreateOptions := types.ServiceCreateOptions{}

	log().WithField("spec", fmt.Sprintf("%+v", serviceSpec)).Debug("Creating swarm service")

	responce, err := cli.ServiceCreate(context.Background(), serviceSpec, serviceCreateOptions)
	if err != nil {
		panic(err)
	}

	if len(responce.Warnings) > 0 {
		log().Debug("Warnings:")
		log().Debugf("%+v", responce.Warnings)
	}

	return responce.ID, nil
}

// Update - updates existing service
func Update(opts SpecOptions) error {
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	serviceSpec := getServiceSpec(opts)
	serviceUpdateOptions := types.ServiceUpdateOptions{}

	responce, err := cli.ServiceUpdate(context.Background(), opts.Service.NSName, swarm.Version{Index: opts.Index}, serviceSpec, serviceUpdateOptions)
	if err != nil {
		panic(err)
	}

	if len(responce.Warnings) > 0 {
		log().Debug("Warnings:")
		log().Debugf("%+v", responce.Warnings)
	}

	return nil
}

// Remove removes service
func Remove(service *entities.Service) error {
	log().Debugf("Removing service. %s", service.NSName)
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	err = cli.ServiceRemove(context.Background(), service.NSName)
	if err != nil {
		fmt.Println(err)
		return err
	}

	return err
}

// Inspect return service status
func Inspect(service *entities.Service) (*swarm.Service, error) {
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	serviceInspection, _, err := cli.ServiceInspectWithRaw(context.Background(), service.NSName)
	if err != nil {
		return nil, err
	}

	return &serviceInspection, nil
}

// Status returns service status
func Status(service *entities.Service) ([]StatusStruct, error) {
	tasks, err := task.ListFor(service.NSName)
	if err != nil {
		return nil, err
	}

	result := make([]StatusStruct, 0)
	for _, task := range *tasks {
		result = append(result, StatusStruct{
			TaskID:    task.ID,
			Node:      task.NodeID,
			Status:    string(task.Status.State),
			Timestamp: task.Status.Timestamp,
		})
	}
	return result, nil
}

func getServiceSpec(opts SpecOptions) swarm.ServiceSpec {
	opts.Service.LoadApplication()

	mounts := getServiceVolumes(opts.Service)

	containerSpec := swarm.ContainerSpec{
		Image:  opts.Service.Image,
		Mounts: mounts,
		Env:    prepareEnvVars(opts.Service),
	}

	updateConfig := swarm.UpdateConfig{
		Parallelism:     opts.Service.Parallelism,
		FailureAction:   "pause",
		MaxFailureRatio: 0.5,
	}

	return swarm.ServiceSpec{
		Annotations: swarm.Annotations{
			Name: opts.Service.NSName,
			Labels: map[string]string{
				"swanager_id":    opts.Service.ID,
				"application_id": opts.Service.Application.ID,
			},
		},
		TaskTemplate: swarm.TaskSpec{
			ContainerSpec: containerSpec,
			Networks: []swarm.NetworkAttachmentConfig{
				swarm.NetworkAttachmentConfig{Target: opts.NetworkName},
			},
		},
		Mode: swarm.ServiceMode{
			Replicated: &swarm.ReplicatedService{Replicas: opts.Service.Replicas},
		},
		UpdateConfig: &updateConfig,
		EndpointSpec: &swarm.EndpointSpec{
			Mode:  swarm.ResolutionModeVIP,
			Ports: preparePorts(opts.Service),
		},
	}
}

func getServiceVolumes(service *entities.Service) []mount.Mount {
	service.LoadApplication()

	result := make([]mount.Mount, 0)
	for _, vol := range service.Volumes {
		sourcePath := filepath.Join(getMountPathPrefix(service), vol)
		os.MkdirAll(sourcePath, 0777)

		result = append(result, mount.Mount{
			Type:     mount.TypeBind,
			Source:   sourcePath,
			Target:   vol,
			ReadOnly: false,
		})
	}
	return result
}

// getServiceMounts returns mount struct based on image volumes
// func getServiceMounts(service *entities.Service) ([]mount.Mount, error) {
// 	result := make([]mount.Mount, 0)
// 	vols, err := image.Volumes(service.Image)
// 	if err != nil {
// 		return result, err
// 	}
//
// 	volumeOptions := mount.VolumeOptions{
// 		Labels: map[string]string{
// 			"application_id": service.Application.ID,
// 			"service_id":     service.ID,
// 		},
// 	}
//
// 	for _, vol := range *vols {
// 		result = append(result, mount.Mount{
// 			Type:          "bind",
// 			Source:        getMountPathPrefix() + vol,
// 			Target:        vol,
// 			VolumeOptions: &volumeOptions,
// 		})
// 	}
//
// 	return result, nil
// }

func prepareEnvVars(service *entities.Service) (vars []string) {
	for _, envVar := range service.EnvVariables {
		vars = append(vars, fmt.Sprintf("%s=%s", envVar.Name, envVar.Value))
	}
	return
}

func preparePorts(service *entities.Service) (ports []swarm.PortConfig) {

	for _, port := range service.PublishedPorts {
		ports = append(ports, swarm.PortConfig{
			Name:          "swanager_port",
			Protocol:      stringToProtocol(port.Protocol),
			TargetPort:    port.Internal,
			PublishedPort: port.External,
			PublishMode:   swarm.PortConfigPublishModeIngress,
		})
	}
	return
}

func stringToProtocol(protocol string) swarm.PortConfigProtocol {
	switch strings.ToLower(protocol) {
	case "udp":
		return swarm.PortConfigProtocolUDP
	}
	return swarm.PortConfigProtocolTCP
}

func getMountPathPrefix(service *entities.Service) string {
	return filepath.Join(config.MountPathPrefix, service.UserID)
}

func log() *logrus.Entry {
	return logrus.WithField("module", "swarm.service")
}
<|endoftext|>


<commit_before>package go_koans

func aboutPointers() {
	{
		a := 3
		b := a // 'b' is a copy of 'a' (all assignments are copy-operations)

		b++

		assert(a == __int__) // variables are independent of one another
	}

	{
		a := 3
		b := &a // 'b' is the address of 'a'

		*b = *b + 2          // de-referencing 'b' means acting like a mutable copy of 'a'
		assert(a == __int__) // pointers seem complicated at first but are actually simple
	}

	{
		increment := func(i int) {
			i++
		}

		a := 3
		increment(a)
		assert(a == __int__) // variables are always passed by value, and so a copy is made
	}

	{
		realIncrement := func(i *int) {
			(*i)++
		}

		b := 3
		realIncrement(&b)
		assert(b == __int__) // but passing a pointer allows others to mutate the value pointed to
	}
}
<commit_msg>Koan pointers<commit_after>package go_koans

func aboutPointers() {
	{
		a := 3
		b := a // 'b' is a copy of 'a' (all assignments are copy-operations)

		b++

		assert(a == 3) // variables are independent of one another
	}

	{
		a := 3
		b := &a // 'b' is the address of 'a'

		*b = *b + 2          // de-referencing 'b' means acting like a mutable copy of 'a'
		assert(a == 5) // pointers seem complicated at first but are actually simple
	}

	{
		increment := func(i int) {
			i++
		}

		a := 3
		increment(a)
		assert(a == 3) // variables are always passed by value, and so a copy is made
	}

	{
		realIncrement := func(i *int) {
			(*i)++
		}

		b := 3
		realIncrement(&b)
		assert(b == 4) // but passing a pointer allows others to mutate the value pointed to
	}
}
<|endoftext|>


<commit_before>package graph

import (
	"testing"
)

func TestTopologicalSort(t *testing.T) {
	graph := New(Directed)
	nodes := make([]Node, 0)
	// create graph on page 613 of CLRS ed. 3
	nodes = append(nodes, graph.MakeNode()) // shirt
	nodes = append(nodes, graph.MakeNode()) // tie
	nodes = append(nodes, graph.MakeNode()) // jacket
	nodes = append(nodes, graph.MakeNode()) // belt
	nodes = append(nodes, graph.MakeNode()) // watch
	nodes = append(nodes, graph.MakeNode()) // undershorts
	nodes = append(nodes, graph.MakeNode()) // pants
	nodes = append(nodes, graph.MakeNode()) // shoes
	nodes = append(nodes, graph.MakeNode()) // socks
	graph.MakeEdge(nodes[0], nodes[1])
	graph.MakeEdge(nodes[1], nodes[2])
	graph.MakeEdge(nodes[0], nodes[3])
	graph.MakeEdge(nodes[3], nodes[2])
	graph.MakeEdge(nodes[5], nodes[6])
	graph.MakeEdge(nodes[5], nodes[7])
	graph.MakeEdge(nodes[6], nodes[3])
	graph.MakeEdge(nodes[6], nodes[7])
	graph.MakeEdge(nodes[8], nodes[7])
	graph.verify(t)
	wantOrder := make([]Node, len(graph.nodes))
	wantOrder[0] = nodes[8] // socks
	wantOrder[1] = nodes[5] // undershorts
	wantOrder[2] = nodes[6] // pants
	wantOrder[3] = nodes[7] // shoes
	wantOrder[4] = nodes[4] // watch
	wantOrder[5] = nodes[0] // shirt
	wantOrder[6] = nodes[3] // belt
	wantOrder[7] = nodes[1] // tie
	wantOrder[8] = nodes[2] // jacket
	result := graph.TopologicalSort()
	for i := range result {
		if result[i] != wantOrder[i] {
			t.Errorf("index %v in result != wanted, value: %v, want value: %v", i, result[i], wantOrder[i])
		}
	}
}

func TestStronglyConnectedComponents(t *testing.T) {
	graph := New(Directed)
	nodes := make([]Node, 0)
	// create SCC graph on page 616 of CLRS ed 3
	nodes = append(nodes, graph.MakeNode()) //0, c
	nodes = append(nodes, graph.MakeNode()) //1, g
	nodes = append(nodes, graph.MakeNode()) //2, f
	nodes = append(nodes, graph.MakeNode()) //3, h
	nodes = append(nodes, graph.MakeNode()) //4, d
	nodes = append(nodes, graph.MakeNode()) //5, b
	nodes = append(nodes, graph.MakeNode()) //6, e
	nodes = append(nodes, graph.MakeNode()) //7, a
	graph.MakeEdge(nodes[0], nodes[1])
	graph.MakeEdge(nodes[0], nodes[4])
	graph.MakeEdge(nodes[1], nodes[2])
	graph.MakeEdge(nodes[1], nodes[3])
	graph.MakeEdge(nodes[2], nodes[1])
	graph.MakeEdge(nodes[3], nodes[3])
	graph.MakeEdge(nodes[4], nodes[3])
	graph.MakeEdge(nodes[4], nodes[0])
	graph.MakeEdge(nodes[5], nodes[6])
	graph.MakeEdge(nodes[5], nodes[0])
	graph.MakeEdge(nodes[5], nodes[2])
	graph.MakeEdge(nodes[6], nodes[2])
	graph.MakeEdge(nodes[6], nodes[7])
	graph.MakeEdge(nodes[7], nodes[5])
	graph.verify(t)
	want := make([][]Node, 4)
	want[0] = make([]Node, 3)
	want[1] = make([]Node, 2)
	want[2] = make([]Node, 2)
	want[3] = make([]Node, 1)
	want[0][0] = nodes[6]
	want[0][1] = nodes[7]
	want[0][2] = nodes[5]
	want[1][0] = nodes[0]
	want[1][1] = nodes[4]
	want[2][0] = nodes[2]
	want[2][1] = nodes[1]
	want[3][0] = nodes[3]
	components := graph.StronglyConnectedComponents()
	for j := range components {
		for i := range want[j] {
			if !componentContains(components[j], want[j][i]) {
				t.Errorf("component slice %v does not contain want node %v", components[j], want[j][i])
			}
		}
	}
}

func componentContains(component []Node, node Node) bool {
	for i := range component {
		if component[i].node.index == node.node.index { // for SCC, the nodes will be reversed but the indices will be the same
			return true
		}
	}
	return false
}
<commit_msg>created MST test<commit_after>package graph

import (
	"testing"
)

func TestTopologicalSort(t *testing.T) {
	graph := New(Directed)
	nodes := make([]Node, 0)
	// create graph on page 613 of CLRS ed. 3
	nodes = append(nodes, graph.MakeNode()) // shirt
	nodes = append(nodes, graph.MakeNode()) // tie
	nodes = append(nodes, graph.MakeNode()) // jacket
	nodes = append(nodes, graph.MakeNode()) // belt
	nodes = append(nodes, graph.MakeNode()) // watch
	nodes = append(nodes, graph.MakeNode()) // undershorts
	nodes = append(nodes, graph.MakeNode()) // pants
	nodes = append(nodes, graph.MakeNode()) // shoes
	nodes = append(nodes, graph.MakeNode()) // socks
	graph.MakeEdge(nodes[0], nodes[1])
	graph.MakeEdge(nodes[1], nodes[2])
	graph.MakeEdge(nodes[0], nodes[3])
	graph.MakeEdge(nodes[3], nodes[2])
	graph.MakeEdge(nodes[5], nodes[6])
	graph.MakeEdge(nodes[5], nodes[7])
	graph.MakeEdge(nodes[6], nodes[3])
	graph.MakeEdge(nodes[6], nodes[7])
	graph.MakeEdge(nodes[8], nodes[7])
	graph.verify(t)
	wantOrder := make([]Node, len(graph.nodes))
	wantOrder[0] = nodes[8] // socks
	wantOrder[1] = nodes[5] // undershorts
	wantOrder[2] = nodes[6] // pants
	wantOrder[3] = nodes[7] // shoes
	wantOrder[4] = nodes[4] // watch
	wantOrder[5] = nodes[0] // shirt
	wantOrder[6] = nodes[3] // belt
	wantOrder[7] = nodes[1] // tie
	wantOrder[8] = nodes[2] // jacket
	result := graph.TopologicalSort()
	for i := range result {
		if result[i] != wantOrder[i] {
			t.Errorf("index %v in result != wanted, value: %v, want value: %v", i, result[i], wantOrder[i])
		}
	}
}

func TestStronglyConnectedComponents(t *testing.T) {
	graph := New(Directed)
	nodes := make([]Node, 0)
	// create SCC graph on page 616 of CLRS ed 3
	nodes = append(nodes, graph.MakeNode()) //0, c
	nodes = append(nodes, graph.MakeNode()) //1, g
	nodes = append(nodes, graph.MakeNode()) //2, f
	nodes = append(nodes, graph.MakeNode()) //3, h
	nodes = append(nodes, graph.MakeNode()) //4, d
	nodes = append(nodes, graph.MakeNode()) //5, b
	nodes = append(nodes, graph.MakeNode()) //6, e
	nodes = append(nodes, graph.MakeNode()) //7, a
	graph.MakeEdge(nodes[0], nodes[1])
	graph.MakeEdge(nodes[0], nodes[4])
	graph.MakeEdge(nodes[1], nodes[2])
	graph.MakeEdge(nodes[1], nodes[3])
	graph.MakeEdge(nodes[2], nodes[1])
	graph.MakeEdge(nodes[3], nodes[3])
	graph.MakeEdge(nodes[4], nodes[3])
	graph.MakeEdge(nodes[4], nodes[0])
	graph.MakeEdge(nodes[5], nodes[6])
	graph.MakeEdge(nodes[5], nodes[0])
	graph.MakeEdge(nodes[5], nodes[2])
	graph.MakeEdge(nodes[6], nodes[2])
	graph.MakeEdge(nodes[6], nodes[7])
	graph.MakeEdge(nodes[7], nodes[5])
	graph.verify(t)
	want := make([][]Node, 4)
	want[0] = make([]Node, 3)
	want[1] = make([]Node, 2)
	want[2] = make([]Node, 2)
	want[3] = make([]Node, 1)
	want[0][0] = nodes[6]
	want[0][1] = nodes[7]
	want[0][2] = nodes[5]
	want[1][0] = nodes[0]
	want[1][1] = nodes[4]
	want[2][0] = nodes[2]
	want[2][1] = nodes[1]
	want[3][0] = nodes[3]
	components := graph.StronglyConnectedComponents()
	for j := range components {
		for i := range want[j] {
			if !componentContains(components[j], want[j][i]) {
				t.Errorf("component slice %v does not contain want node %v", components[j], want[j][i])
			}
		}
	}
}

func TestMinimumSpanningTree(t *testing.T) {
	g := New(Undirected)
	nodes := make(map[string]Node, 0)
	nodes["a"] = g.MakeNode()
	nodes["b"] = g.MakeNode()
	nodes["c"] = g.MakeNode()
	nodes["d"] = g.MakeNode()
	nodes["e"] = g.MakeNode()
	nodes["f"] = g.MakeNode()
	nodes["g"] = g.MakeNode()
	nodes["h"] = g.MakeNode()
	nodes["i"] = g.MakeNode()
	for key, node := range nodes {
		*node.Value = key
	}
	g.MakeEdgeWeight(nodes["a"], nodes["b"], 4)
	g.MakeEdgeWeight(nodes["a"], nodes["h"], 8)
	g.MakeEdgeWeight(nodes["b"], nodes["h"], 11)
	g.MakeEdgeWeight(nodes["b"], nodes["c"], 8)
	g.MakeEdgeWeight(nodes["c"], nodes["i"], 2)
	g.MakeEdgeWeight(nodes["c"], nodes["f"], 4)
	g.MakeEdgeWeight(nodes["c"], nodes["d"], 7)
	g.MakeEdgeWeight(nodes["d"], nodes["e"], 9)
	g.MakeEdgeWeight(nodes["d"], nodes["f"], 14)
	g.MakeEdgeWeight(nodes["e"], nodes["f"], 10)
	g.MakeEdgeWeight(nodes["f"], nodes["g"], 2)
	g.MakeEdgeWeight(nodes["g"], nodes["h"], 1)
	g.MakeEdgeWeight(nodes["g"], nodes["i"], 6)
	g.MakeEdgeWeight(nodes["h"], nodes["i"], 7)
	mst := g.MinimumSpanningTree()
	mstNodes := make(map[Node]bool, 0)
	spanCost := 0
	for _, edge := range mst {
		if _, exists := mstNodes[edge.Start]; !exists {
			mstNodes[edge.Start] = true
		}
		if _, exists := mstNodes[edge.End]; !exists {
			mstNodes[edge.End] = true
		}
		spanCost += edge.Weight
	}
	if len(mstNodes) != len(nodes) { // 9
		t.Errorf("mst: # of nodes in MST is %v, expected %v", len(mstNodes), len(nodes))
	}
	if spanCost != 37 {
		t.Errorf("mst: expected MST cost of 37, got %v", spanCost)
	}

}

func componentContains(component []Node, node Node) bool {
	for i := range component {
		if component[i].node.index == node.node.index { // for SCC, the nodes will be reversed but the indices will be the same
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
Package miniprofiler_gae is a simple but effective mini-profiler for app engine.

miniprofiler_gae hooks into the appstats package, and all app engine RPCs are automatically profiled.
An appstats link is listed in each Profile.

Installation

In your main .go file:

    import mpg "github.com/mjibson/MiniProfiler/go/miniprofiler_gae"

Change all handler functions to the following signature:

    func(mpg.Context, http.ResponseWriter, *http.Request)

Wrap all calls to those functions in the miniprofiler.NewHandler wrapper:

    http.Handle("/", mpg.NewHandler(Main))

Send output of miniprofiler.Includes to your HTML (it is empty if Enable returns
false).

By default, miniprofiler is enabled on dev for all and on prod for admins.
Override miniprofiler.Enable to change.

Step

The Step function can be used to profile more specific parts of your code. It
should be called with the name of the step and a closure:

    c.P.Step("something", func() {
        // do some work
    })

Configuration

Refer to the variables section of the documentation: http://godoc.org/github.com/mjibson/MiniProfiler/go/miniprofiler#_variables.

Also refer to the base miniprofiler docs: http://godoc.org/github.com/mjibson/MiniProfiler/go/miniprofiler.

Other implementations and resources: http://miniprofiler.com.
*/
package miniprofiler_gae
<commit_msg>Update docs<commit_after>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
Package miniprofiler_gae is a simple but effective mini-profiler for app engine.

miniprofiler_gae hooks into the appstats package, and all app engine RPCs are automatically profiled.
An appstats link is listed in each Profile.

Installation

In your main .go file:

    import mpg "github.com/mjibson/MiniProfiler/go/miniprofiler_gae"

Change all handler functions to the following signature:

    func(mpg.Context, http.ResponseWriter, *http.Request)

Wrap all calls to those functions in the miniprofiler.NewHandler wrapper:

    http.Handle("/", mpg.NewHandler(Main))

Send output of miniprofiler.Includes to your HTML (it is empty if Enable returns
false).

By default, miniprofiler is enabled on dev for all and on prod for admins.
Override miniprofiler.Enable to change.

Step

The Step function can be used to profile more specific parts of your code. It
should be called with the name of the step and a closure:

    c.Step("something", func() {
        // do some work
    })

Configuration

Refer to the variables section of the documentation: http://godoc.org/github.com/mjibson/MiniProfiler/go/miniprofiler#_variables.

Also refer to the base miniprofiler docs: http://godoc.org/github.com/mjibson/MiniProfiler/go/miniprofiler.

Other implementations and resources: http://miniprofiler.com.
*/
package miniprofiler_gae
<|endoftext|>


<commit_before>package table

import "errors"

func (rt *RTable) Add(s string) {
	c := new(Column)
	*rt = append(*rt, c)
	c.AddAndCompute(s, rt)
}

func (rt *RTable) insertFollowing(pos int) {
	for col := pos + 1; col < len(*rt); col++ {
		(*rt)[col].Front(&Item{})
		(*rt)[col].ComputeFrom(pos, col, rt)
	}
}

func (rt *RTable) Insert(s string, pos int) error {
	if pos < 0 || pos > len(*rt) {
		return errors.New("index out of range")
	}
	if pos == len(*rt) {
		rt.Add(s)
		return nil
	}
	c := new(Column)

	*rt = append(*rt, nil)
	copy((*rt)[pos+1:], (*rt)[pos:])
	(*rt)[pos] = c
	c.InsertAndCompute(s, pos, rt)

	rt.insertFollowing(pos)
	return nil
}

func (rt *RTable) removeFollowing(pos int) {
	for col := pos; col < len(*rt); col++ {
		(*rt)[col].PopFront()
		(*rt)[col].ComputeFrom(pos-1, col, rt)
	}
}

func (rt *RTable) Remove(pos int) error {
	if pos < 0 || pos >= len(*rt) {
		return errors.New("index out of range")
	}
	(*rt) = append((*rt)[:pos], (*rt)[pos+1:]...)
	rt.removeFollowing(pos)
	return nil
}
<commit_msg>add comments to table/modify.go<commit_after>package table

import "errors"

// Add adds a new column at the end of the recognition table and
// fills it with the appropriate items.
func (rt *RTable) Add(s string) {
	c := new(Column)
	*rt = append(*rt, c)
	c.AddAndCompute(s, rt)
}

// insertFollowing computes the rest each item until the end and
// modify it appropriately. It also modifies only from a given position.
func (rt *RTable) insertFollowing(pos int) {
	for col := pos + 1; col < len(*rt); col++ {
		(*rt)[col].Front(&Item{})
		(*rt)[col].ComputeFrom(pos, col, rt)
	}
}

// Insert inserts a new column at give position of the
// recognition table and fills it with the appropriate items.
func (rt *RTable) Insert(s string, pos int) error {
	if pos < 0 || pos > len(*rt) {
		return errors.New("index out of range")
	}
	if pos == len(*rt) {
		rt.Add(s)
		return nil
	}
	c := new(Column)

	*rt = append(*rt, nil)
	copy((*rt)[pos+1:], (*rt)[pos:])
	(*rt)[pos] = c
	c.InsertAndCompute(s, pos, rt)

	rt.insertFollowing(pos)
	return nil
}

// removeFollowing computes the rest each item until the end and
// modify it appropriately. It also modifies only from a given position.
func (rt *RTable) removeFollowing(pos int) {
	for col := pos; col < len(*rt); col++ {
		(*rt)[col].PopFront()
		(*rt)[col].ComputeFrom(pos-1, col, rt)
	}
}

// Remove removes a column at give position of the
// recognition table and compute the new items appropriately.
func (rt *RTable) Remove(pos int) error {
	if pos < 0 || pos >= len(*rt) {
		return errors.New("index out of range")
	}
	(*rt) = append((*rt)[:pos], (*rt)[pos+1:]...)
	rt.removeFollowing(pos)
	return nil
}
<|endoftext|>


<commit_before>package compress

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

	"github.com/disorganizer/brig/util/testutil"
)

var (
	ZipFilePath = filepath.Join(os.TempDir(), "compressed.zip")
	TestOffsets = []int64{-1, -500, 0, 1, -C64K, -C32K, C64K - 1, C64K, C64K + 1, C32K - 1, C32K, C32K + 1, C64K - 5, C64K + 5, C32K - 5, C32K + 5}
	TestSizes   = []int64{0, 1, C64K - 1, C64K, C64K + 1, C32K - 1, C32K, C32K + 1, C64K - 5, C64K + 5, C32K - 5, C32K + 5}
)

func openDest(t *testing.T, dest string) *os.File {
	if _, err := os.Stat(dest); !os.IsNotExist(err) {
		t.Fatalf("Opening destination %v failed: %v\n", dest, err)
	}
	fd, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755)
	if err != nil {
		t.Fatalf("Opening source %v failed: %v\n", dest, err)
	}
	return fd
}

func openSrc(t *testing.T, src string) *os.File {
	fd, err := os.Open(src)
	if err != nil {
		t.Fatalf("Opening source %v failed: %v\n", src, err)
	}
	return fd
}

const (
	C64K = 64 * 1024
	C32K = 32 * 1024
)

func TestCompressDecompress(t *testing.T) {
	sizes := TestSizes
	algos := []AlgorithmType{AlgoNone, AlgoSnappy}

	for _, algo := range algos {
		for _, size := range sizes {
			testCompressDecompress(t, size, algo, true, true)
			testCompressDecompress(t, size, algo, false, false)
			testCompressDecompress(t, size, algo, true, false)
			testCompressDecompress(t, size, algo, false, true)
		}
	}
}
func Copy(dst io.Writer, src io.Reader, useReadFrom, useWriteTo bool) (written int64, err error) {
	return copyBuffer(dst, src, nil, useReadFrom, useWriteTo)
}

// CopyBuffer is identical to Copy except that it stages through the
// provided buffer (if one is required) rather than allocating a
// temporary one. If buf is nil, one is allocated; otherwise if it has
// zero length, CopyBuffer panics.
func CopyBuffer(dst io.Writer, src io.Reader, buf []byte, useReadFrom, useWriteTo bool) (written int64, err error) {
	if buf != nil && len(buf) == 0 {
		panic("empty buffer in io.CopyBuffer")
	}
	return copyBuffer(dst, src, buf, useReadFrom, useWriteTo)
}

func copyBuffer(dst io.Writer, src io.Reader, buf []byte, useReadFrom, useWriteTo bool) (written int64, err error) {
	// If the reader has a WriteTo method, use it to do the copy.
	// Avoids an allocation and a copy.
	if wt, ok := src.(io.WriterTo); ok && useWriteTo {
		return wt.WriteTo(dst)
	}
	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
	if rt, ok := dst.(io.ReaderFrom); ok && useReadFrom {
		return rt.ReadFrom(src)
	}
	if buf == nil {
		buf = make([]byte, 32*1024)
	}
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = io.ErrShortWrite
				break
			}
		}
		if er == io.EOF {
			break
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

func testCompressDecompress(t *testing.T, size int64, algo AlgorithmType, useReadFrom, useWriteTo bool) {
	// Fake data file is written to disk,
	// as compression reader has to be a ReadSeeker.
	testutil.Remover(t, ZipFilePath)
	data := testutil.CreateDummyBuf(size)
	zipFileDest := openDest(t, ZipFilePath)

	defer testutil.Remover(t, ZipFilePath)

	// Compress.
	w := NewWriter(zipFileDest, algo)
	if _, err := Copy(w, bytes.NewReader(data), useReadFrom, useWriteTo); err != nil {
		t.Errorf("Compress failed %v", err)
		return
	}

	if err := w.Close(); err != nil {
		t.Errorf("Compression writer close failed: %v", err)
		return
	}

	if err := zipFileDest.Close(); err != nil {
		t.Errorf("close(zipFileDest) failed: %v", err)
		return
	}

	// Read compressed file into buffer.
	dataUncomp := bytes.NewBuffer(nil)
	dataFromZip := openSrc(t, ZipFilePath)

	// Uncompress.
	r := NewReader(dataFromZip)
	if _, err := Copy(dataUncomp, r, useReadFrom, useWriteTo); err != nil {
		t.Errorf("Decompression failed: %v", err)
		return
	}
	if err := dataFromZip.Close(); err != nil {
		t.Errorf("Zip close failed: %v", err)
		return
	}

	// Compare.
	//if !bytes.Equal(dataUncomp.Bytes(), data) {
	//	t.Error("Uncompressed data and input data does not match.")
	//	return
	//}
	got, want := dataUncomp.Bytes(), data
	if !bytes.Equal(got, want) {
		t.Error("Uncompressed data and input data does not match.")
		t.Errorf("\tGOT:   %v", omit(got, 10))
		t.Errorf("\tWANT:  %v", omit(want, 10))
		return
	}
}

func TestSeek(t *testing.T) {
	sizes := TestSizes
	offsets := TestOffsets
	algos := []AlgorithmType{AlgoNone, AlgoSnappy}
	for _, algo := range algos {
		for _, size := range sizes {
			for _, off := range offsets {
				testSeek(t, size, off, algo, false, false)
				testSeek(t, size, off, algo, true, true)
				testSeek(t, size, off, algo, false, true)
				testSeek(t, size, off, algo, true, false)
			}
		}
	}
}

func omit(data []byte, lim int) string {
	lo := lim
	if lo > len(data) {
		lo = len(data)
	}

	hi := len(data) - lim
	if hi < 0 {
		hi = len(data)
	}

	return fmt.Sprintf("%v ... %v", data[:lo], data[hi:])
}

func testSeek(t *testing.T, size, offset int64, algo AlgorithmType, useReadFrom, useWriteTo bool) {
	// Fake data file is written to disk,
	// as compression reader has to be a ReadSeeker.
	testutil.Remover(t, ZipFilePath)
	data := testutil.CreateDummyBuf(size)
	zipFileDest := openDest(t, ZipFilePath)

	// Compress.
	w := NewWriter(zipFileDest, algo)
	if _, err := Copy(w, bytes.NewReader(data), useReadFrom, useWriteTo); err != nil {
		t.Errorf("Compress failed %v", err)
		return
	}
	defer testutil.Remover(t, ZipFilePath)

	if err := w.Close(); err != nil {
		t.Errorf("Compression writer close failed: %v", err)
		return
	}

	if err := zipFileDest.Close(); err != nil {
		t.Errorf("close(zipFileDest) failed: %v", err)
		return
	}

	// Read compressed file into buffer.
	dataUncomp := bytes.NewBuffer(nil)
	dataFromZip := openSrc(t, ZipFilePath)
	zr := NewReader(dataFromZip)

	// Set specific offset before read.
	_, err := zr.Seek(offset, os.SEEK_SET)
	if err == io.EOF && offset < size && offset > -1 {
		t.Errorf("Seek failed even with EOF: %d <= %d", offset, size)
		return
	}
	if err != io.EOF && err != nil {
		t.Errorf("Seek failed: %v", err)
		return
	}

	// Read starting at a specific offset.
	if _, err := Copy(dataUncomp, zr, useReadFrom, useWriteTo); err != nil {
		t.Errorf("Decompression failed: %v", err)
		return
	}
	if err := dataFromZip.Close(); err != nil {
		t.Errorf("Zip close failed: %v", err)
		return
	}

	// Compare.
	maxOffset := offset
	if offset > size {
		maxOffset = size
	}

	if offset < 0 {
		maxOffset = 0
	}

	got, want := dataUncomp.Bytes(), data[maxOffset:]
	if !bytes.Equal(got, want) {
		t.Error("Uncompressed data and input data does not match.")
		t.Errorf("\tGOT:   %v", omit(got, 10))
		t.Errorf("\tWANT:  %v", omit(want, 10))
		return
	}
}
<commit_msg>store/compress/compress_test.go: Test Algorithms unified.<commit_after>package compress

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

	"github.com/disorganizer/brig/util/testutil"
)

var (
	ZipFilePath      = filepath.Join(os.TempDir(), "compressed.zip")
	TestOffsets      = []int64{-1, -500, 0, 1, -C64K, -C32K, C64K - 1, C64K, C64K + 1, C32K - 1, C32K, C32K + 1, C64K - 5, C64K + 5, C32K - 5, C32K + 5}
	TestSizes        = []int64{0, 1, C64K - 1, C64K, C64K + 1, C32K - 1, C32K, C32K + 1, C64K - 5, C64K + 5, C32K - 5, C32K + 5}
	CompressionAlgos = []AlgorithmType{AlgoLZ4}
)

func openDest(t *testing.T, dest string) *os.File {
	if _, err := os.Stat(dest); !os.IsNotExist(err) {
		t.Fatalf("Opening destination %v failed: %v\n", dest, err)
	}
	fd, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755)
	if err != nil {
		t.Fatalf("Opening source %v failed: %v\n", dest, err)
	}
	return fd
}

func openSrc(t *testing.T, src string) *os.File {
	fd, err := os.Open(src)
	if err != nil {
		t.Fatalf("Opening source %v failed: %v\n", src, err)
	}
	return fd
}

const (
	C64K = 64 * 1024
	C32K = 32 * 1024
)

func TestCompressDecompress(t *testing.T) {
	sizes := TestSizes
	algos := CompressionAlgos

	for _, algo := range algos {
		for _, size := range sizes {
			testCompressDecompress(t, size, algo, true, true)
			testCompressDecompress(t, size, algo, false, false)
			testCompressDecompress(t, size, algo, true, false)
			testCompressDecompress(t, size, algo, false, true)
		}
	}
}
func Copy(dst io.Writer, src io.Reader, useReadFrom, useWriteTo bool) (written int64, err error) {
	return copyBuffer(dst, src, nil, useReadFrom, useWriteTo)
}

// CopyBuffer is identical to Copy except that it stages through the
// provided buffer (if one is required) rather than allocating a
// temporary one. If buf is nil, one is allocated; otherwise if it has
// zero length, CopyBuffer panics.
func CopyBuffer(dst io.Writer, src io.Reader, buf []byte, useReadFrom, useWriteTo bool) (written int64, err error) {
	if buf != nil && len(buf) == 0 {
		panic("empty buffer in io.CopyBuffer")
	}
	return copyBuffer(dst, src, buf, useReadFrom, useWriteTo)
}

func copyBuffer(dst io.Writer, src io.Reader, buf []byte, useReadFrom, useWriteTo bool) (written int64, err error) {
	// If the reader has a WriteTo method, use it to do the copy.
	// Avoids an allocation and a copy.
	if wt, ok := src.(io.WriterTo); ok && useWriteTo {
		return wt.WriteTo(dst)
	}
	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
	if rt, ok := dst.(io.ReaderFrom); ok && useReadFrom {
		return rt.ReadFrom(src)
	}
	if buf == nil {
		buf = make([]byte, 32*1024)
	}
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = io.ErrShortWrite
				break
			}
		}
		if er == io.EOF {
			break
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

func testCompressDecompress(t *testing.T, size int64, algo AlgorithmType, useReadFrom, useWriteTo bool) {
	// Fake data file is written to disk,
	// as compression reader has to be a ReadSeeker.
	testutil.Remover(t, ZipFilePath)
	data := testutil.CreateDummyBuf(size)
	zipFileDest := openDest(t, ZipFilePath)

	defer testutil.Remover(t, ZipFilePath)

	// Compress.
	w, err := NewWriter(zipFileDest, algo)
	if err != nil {
		t.Errorf("Writer init failed %v", err)
		return

	}
	if _, err := Copy(w, bytes.NewReader(data), useReadFrom, useWriteTo); err != nil {
		t.Errorf("Compress failed %v", err)
		return
	}

	if err := w.Close(); err != nil {
		t.Errorf("Compression writer close failed: %v", err)
		return
	}

	if err := zipFileDest.Close(); err != nil {
		t.Errorf("close(zipFileDest) failed: %v", err)
		return
	}

	// Read compressed file into buffer.
	dataUncomp := bytes.NewBuffer(nil)
	dataFromZip := openSrc(t, ZipFilePath)

	// Uncompress.
	r := NewReader(dataFromZip)
	if _, err := Copy(dataUncomp, r, useReadFrom, useWriteTo); err != nil {
		t.Errorf("Decompression failed: %v", err)
		return
	}
	if err := dataFromZip.Close(); err != nil {
		t.Errorf("Zip close failed: %v", err)
		return
	}

	// Compare.
	got, want := dataUncomp.Bytes(), data
	if !bytes.Equal(got, want) {
		t.Error("Uncompressed data and input data does not match.")
		t.Errorf("\tGOT:   %v", omit(got, 10))
		t.Errorf("\tWANT:  %v", omit(want, 10))
		return
	}
}

func TestSeek(t *testing.T) {
	sizes := TestSizes
	offsets := TestOffsets
	algos := CompressionAlgos
	for _, algo := range algos {
		for _, size := range sizes {
			for _, off := range offsets {
				testSeek(t, size, off, algo, false, false)
				testSeek(t, size, off, algo, true, true)
				testSeek(t, size, off, algo, false, true)
				testSeek(t, size, off, algo, true, false)
			}
		}
	}
}

func omit(data []byte, lim int) string {
	lo := lim
	if lo > len(data) {
		lo = len(data)
	}

	hi := len(data) - lim
	if hi < 0 {
		hi = len(data)
	}

	return fmt.Sprintf("%v ... %v", data[:lo], data[hi:])
}

func testSeek(t *testing.T, size, offset int64, algo AlgorithmType, useReadFrom, useWriteTo bool) {
	// Fake data file is written to disk,
	// as compression reader has to be a ReadSeeker.
	testutil.Remover(t, ZipFilePath)
	data := testutil.CreateDummyBuf(size)
	zipFileDest := openDest(t, ZipFilePath)

	// Compress.
	w, err := NewWriter(zipFileDest, algo)
	if err != nil {
		t.Errorf("Writer init failed %v", err)
		return
	}
	if _, err := Copy(w, bytes.NewReader(data), useReadFrom, useWriteTo); err != nil {
		t.Errorf("Compress failed %v", err)
		return
	}
	defer testutil.Remover(t, ZipFilePath)

	if err := w.Close(); err != nil {
		t.Errorf("Compression writer close failed: %v", err)
		return
	}

	if err := zipFileDest.Close(); err != nil {
		t.Errorf("close(zipFileDest) failed: %v", err)
		return
	}

	// Read compressed file into buffer.
	dataUncomp := bytes.NewBuffer(nil)
	dataFromZip := openSrc(t, ZipFilePath)
	zr := NewReader(dataFromZip)

	// Set specific offset before read.
	_, err = zr.Seek(offset, os.SEEK_SET)
	if err == io.EOF && offset < size && offset > -1 {
		t.Errorf("Seek failed even with EOF: %d <= %d", offset, size)
		return
	}
	if err != io.EOF && err != nil {
		t.Errorf("Seek failed: %v", err)
		return
	}

	// Read starting at a specific offset.
	if _, err := Copy(dataUncomp, zr, useReadFrom, useWriteTo); err != nil {
		t.Errorf("Decompression failed: %v", err)
		return
	}
	if err := dataFromZip.Close(); err != nil {
		t.Errorf("Zip close failed: %v", err)
		return
	}

	// Compare.
	maxOffset := offset
	if offset > size {
		maxOffset = size
	}

	if offset < 0 {
		maxOffset = 0
	}

	got, want := dataUncomp.Bytes(), data[maxOffset:]
	if !bytes.Equal(got, want) {
		t.Error("Uncompressed data and input data does not match.")
		t.Errorf("\tGOT:   %v", omit(got, 10))
		t.Errorf("\tWANT:  %v", omit(want, 10))
		return
	}
}
<|endoftext|>


<commit_before>package tally

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"
	_ "net/http/pprof"
	"sort"
	"strings"
	"time"
)

type StatusRequest struct {
	s    *Server
	w    http.ResponseWriter
	r    *http.Request
	t    *template.Template
	data interface{}
}

type statusHandler interface {
	handle(*StatusRequest)
}

type statusHandlerWithTemplate interface {
	statusHandler
	getTemplate() string
}

func ServeStatus(server *Server) error {
	pages := map[string]statusHandler{
		"/":         statusPage{},
		"/strings/": stringsPage{},
	}

	var err error
	for path, h := range pages {
		e := handleStatus(server, path, h)
		if e != nil {
			err = e
			errorlog("error: %s", err)
		}
	}
	if err == nil {
		addr := fmt.Sprintf("%s:%d", server.receiverHost, server.receiverPort)
		go http.ListenAndServe(addr, nil)
	}
	return err
}

func handleStatus(server *Server, path string, h statusHandler) (err error) {
	err = makePage(server, "/json"+path, h, false)
	if err == nil {
		err = makePage(server, path, h, true)
	}
	return
}

func makePage(s *Server, path string, h statusHandler,
	applyTemplate bool) error {
	var t *template.Template
	switch h.(type) {
	case statusHandlerWithTemplate:
		text := h.(statusHandlerWithTemplate).getTemplate()
		var e error
		t, e = template.New(path).Parse(text)
		if e != nil {
			return e
		}
	}
	var f http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
		req := StatusRequest{s, w, r, t, nil}
		h.handle(&req)
		if req.data != nil {
			if applyTemplate && req.t != nil {
				err := req.t.Execute(req.w, req.data)
				if err != nil {
					errorlog("template exec error: %s", err)
				}
			} else {
				w.Header().Set("Content-type",
					"application/json; charset=utf-8")
				json.NewEncoder(req.w).Encode(req.data)
			}
		}
	}
	http.Handle(path, f)
	return nil
}

type statusPage struct{}

func (statusPage) getTemplate() string {
	return `

tallier status

top stats

strings

cpu profile

`
}

func (statusPage) handle(req *StatusRequest) {
	// this function only exists to register the handler
	req.data = map[string]interface{}{}
}

type stringsPage struct{}

func (stringsPage) getTemplate() string {
	return `
{{if .str}}

        rank	string	minute	hour

      {{range .items}}

          {{.rank}}
          {{.key}}
          {{printf "%.2g" .minute.rate}} ({{.minute.total}})
          {{printf "%.2g" .hour.rate}} ({{.hour.total}})

      {{end}}

{{else}}
  {{range $_, $key := .keys}}
    {{$key}}

  {{end}}
{{end}}`
}

func (stringsPage) handle(req *StatusRequest) {
	var str string
	var needSort bool
	if strings.HasPrefix(req.r.URL.Path, "/json/strings/") {
		str = req.r.URL.Path[len("/json/strings/"):]
	} else if strings.HasPrefix(req.r.URL.Path, "/strings/") {
		str = req.r.URL.Path[len("/strings/"):]
		needSort = true
	}
	if str != "" {
		stringPage(req, str)
		return
	}

	if req.s.snapshot == nil || len(req.s.snapshot.stringCounts) == 0 {
		fmt.Fprintf(req.w, "no stats to report yet")
		return
	}
	data := make([]string, 0, len(req.s.snapshot.stringCounts))
	for key, _ := range req.s.snapshot.stringCounts {
		data = append(data, key)
	}
	if needSort {
		sort.Strings(data)
	}
	req.data = map[string]interface{}{"keys": data}
}

func stringPage(req *StatusRequest, key string) {
	if req.s.snapshot == nil {
		http.NotFound(req.w, req.r)
		return
	}
	fcs, ok := req.s.snapshot.stringCounts[key]
	if !ok {
		http.NotFound(req.w, req.r)
		return
	}
	items := fcs.SortedItems()
	levels := []string{"minute", "hour"}
	data := make([]map[string]interface{}, len(items))
	for i, item := range items {
		data[i] = map[string]interface{}{
			"key":  item.key,
			"rank": i + 1,
		}
		for j, level := range levels {
			c := (*(item.count))[j+1]
			data[i][level] = map[string]interface{}{
				"rate":  c.RatePer(time.Second),
				"total": c.Current,
			}
		}
	}
	req.data = map[string]interface{}{
		"str":   key,
		"items": data,
	}
}
<commit_msg>Status: Don't use scientific notation for large numbers.<commit_after>package tally

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"
	_ "net/http/pprof"
	"sort"
	"strings"
	"time"
)

type StatusRequest struct {
	s    *Server
	w    http.ResponseWriter
	r    *http.Request
	t    *template.Template
	data interface{}
}

type statusHandler interface {
	handle(*StatusRequest)
}

type statusHandlerWithTemplate interface {
	statusHandler
	getTemplate() string
}

func ServeStatus(server *Server) error {
	pages := map[string]statusHandler{
		"/":         statusPage{},
		"/strings/": stringsPage{},
	}

	var err error
	for path, h := range pages {
		e := handleStatus(server, path, h)
		if e != nil {
			err = e
			errorlog("error: %s", err)
		}
	}
	if err == nil {
		addr := fmt.Sprintf("%s:%d", server.receiverHost, server.receiverPort)
		go http.ListenAndServe(addr, nil)
	}
	return err
}

func handleStatus(server *Server, path string, h statusHandler) (err error) {
	err = makePage(server, "/json"+path, h, false)
	if err == nil {
		err = makePage(server, path, h, true)
	}
	return
}

func makePage(s *Server, path string, h statusHandler,
	applyTemplate bool) error {
	var t *template.Template
	switch h.(type) {
	case statusHandlerWithTemplate:
		text := h.(statusHandlerWithTemplate).getTemplate()
		var e error
		t, e = template.New(path).Parse(text)
		if e != nil {
			return e
		}
	}
	var f http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
		req := StatusRequest{s, w, r, t, nil}
		h.handle(&req)
		if req.data != nil {
			if applyTemplate && req.t != nil {
				err := req.t.Execute(req.w, req.data)
				if err != nil {
					errorlog("template exec error: %s", err)
				}
			} else {
				w.Header().Set("Content-type",
					"application/json; charset=utf-8")
				json.NewEncoder(req.w).Encode(req.data)
			}
		}
	}
	http.Handle(path, f)
	return nil
}

type statusPage struct{}

func (statusPage) getTemplate() string {
	return `

tallier status

top stats

strings

cpu profile

`
}

func (statusPage) handle(req *StatusRequest) {
	// this function only exists to register the handler
	req.data = map[string]interface{}{}
}

type stringsPage struct{}

func (stringsPage) getTemplate() string {
	return `
{{if .str}}

        rank	string	minute	hour

      {{range .items}}

          {{.rank}}
          {{.key}}
          {{printf "%.2f" .minute.rate}} ({{.minute.total}})
          {{printf "%.2f" .hour.rate}} ({{.hour.total}})

      {{end}}

{{else}}
  {{range $_, $key := .keys}}
    {{$key}}

  {{end}}
{{end}}`
}

func (stringsPage) handle(req *StatusRequest) {
	var str string
	var needSort bool
	if strings.HasPrefix(req.r.URL.Path, "/json/strings/") {
		str = req.r.URL.Path[len("/json/strings/"):]
	} else if strings.HasPrefix(req.r.URL.Path, "/strings/") {
		str = req.r.URL.Path[len("/strings/"):]
		needSort = true
	}
	if str != "" {
		stringPage(req, str)
		return
	}

	if req.s.snapshot == nil || len(req.s.snapshot.stringCounts) == 0 {
		fmt.Fprintf(req.w, "no stats to report yet")
		return
	}
	data := make([]string, 0, len(req.s.snapshot.stringCounts))
	for key, _ := range req.s.snapshot.stringCounts {
		data = append(data, key)
	}
	if needSort {
		sort.Strings(data)
	}
	req.data = map[string]interface{}{"keys": data}
}

func stringPage(req *StatusRequest, key string) {
	if req.s.snapshot == nil {
		http.NotFound(req.w, req.r)
		return
	}
	fcs, ok := req.s.snapshot.stringCounts[key]
	if !ok {
		http.NotFound(req.w, req.r)
		return
	}
	items := fcs.SortedItems()
	levels := []string{"minute", "hour"}
	data := make([]map[string]interface{}, len(items))
	for i, item := range items {
		data[i] = map[string]interface{}{
			"key":  item.key,
			"rank": i + 1,
		}
		for j, level := range levels {
			c := (*(item.count))[j+1]
			data[i][level] = map[string]interface{}{
				"rate":  c.RatePer(time.Second),
				"total": c.Current,
			}
		}
	}
	req.data = map[string]interface{}{
		"str":   key,
		"items": data,
	}
}
<|endoftext|>


<commit_before>/* {{{ Copyright (c) Paul R. Tagliamonte <paultag@debian.org>, 2015
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE. }}} */

package parser

import (
	"fmt"
)

var TLSHeaderLength = 5

/* This function is basically all most folks want to invoke out of this
 * jumble of bits. This will take an incoming TLS Client Hello (including
 * all the fuzzy bits at the beginning of it - fresh out of the socket) and
 * go ahead and give us the SNI Name they want. */
func GetHostname(data []byte) (string, error) {
	if len(data) == 0 && data[0] != 0x16 {
		return "", fmt.Errorf("Doens't look like a TLS Client Hello")
	}

	extensions, err := GetExtensionBlock(data)
	if err != nil {
		return "", err
	}
	sn, err := GetSNBlock(extensions)
	if err != nil {
		return "", err
	}
	sni, err := GetSNIBlock(sn)
	if err != nil {
		return "", err
	}
	return string(sni), nil
}

/* Given a Server Name TLS Extension block, parse out and return the SNI
 * (Server Name Indication) payload */
func GetSNIBlock(data []byte) ([]byte, error) {
	index := 0

	for {
		if index >= len(data) {
			break
		}
		length := int((data[index] << 8) + data[index+1])
		endIndex := index + 2 + length
		if data[index+2] == 0x00 { /* SNI */
			sni := data[index+3:]
			sniLength := int((sni[0] << 8) + sni[1])
			return sni[2 : sniLength+2], nil
		}
		index = endIndex
	}
	return []byte{}, fmt.Errorf(
		"Finished parsing the SN block without finding an SNI",
	)
}

/* Given an TLS Extensions data block, go ahead and find the SN block */
func GetSNBlock(data []byte) ([]byte, error) {
	index := 0

	if len(data) < 2 {
		return []byte{}, fmt.Errorf("Not enough bytes to be a SN block")
	}

	extensionLength := int((data[index] << 8) + data[index+1])
	data = data[2 : extensionLength+2]

	for {
		if index >= len(data) {
			break
		}
		length := int((data[index+2] << 8) + data[index+3])
		endIndex := index + 4 + length
		if data[index] == 0x00 && data[index+1] == 0x00 {
			return data[index+4 : endIndex], nil
		}

		index = endIndex
	}

	return []byte{}, fmt.Errorf(
		"Finished parsing the Extension block without finding an SN block",
	)
}

/* Given a raw TLS Client Hello, go ahead and find all the Extensions */
func GetExtensionBlock(data []byte) ([]byte, error) {
	/*   data[0]           - content type
	 *   data[1], data[2]  - major/minor version
	 *   data[3], data[4]  - total length
	 *   data[...38+5]     - start of SessionID (length bit)
	 *   data[38+5]        - length of SessionID
	 */
	var index = TLSHeaderLength + 38

	if len(data) <= index+1 {
		return []byte{}, fmt.Errorf("Not enough bits to be a Client Hello")
	}

	/* Index is at SessionID Length bit */
	if newIndex := index + 1 + int(data[index]); (newIndex + 2) < len(data) {
		index = newIndex
	} else {
		return []byte{}, fmt.Errorf("Not enough bytes for the SessionID")
	}

	/* Index is at Cipher List Length bits */
	if newIndex := (index + 2 + int((data[index]<<8)+data[index+1])); (newIndex + 1) < len(data) {
		index = newIndex
	} else {
		return []byte{}, fmt.Errorf("Not enough bytes for the Cipher List")
	}

	/* Index is now at the compression length bit */
	if newIndex := index + 1 + int(data[index]); newIndex < len(data) {
		index = newIndex
	} else {
		return []byte{}, fmt.Errorf("Not enough bytes for the compression length")
	}

	/* Now we're at the Extension start */
	if len(data[index:]) == 0 {
		return nil, fmt.Errorf("No extensions")
	}
	return data[index:], nil
}

// vim: foldmethod=marker
<commit_msg>&& -> ||<commit_after>/* {{{ Copyright (c) Paul R. Tagliamonte <paultag@debian.org>, 2015
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE. }}} */

package parser

import (
	"fmt"
)

var TLSHeaderLength = 5

/* This function is basically all most folks want to invoke out of this
 * jumble of bits. This will take an incoming TLS Client Hello (including
 * all the fuzzy bits at the beginning of it - fresh out of the socket) and
 * go ahead and give us the SNI Name they want. */
func GetHostname(data []byte) (string, error) {
	if len(data) == 0 || data[0] != 0x16 {
		return "", fmt.Errorf("Doens't look like a TLS Client Hello")
	}

	extensions, err := GetExtensionBlock(data)
	if err != nil {
		return "", err
	}
	sn, err := GetSNBlock(extensions)
	if err != nil {
		return "", err
	}
	sni, err := GetSNIBlock(sn)
	if err != nil {
		return "", err
	}
	return string(sni), nil
}

/* Given a Server Name TLS Extension block, parse out and return the SNI
 * (Server Name Indication) payload */
func GetSNIBlock(data []byte) ([]byte, error) {
	index := 0

	for {
		if index >= len(data) {
			break
		}
		length := int((data[index] << 8) + data[index+1])
		endIndex := index + 2 + length
		if data[index+2] == 0x00 { /* SNI */
			sni := data[index+3:]
			sniLength := int((sni[0] << 8) + sni[1])
			return sni[2 : sniLength+2], nil
		}
		index = endIndex
	}
	return []byte{}, fmt.Errorf(
		"Finished parsing the SN block without finding an SNI",
	)
}

/* Given an TLS Extensions data block, go ahead and find the SN block */
func GetSNBlock(data []byte) ([]byte, error) {
	index := 0

	if len(data) < 2 {
		return []byte{}, fmt.Errorf("Not enough bytes to be a SN block")
	}

	extensionLength := int((data[index] << 8) + data[index+1])
	data = data[2 : extensionLength+2]

	for {
		if index >= len(data) {
			break
		}
		length := int((data[index+2] << 8) + data[index+3])
		endIndex := index + 4 + length
		if data[index] == 0x00 && data[index+1] == 0x00 {
			return data[index+4 : endIndex], nil
		}

		index = endIndex
	}

	return []byte{}, fmt.Errorf(
		"Finished parsing the Extension block without finding an SN block",
	)
}

/* Given a raw TLS Client Hello, go ahead and find all the Extensions */
func GetExtensionBlock(data []byte) ([]byte, error) {
	/*   data[0]           - content type
	 *   data[1], data[2]  - major/minor version
	 *   data[3], data[4]  - total length
	 *   data[...38+5]     - start of SessionID (length bit)
	 *   data[38+5]        - length of SessionID
	 */
	var index = TLSHeaderLength + 38

	if len(data) <= index+1 {
		return []byte{}, fmt.Errorf("Not enough bits to be a Client Hello")
	}

	/* Index is at SessionID Length bit */
	if newIndex := index + 1 + int(data[index]); (newIndex + 2) < len(data) {
		index = newIndex
	} else {
		return []byte{}, fmt.Errorf("Not enough bytes for the SessionID")
	}

	/* Index is at Cipher List Length bits */
	if newIndex := (index + 2 + int((data[index]<<8)+data[index+1])); (newIndex + 1) < len(data) {
		index = newIndex
	} else {
		return []byte{}, fmt.Errorf("Not enough bytes for the Cipher List")
	}

	/* Index is now at the compression length bit */
	if newIndex := index + 1 + int(data[index]); newIndex < len(data) {
		index = newIndex
	} else {
		return []byte{}, fmt.Errorf("Not enough bytes for the compression length")
	}

	/* Now we're at the Extension start */
	if len(data[index:]) == 0 {
		return nil, fmt.Errorf("No extensions")
	}
	return data[index:], nil
}

// vim: foldmethod=marker
<|endoftext|>


<commit_before>package parser

// Note that you should include a lot of calls to panic() where something's happening that shouldn't be.
// This will help to find bugs. Once the compiler is in a better state, a lot of these calls can be removed.

import (
	"fmt"
	"os"
	"strings"
	"strconv"

	"github.com/ark-lang/ark-go/lexer"
	"github.com/ark-lang/ark-go/util"
)

type parser struct {
	file         *File
	input        []*lexer.Token
	currentToken int
	verbose      bool

	scope *Scope
}

func (v *parser) err(err string, stuff ...interface{}) {
	fmt.Printf(util.TEXT_RED+util.TEXT_BOLD+"Parser error:"+util.TEXT_RESET+" [%s:%d:%d] %s\n",
		v.peek(0).Filename, v.peek(0).LineNumber, v.peek(0).CharNumber, fmt.Sprintf(err, stuff...))
	os.Exit(2)
}

func (v *parser) peek(ahead int) *lexer.Token {
	if ahead < 0 {
		panic(fmt.Sprintf("Tried to peek a negative number: %d", ahead))
	}

	if v.currentToken+ahead >= len(v.input) {
		return nil
	}

	return v.input[v.currentToken+ahead]
}

func (v *parser) consumeToken() *lexer.Token {
	ret := v.peek(0)
	v.currentToken++
	return ret
}

func (v *parser) pushNode(node Node) {
	v.file.nodes = append(v.file.nodes, node)
}

func (v *parser) pushScope() {
	v.scope = newScope(v.scope)
}

func (v *parser) popScope() {
	v.scope = v.scope.Outer
	if v.scope == nil {
		panic("pushed too many scopes")
	}
}

func (v *parser) tokenMatches(ahead int, t lexer.TokenType, contents string) bool {
	tok := v.peek(ahead)
	return tok.Type == t && (contents == "" || (tok.Contents == contents))
}

func (v *parser) tokensMatch(args ...interface{}) bool {
	if len(args)%2 != 0 {
		panic("passed uneven args to tokensMatch")
	}

	for i := 0; i < len(args)/2; i++ {
		if !(v.tokenMatches(i, args[i*2].(lexer.TokenType), args[i*2+1].(string))) {
			return false
		}
	}
	return true
}

func Parse(tokens []*lexer.Token, verbose bool) *File {
	p := &parser{
		file: &File{
			nodes: make([]Node, 0),
		},
		input:   tokens,
		verbose: verbose,
		scope:   newGlobalScope(),
	}

	if verbose {
		fmt.Println(util.TEXT_BOLD+util.TEXT_GREEN+"Started parsing"+util.TEXT_RESET, tokens[0].Filename)
	}
	p.parse()
	if verbose {
		fmt.Println(util.TEXT_BOLD+util.TEXT_GREEN+"Finished parsing"+util.TEXT_RESET, tokens[0].Filename)
	}

	return p.file
}

func (v *parser) parse() {
	for v.peek(0) != nil {
		if n := v.parseStatement(); n != nil {
			v.pushNode(n)
		} else {
			v.consumeToken() // TODO
		}
	}
}

func (v *parser) parseStatement() Node {
	if decl := v.parseDecl(); decl != nil {
		return decl
	}
	return nil
}

func (v *parser) parseDecl() Decl {
	if variableDecl := v.parseVariableDecl(); variableDecl != nil {
		return variableDecl
	}
	return nil
}

func (v *parser) parseVariableDecl() *VariableDecl {
	variable := &Variable{}
	varDecl := &VariableDecl{
		Variable: variable,
	}

	if v.tokenMatches(0, lexer.TOKEN_IDENTIFIER, KEYWORD_MUT) {
		variable.Mutable = true
		v.consumeToken()
	}

	if v.tokensMatch(lexer.TOKEN_IDENTIFIER, "", lexer.TOKEN_OPERATOR, ":") {
		variable.Name = v.consumeToken().Contents // consume name

		v.consumeToken() // consume :

		if v.tokenMatches(0, lexer.TOKEN_IDENTIFIER, "") {
			typeName := v.consumeToken().Contents // consume type

			variable.Type = v.scope.GetType(typeName)
			if variable.Type == nil {
				v.err("Unrecognized type `%s`", typeName)
			}
		} else if v.tokenMatches(0, lexer.TOKEN_OPERATOR, "=") {
			panic("type inference unimplemented")
		}

		if v.tokenMatches(0, lexer.TOKEN_OPERATOR, "=") {
			v.consumeToken() // consume =
			varDecl.Assignment = v.parseExpr()
			if varDecl.Assignment == nil {
				v.err("Expected expression in assignment to variable `%s`", variable.Name)
			}

		} else if v.tokenMatches(0, lexer.TOKEN_SEPARATOR, ";") {
			v.consumeToken()
		} else {
			v.err("Missing semicolon at end of variable declaration")
		}
	} else {
		return nil
	}

	if sname := v.scope.InsertVariable(variable); sname != nil {
		v.err("Illegal redeclaration of variable `%s`", variable.Name)
	}
	return varDecl
}

func (v *parser) parseExpr() Expr {
	if litExpr := v.parseLiteral(); litExpr != nil {
		return litExpr
	}
	return nil
}

func (v *parser) parseLiteral() Expr {
	if numLit := v.parseNumericLiteral(); numLit != nil {
		return numLit
	} else if stringLit := v.parseStringLiteral(); stringLit != nil {
		return stringLit
	} else if runeLit := v.parseRuneLiteral(); runeLit != nil {
		return runeLit
	}
	return nil
}

func (v *parser) parseNumericLiteral() Expr {
	if !v.tokenMatches(0, lexer.TOKEN_NUMBER, "") {
		return nil
	}

	num := v.consumeToken().Contents
	var err error

	if strings.HasPrefix(num, "0x") || strings.HasPrefix(num, "0X") {
		// Hexadecimal integer
		hex := &IntegerLiteral {}
		hex.Value, err = strconv.ParseUint(num[2:], 16, 64)
		if err != nil {
			panic("bad hex got through lexer")
		}
		return hex
	} else if strings.HasPrefix(num, "0b") {
		// Binary integer
		bin := &IntegerLiteral {}
		bin.Value, err = strconv.ParseUint(num[2:], 2, 64)
		if err != nil {
			panic("bad binary got through lexer")
		}
		return bin
	} else if strings.HasPrefix(num, "0o") {
		// Octal integer
		oct := &IntegerLiteral {}
		oct.Value, err = strconv.ParseUint(num[2:], 8, 64)
		if err != nil {
			panic("bad octal got through lexer")
		}
		return oct
	} else if strings.ContainsRune(num, '.') || strings.HasSuffix(num, "f") || strings.HasSuffix(num, "d") {
		if strings.Count(num, ".") > 1 {
			v.err("Floating-point cannot have multiple periods: `%s`", num)
			return nil
		}
		// TODO parse float
		return nil
	} else {
		// Decimal integer
		i := &IntegerLiteral {}
		i.Value, err = strconv.ParseUint(num, 10, 64)
		if err != nil {
			panic("bad decimal got through lexer")
		}
		return i
	}
}

func (v *parser) parseStringLiteral() *StringLiteral {
	return nil
}

func (v *parser) parseRuneLiteral() *RuneLiteral {
	return nil
}
<commit_msg>small fixes<commit_after>package parser

// Note that you should include a lot of calls to panic() where something's happening that shouldn't be.
// This will help to find bugs. Once the compiler is in a better state, a lot of these calls can be removed.

import (
	"fmt"
	"os"
	"strings"
	"strconv"

	"github.com/ark-lang/ark-go/lexer"
	"github.com/ark-lang/ark-go/util"
)

type parser struct {
	file         *File
	input        []*lexer.Token
	currentToken int
	verbose      bool

	scope *Scope
}

func (v *parser) err(err string, stuff ...interface{}) {
	fmt.Printf(util.TEXT_RED+util.TEXT_BOLD+"Parser error:"+util.TEXT_RESET+" [%s:%d:%d] %s\n",
		v.peek(0).Filename, v.peek(0).LineNumber, v.peek(0).CharNumber, fmt.Sprintf(err, stuff...))
	os.Exit(2)
}

func (v *parser) peek(ahead int) *lexer.Token {
	if ahead < 0 {
		panic(fmt.Sprintf("Tried to peek a negative number: %d", ahead))
	}

	if v.currentToken+ahead >= len(v.input) {
		return nil
	}

	return v.input[v.currentToken+ahead]
}

func (v *parser) consumeToken() *lexer.Token {
	ret := v.peek(0)
	v.currentToken++
	return ret
}

func (v *parser) pushNode(node Node) {
	v.file.nodes = append(v.file.nodes, node)
}

func (v *parser) pushScope() {
	v.scope = newScope(v.scope)
}

func (v *parser) popScope() {
	v.scope = v.scope.Outer
	if v.scope == nil {
		panic("pushed too many scopes")
	}
}

func (v *parser) tokenMatches(ahead int, t lexer.TokenType, contents string) bool {
	tok := v.peek(ahead)
	return tok.Type == t && (contents == "" || (tok.Contents == contents))
}

func (v *parser) tokensMatch(args ...interface{}) bool {
	if len(args)%2 != 0 {
		panic("passed uneven args to tokensMatch")
	}

	for i := 0; i < len(args)/2; i++ {
		if !(v.tokenMatches(i, args[i*2].(lexer.TokenType), args[i*2+1].(string))) {
			return false
		}
	}
	return true
}

func Parse(tokens []*lexer.Token, verbose bool) *File {
	p := &parser{
		file: &File{
			nodes: make([]Node, 0),
		},
		input:   tokens,
		verbose: verbose,
		scope:   newGlobalScope(),
	}

	if verbose {
		fmt.Println(util.TEXT_BOLD+util.TEXT_GREEN+"Started parsing"+util.TEXT_RESET, tokens[0].Filename)
	}
	p.parse()
	if verbose {
		fmt.Println(util.TEXT_BOLD+util.TEXT_GREEN+"Finished parsing"+util.TEXT_RESET, tokens[0].Filename)
	}

	return p.file
}

func (v *parser) parse() {
	for v.peek(0) != nil {
		if n := v.parseStatement(); n != nil {
			v.pushNode(n)
		} else {
			v.consumeToken() // TODO
		}
	}
}

func (v *parser) parseStatement() Node {
	if decl := v.parseDecl(); decl != nil {
		return decl
	}
	return nil
}

func (v *parser) parseDecl() Decl {
	if variableDecl := v.parseVariableDecl(); variableDecl != nil {
		return variableDecl
	}
	return nil
}

func (v *parser) parseVariableDecl() *VariableDecl {
	variable := &Variable{}
	varDecl := &VariableDecl{
		Variable: variable,
	}

	if v.tokenMatches(0, lexer.TOKEN_IDENTIFIER, KEYWORD_MUT) {
		variable.Mutable = true
		v.consumeToken()
	}

	if v.tokensMatch(lexer.TOKEN_IDENTIFIER, "", lexer.TOKEN_OPERATOR, ":") {
		variable.Name = v.consumeToken().Contents // consume name

		v.consumeToken() // consume :

		if v.tokenMatches(0, lexer.TOKEN_IDENTIFIER, "") {
			typeName := v.consumeToken().Contents // consume type

			variable.Type = v.scope.GetType(typeName)
			if variable.Type == nil {
				v.err("Unrecognized type `%s`", typeName)
			}
		} else if v.tokenMatches(0, lexer.TOKEN_OPERATOR, "=") {
			panic("type inference unimplemented")
		}

		if v.tokenMatches(0, lexer.TOKEN_OPERATOR, "=") {
			v.consumeToken() // consume =
			varDecl.Assignment = v.parseExpr()
			if varDecl.Assignment == nil {
				v.err("Expected expression in assignment to variable `%s`", variable.Name)
			}
		}

		if v.tokenMatches(0, lexer.TOKEN_SEPARATOR, ";") {
			v.consumeToken()
		} else {
			v.err("Missing semicolon at end of variable declaration")
		}
	} else {
		return nil
	}

	if sname := v.scope.InsertVariable(variable); sname != nil {
		v.err("Illegal redeclaration of variable `%s`", variable.Name)
	}
	return varDecl
}

func (v *parser) parseExpr() Expr {
	if litExpr := v.parseLiteral(); litExpr != nil {
		return litExpr
	}
	return nil
}

func (v *parser) parseLiteral() Expr {
	if numLit := v.parseNumericLiteral(); numLit != nil {
		return numLit
	} else if stringLit := v.parseStringLiteral(); stringLit != nil {
		return stringLit
	} else if runeLit := v.parseRuneLiteral(); runeLit != nil {
		return runeLit
	}
	return nil
}

func (v *parser) parseNumericLiteral() Expr {
	if !v.tokenMatches(0, lexer.TOKEN_NUMBER, "") {
		return nil
	}

	num := v.consumeToken().Contents
	var err error

	if strings.HasPrefix(num, "0x") || strings.HasPrefix(num, "0X") {
		// Hexadecimal integer
		hex := &IntegerLiteral {}
		hex.Value, err = strconv.ParseUint(num[2:], 16, 64)
		if err != nil {
			panic("bad hex got through lexer")
		}
		return hex
	} else if strings.HasPrefix(num, "0b") {
		// Binary integer
		bin := &IntegerLiteral {}
		bin.Value, err = strconv.ParseUint(num[2:], 2, 64)
		if err != nil {
			panic("bad binary got through lexer")
		}
		return bin
	} else if strings.HasPrefix(num, "0o") {
		// Octal integer
		oct := &IntegerLiteral {}
		oct.Value, err = strconv.ParseUint(num[2:], 8, 64)
		if err != nil {
			panic("bad octal got through lexer")
		}
		return oct
	} else if strings.ContainsRune(num, '.') || strings.HasSuffix(num, "f") || strings.HasSuffix(num, "d") {
		if strings.Count(num, ".") > 1 {
			v.err("Floating-point cannot have multiple periods: `%s`", num)
			return nil
		}
		// TODO parse float
		return nil
	} else {
		// Decimal integer
		i := &IntegerLiteral {}
		i.Value, err = strconv.ParseUint(num, 10, 64)
		if err != nil {
			panic("bad decimal got through lexer")
		}
		return i
	}
}

func (v *parser) parseStringLiteral() *StringLiteral {
	return nil
}

func (v *parser) parseRuneLiteral() *RuneLiteral {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"image"
	"image/color"
	"log"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/ebitenutil"
)

var square *ebiten.Image

func block(screen *ebiten.Image) {
	if square == nil {

		// Create an 16x16 image
		square, _ = ebiten.NewImage(16, 16, ebiten.FilterNearest)
	}

	// Fill the square with the white color

	square.Fill(color.White)

	// Create an empty option struct
	opts := &ebiten.DrawImageOptions{}

	// Add the Translate effect to the option struct.
	w, h := screen.Size()
	w = (w / 2) - (16 / 2)
	h = (h / 2) - (16 / 2)
	opts.GeoM.Translate(float64(w), float64(h))

	// Draw the square image to the screen with an empty option
	screen.DrawImage(square, opts)
}

var img *image.RGBA
var screenWidth = 320
var screenHeight = 240

func drawPix(x, y int) {
	pos := 4*y*screenWidth + 4*x
	img.Pix[pos] = 0xff
	img.Pix[pos+1] = 0xff
	img.Pix[pos+2] = 0xff
	img.Pix[pos+3] = 0xff
}

func update(screen *ebiten.Image) error {

	screen.Fill(color.NRGBA{0x00, 0x00, 0xff, 0xff})

	block(screen)
	////

	drawPix(100, 100)
	drawPix(101, 100)
	drawPix(102, 100)
	drawPix(103, 100)
	drawPix(104, 100)
	drawPix(105, 100)
	drawPix(100, 100)
	drawPix(101, 101)
	drawPix(102, 102)
	drawPix(103, 103)
	drawPix(104, 104)
	drawPix(105, 105)
	screen.ReplacePixels(img.Pix)

	////
	if ebiten.IsKeyPressed(ebiten.KeyUp) {
		ebitenutil.DebugPrint(screen, "You're pressing the 'UP' button.")
	}
	// When the "down arrow key" is pressed..
	if ebiten.IsKeyPressed(ebiten.KeyDown) {
		ebitenutil.DebugPrint(screen, "\nYou're pressing the 'DOWN' button.")
	}
	// When the "left arrow key" is pressed..
	if ebiten.IsKeyPressed(ebiten.KeyLeft) {
		ebitenutil.DebugPrint(screen, "\n\nYou're pressing the 'LEFT' button.")
	}
	// When the "right arrow key" is pressed..
	if ebiten.IsKeyPressed(ebiten.KeyRight) {
		ebitenutil.DebugPrint(screen, "\n\n\nYou're pressing the 'RIGHT' button.")
	}

	// When the "left mouse button" is pressed...
	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
		ebitenutil.DebugPrint(screen, "You're pressing the 'LEFT' mouse button.")
	}
	// When the "right mouse button" is pressed...
	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonRight) {
		ebitenutil.DebugPrint(screen, "\nYou're pressing the 'RIGHT' mouse button.")
	}
	// When the "middle mouse button" is pressed...
	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonMiddle) {
		ebitenutil.DebugPrint(screen, "\n\nYou're pressing the 'MIDDLE' mouse button.")
	}

	x, y := ebiten.CursorPosition()

	// Display the information with "X: xx, Y: xx" format
	ebitenutil.DebugPrint(screen, fmt.Sprintf("X: %d, Y: %d", x, y))

	return nil
}

func main() {

	img = image.NewRGBA(image.Rect(0, 0, screenWidth, screenHeight))
	if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Game of Life (Ebiten Demo)"); err != nil {
		log.Fatal(err)
	}

	if err := ebiten.Run(update, 320, 240, 2, "Metal"); err != nil {
		panic(err)
	}

}
<commit_msg>update window title<commit_after>package main

import (
	"fmt"
	"image"
	"image/color"
	"log"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/ebitenutil"
)

var square *ebiten.Image

func block(screen *ebiten.Image) {
	if square == nil {

		// Create an 16x16 image
		square, _ = ebiten.NewImage(16, 16, ebiten.FilterNearest)
	}

	// Fill the square with the white color

	square.Fill(color.White)

	// Create an empty option struct
	opts := &ebiten.DrawImageOptions{}

	// Add the Translate effect to the option struct.
	w, h := screen.Size()
	w = (w / 2) - (16 / 2)
	h = (h / 2) - (16 / 2)
	opts.GeoM.Translate(float64(w), float64(h))

	// Draw the square image to the screen with an empty option
	screen.DrawImage(square, opts)
}

var img *image.RGBA
var screenWidth = 320
var screenHeight = 240

func drawPix(x, y int) {
	pos := 4*y*screenWidth + 4*x
	img.Pix[pos] = 0xff
	img.Pix[pos+1] = 0xff
	img.Pix[pos+2] = 0xff
	img.Pix[pos+3] = 0xff
}

func update(screen *ebiten.Image) error {

	screen.Fill(color.NRGBA{0x00, 0x00, 0xff, 0xff})

	block(screen)
	////

	drawPix(100, 100)
	drawPix(101, 100)
	drawPix(102, 100)
	drawPix(103, 100)
	drawPix(104, 100)
	drawPix(105, 100)
	drawPix(100, 100)
	drawPix(101, 101)
	drawPix(102, 102)
	drawPix(103, 103)
	drawPix(104, 104)
	drawPix(105, 105)
	screen.ReplacePixels(img.Pix)

	////
	if ebiten.IsKeyPressed(ebiten.KeyUp) {
		ebitenutil.DebugPrint(screen, "You're pressing the 'UP' button.")
	}
	// When the "down arrow key" is pressed..
	if ebiten.IsKeyPressed(ebiten.KeyDown) {
		ebitenutil.DebugPrint(screen, "\nYou're pressing the 'DOWN' button.")
	}
	// When the "left arrow key" is pressed..
	if ebiten.IsKeyPressed(ebiten.KeyLeft) {
		ebitenutil.DebugPrint(screen, "\n\nYou're pressing the 'LEFT' button.")
	}
	// When the "right arrow key" is pressed..
	if ebiten.IsKeyPressed(ebiten.KeyRight) {
		ebitenutil.DebugPrint(screen, "\n\n\nYou're pressing the 'RIGHT' button.")
	}

	// When the "left mouse button" is pressed...
	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
		ebitenutil.DebugPrint(screen, "You're pressing the 'LEFT' mouse button.")
	}
	// When the "right mouse button" is pressed...
	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonRight) {
		ebitenutil.DebugPrint(screen, "\nYou're pressing the 'RIGHT' mouse button.")
	}
	// When the "middle mouse button" is pressed...
	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonMiddle) {
		ebitenutil.DebugPrint(screen, "\n\nYou're pressing the 'MIDDLE' mouse button.")
	}

	x, y := ebiten.CursorPosition()

	// Display the information with "X: xx, Y: xx" format
	ebitenutil.DebugPrint(screen, fmt.Sprintf("X: %d, Y: %d", x, y))

	return nil
}

func main() {

	img = image.NewRGBA(image.Rect(0, 0, screenWidth, screenHeight))
	if err := ebiten.Run(update, screenWidth, screenHeight, 2, "METAL BASIC 0.01"); err != nil {
		log.Fatal(err)
	}

	if err := ebiten.Run(update, 320, 240, 2, "Metal"); err != nil {
		panic(err)
	}

}
<|endoftext|>


<commit_before>package main

import "os"
import "os/exec"
import "strings"
import "sync"
import "os/signal"
import "syscall"
import "github.com/robfig/cron"

import (
	"fmt"
	"net/http"
)

var last_err error

func execute(command string, args []string) {

	println("executing:", command, strings.Join(args, " "))

	cmd := exec.Command(command, args...)

	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	last_err = cmd.Run()
	cmd.Wait()
}

func create() (cr *cron.Cron, wgr *sync.WaitGroup) {
	var schedule string = os.Args[1]
	var command string = os.Args[2]
	var args []string = os.Args[3:len(os.Args)]

	wg := &sync.WaitGroup{}

	c := cron.New()
	println("new cron:", schedule)

	c.AddFunc(schedule, func() {
		wg.Add(1)
		execute(command, args)
		wg.Done()
	})

	return c, wg
}

func handler(w http.ResponseWriter, r *http.Request) {
	if last_err != nil {
		http.Error(w, last_err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "OK")
}

func http_server(c *cron.Cron, wg *sync.WaitGroup) {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":18080", nil)
}

func start(c *cron.Cron, wg *sync.WaitGroup) {
	c.Start()
}

func stop(c *cron.Cron, wg *sync.WaitGroup) {
	println("Stopping")
	c.Stop()
	println("Waiting")
	wg.Wait()
	println("Exiting")
	os.Exit(0)
}

func main() {

	c, wg := create()

	go start(c, wg)
	go http_server(c, wg)

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	println(<-ch)
	stop(c, wg)
}
<commit_msg>Rewrite<commit_after>package main

import "os"
import "os/exec"
import "strings"
import "sync"
import "os/signal"
import "syscall"
import "github.com/robfig/cron"
import "log"

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

//var last_err error
var last_err LastRun

type LastRun struct {
	exit_status int
	//stdout      bytes.Buffer
	//stderr      bytes.Buffer
	stdout string
	stderr string
}

func execute(command string, args []string) {

	log.Println("executing:", command, strings.Join(args, " "))

	cmd := exec.Command(command, args...)
	//last_err.stdout.Reset()
	//last_err.stderr.Reset()

	var stdout bytes.Buffer
	var stderr bytes.Buffer

	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	if err := cmd.Start(); err != nil {
		log.Fatalf("cmd.Start: %v")
	}
	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0

			last_err.exit_status = 0

			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				last_err.exit_status = status.ExitStatus()
				log.Printf("Exit Status: %d", last_err.exit_status)
			}
			last_err.stderr = stderr.String()
			last_err.stdout = stdout.String()
		} else {
			log.Fatalf("cmd.Wait: %v", err)
		}
	}
}

func create() (cr *cron.Cron, wgr *sync.WaitGroup) {
	var schedule string = os.Args[1]
	var command string = os.Args[2]
	var args []string = os.Args[3:len(os.Args)]

	wg := &sync.WaitGroup{}

	c := cron.New()
	log.Println("new cron:", schedule)

	c.AddFunc(schedule, func() {
		wg.Add(1)
		execute(command, args)
		wg.Done()
	})

	return c, wg
}

func handler(w http.ResponseWriter, r *http.Request) {
	if last_err.exit_status != 0 {
		b, _ := json.Marshal(last_err)
		log.Println(string(b[:len(b)]))
		http.Error(w, last_err.stderr, http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, last_err.stdout)
}

func http_server(c *cron.Cron, wg *sync.WaitGroup) {
	http.HandleFunc("/", handler)
	err := http.ListenAndServe(":18080", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func start(c *cron.Cron, wg *sync.WaitGroup) {
	c.Start()
}

func stop(c *cron.Cron, wg *sync.WaitGroup) {
	log.Println("Stopping")
	c.Stop()
	log.Println("Waiting")
	wg.Wait()
	log.Println("Exiting")
	os.Exit(0)
}

func main() {

	c, wg := create()

	go start(c, wg)
	go http_server(c, wg)

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	println(<-ch)
	stop(c, wg)
}
<|endoftext|>


<commit_before>package zerolog

import "testing"

func TestAppendJSONString(t *testing.T) {
	encodeStringTests := []struct {
		in  string
		out string
	}{
		{"\\", `"\\"`},
		{"\x00", `"\u0000"`},
		{"\x01", `"\u0001"`},
		{"\x02", `"\u0002"`},
		{"\x03", `"\u0003"`},
		{"\x04", `"\u0004"`},
		{"\x05", `"\u0005"`},
		{"\x06", `"\u0006"`},
		{"\x07", `"\u0007"`},
		{"\x08", `"\b"`},
		{"\x09", `"\t"`},
		{"\x0a", `"\n"`},
		{"\x0b", `"\u000b"`},
		{"\x0c", `"\f"`},
		{"\x0d", `"\r"`},
		{"\x0e", `"\u000e"`},
		{"\x0f", `"\u000f"`},
		{"\x10", `"\u0010"`},
		{"\x11", `"\u0011"`},
		{"\x12", `"\u0012"`},
		{"\x13", `"\u0013"`},
		{"\x14", `"\u0014"`},
		{"\x15", `"\u0015"`},
		{"\x16", `"\u0016"`},
		{"\x17", `"\u0017"`},
		{"\x18", `"\u0018"`},
		{"\x19", `"\u0019"`},
		{"\x1a", `"\u001a"`},
		{"\x1b", `"\u001b"`},
		{"\x1c", `"\u001c"`},
		{"\x1d", `"\u001d"`},
		{"\x1e", `"\u001e"`},
		{"\x1f", `"\u001f"`},
		{"ascii", `"ascii"`},
		{"emoji \u2764\ufe0f!", `"emoji ❤!"`},
	}

	for _, tt := range encodeStringTests {
		b := appendJSONString([]byte{}, tt.in)
		if got, want := string(b), tt.out; got != want {
			t.Errorf("appendJSONString(%q) = %#q, want %#q", tt.in, got, want)
		}
	}
}
<commit_msg>Add some json encoder benchmarks<commit_after>package zerolog

import (
	"testing"
)

func TestAppendJSONString(t *testing.T) {
	encodeStringTests := []struct {
		in  string
		out string
	}{
		{"", `""`},
		{"\\", `"\\"`},
		{"\x00", `"\u0000"`},
		{"\x01", `"\u0001"`},
		{"\x02", `"\u0002"`},
		{"\x03", `"\u0003"`},
		{"\x04", `"\u0004"`},
		{"\x05", `"\u0005"`},
		{"\x06", `"\u0006"`},
		{"\x07", `"\u0007"`},
		{"\x08", `"\b"`},
		{"\x09", `"\t"`},
		{"\x0a", `"\n"`},
		{"\x0b", `"\u000b"`},
		{"\x0c", `"\f"`},
		{"\x0d", `"\r"`},
		{"\x0e", `"\u000e"`},
		{"\x0f", `"\u000f"`},
		{"\x10", `"\u0010"`},
		{"\x11", `"\u0011"`},
		{"\x12", `"\u0012"`},
		{"\x13", `"\u0013"`},
		{"\x14", `"\u0014"`},
		{"\x15", `"\u0015"`},
		{"\x16", `"\u0016"`},
		{"\x17", `"\u0017"`},
		{"\x18", `"\u0018"`},
		{"\x19", `"\u0019"`},
		{"\x1a", `"\u001a"`},
		{"\x1b", `"\u001b"`},
		{"\x1c", `"\u001c"`},
		{"\x1d", `"\u001d"`},
		{"\x1e", `"\u001e"`},
		{"\x1f", `"\u001f"`},
		{"ascii", `"ascii"`},
		{"\"a", `"\"a"`},
		{"\x1fa", `"\u001fa"`},
		{"foo\"bar\"baz", `"foo\"bar\"baz"`},
		{"\x1ffoo\x1fbar\x1fbaz", `"\u001ffoo\u001fbar\u001fbaz"`},
		{"emoji \u2764\ufe0f!", `"emoji ❤!"`},
	}

	for _, tt := range encodeStringTests {
		b := appendJSONString([]byte{}, tt.in)
		if got, want := string(b), tt.out; got != want {
			t.Errorf("appendJSONString(%q) = %#q, want %#q", tt.in, got, want)
		}
	}
}

func BenchmarkAppendJSONString(b *testing.B) {
	tests := map[string]string{
		"NoEncoding":     `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`,
		"EncodingFirst":  `"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`,
		"EncodingMiddle": `aaaaaaaaaaaaaaaaaaaaaaaaa"aaaaaaaaaaaaaaaaaaaaaaaa`,
		"EncodingLast":   `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"`,
		"RuneFirst":      `❤aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`,
		"RuneMiddle":     `aaaaaaaaaaaaaaaaaaaaaaaaa❤aaaaaaaaaaaaaaaaaaaaaaaa`,
		"RuneLast":       `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa❤`,
	}
	for name, str := range tests {
		b.Run(name, func(b *testing.B) {
			buf := make([]byte, 0, 100)
			for i := 0; i < b.N; i++ {
				_ = appendJSONString(buf, str)
			}
		})
	}
}
<|endoftext|>