<commit_before>package cl11

import (
	"fmt"
	"unsafe"

	clw "github.com/rdwilliamson/clw11"
)

// Event objects can be used to refer to a kernel execution command, read,
// write, map and copy commands on memory objects, EnqueueMarker, or user
// events.
//
// An event object can be used to track the execution status of a command. The
// API calls that enqueue commands to a command-queue create a new event object
// that is returned in the event argument.
type Event struct {
	id clw.Event

	// The context the event was created on.
	Context *Context

	// The command type the event represents.
	CommandType CommandType

	// The command queue the event was created on.
	CommandQueue *CommandQueue

	Queued int64 // Profiling information.
	Submit int64 // Profiling information.
	Start  int64 // Profiling information.
	End    int64 // Profiling information.
}

// Differs from clw.EventCallbackFunc because the command execution status is
// either Complete (success) or an error.
type EventCallback func(e *Event, err error, userData interface{})

var noOpEventCallback EventCallback = func(e *Event, err error, userData interface{}) {
	// TODO how to report errors here?
	e.Release()
}

type CommandType int

const (
	CommandNDRangeKernel        = CommandType(clw.CommandNdrangeKernel)
	CommandTask                 = CommandType(clw.CommandTask)
	CommandNativeKernel         = CommandType(clw.CommandNativeKernel)
	CommandReadBuffer           = CommandType(clw.CommandReadBuffer)
	CommandWriteBuffer          = CommandType(clw.CommandWriteBuffer)
	CommandCopyBuffer           = CommandType(clw.CommandCopyBuffer)
	CommandReadImage            = CommandType(clw.CommandReadImage)
	CommandWriteImage           = CommandType(clw.CommandWriteImage)
	CommandCopyImage            = CommandType(clw.CommandCopyImage)
	CommandCopyImageToBuffer    = CommandType(clw.CommandCopyImageToBuffer)
	CommandCopyBufferToImage    = CommandType(clw.CommandCopyBufferToImage)
	CommandMapBuffer            = CommandType(clw.CommandMapBuffer)
	CommandMapImage             = CommandType(clw.CommandMapImage)
	CommandUnmapMemoryObject    = CommandType(clw.CommandUnmapMemoryObject)
	CommandMarker               = CommandType(clw.CommandMarker)
	CommandAcquireGlObjects     = CommandType(clw.CommandAcquireGlObjects)
	CommandReleaseGlObjects     = CommandType(clw.CommandReleaseGlObjects)
	CommandReadBufferRectangle  = CommandType(clw.CommandReadBufferRectangle)
	CommandWriteBufferRectangle = CommandType(clw.CommandWriteBufferRectangle)
	CommandCopyBufferRectangle  = CommandType(clw.CommandCopyBufferRectangle)
	CommandUser                 = CommandType(clw.CommandUser)
)

var commandTypeMap = map[CommandType]string{
	CommandNDRangeKernel:        "ND range kernel",
	CommandTask:                 "task",
	CommandNativeKernel:         "native kernel",
	CommandReadBuffer:           "read buffer",
	CommandWriteBuffer:          "write buffer",
	CommandCopyBuffer:           "copy buffer",
	CommandReadImage:            "read image",
	CommandWriteImage:           "write image",
	CommandCopyImage:            "copy image",
	CommandCopyImageToBuffer:    "copy image to buffer",
	CommandCopyBufferToImage:    "copy buffer to image",
	CommandMapBuffer:            "map buffer",
	CommandMapImage:             "map image",
	CommandUnmapMemoryObject:    "unmap memory object",
	CommandMarker:               "marker",
	CommandAcquireGlObjects:     "acquire GL objects",
	CommandReleaseGlObjects:     "release GL objects",
	CommandReadBufferRectangle:  "read buffer rectangle",
	CommandWriteBufferRectangle: "write buffer rectangle",
	CommandCopyBufferRectangle:  "copy buffer rectangle",
	CommandUser:                 "user",
}

func (ct CommandType) String() string {
	return commandTypeMap[ct]
}

type CommandExecutionStatus int

const (
	Queued    = CommandExecutionStatus(clw.Queued)
	Submitted = CommandExecutionStatus(clw.Submitted)
	Running   = CommandExecutionStatus(clw.Running)
	Complete  = CommandExecutionStatus(clw.Complete)
)

func (ces CommandExecutionStatus) String() string {
	switch ces {
	case Complete:
		return "complete"
	case Running:
		return "running"
	case Submitted:
		return "submitted"
	case Queued:
		return "queued"
	}
	return ""
}

// Return the execution status of the command identified by event.
//
// Statuses are: Queued (command has been enqueued in the command-queue),
// Submitted (enqueued command has been submitted by the host to the device
// associated with the command-queue), Running (device is currently executing
// this command), Complete (the command has completed).
//
// An eventErr is an error that cause the event to abnormally terminate. A
// getStatusErr is an error that occurred while trying to retrieve the event's
// status.
func (e *Event) Status() (ces CommandExecutionStatus, eventErr, getStatusErr error) {

	err := clw.GetEventInfo(e.id, clw.EventCommandExecutionStatus, clw.Size(unsafe.Sizeof(ces)),
		unsafe.Pointer(&ces), nil)
	if err != nil {
		return 0, nil, err
	}

	if ces < 0 {
		return 0, fmt.Errorf("cl: event abnormally terminated: %s", clw.CodeToError(clw.Int(ces)).Error()), nil
	}

	return CommandExecutionStatus(ces), nil, nil
}

// Gets profiling information for the command associated with event if profiling
// is enabled.
//
// The 64-bit values can be used to measure the time in nano-seconds consumed by
// OpenCL commands.
//
// OpenCL devices are required to correctly track time across changes in device
// frequency and power states. The Device.ProfilingTimerResolution specifies the
// resolution of the timer i.e. the number of nanoseconds elapsed before the
// timer is incremented.
//
// Event objects can be used to capture profiling information that measure
// execution time of a command. Profiling of OpenCL commands can be enabled
// either by using a command-queue created with QueueProfilingEnable flag set in
// properties argument to CreateCommandQueue.
func (e *Event) GetProfilingInfo() error {

	var value clw.Ulong
	err := clw.GetEventProfilingInfo(e.id, clw.ProfilingCommandQueued, clw.Size(unsafe.Sizeof(value)),
		unsafe.Pointer(&value), nil)
	if err != nil {
		return err
	}
	e.Queued = int64(value)

	err = clw.GetEventProfilingInfo(e.id, clw.ProfilingCommandSubmit, clw.Size(unsafe.Sizeof(value)),
		unsafe.Pointer(&value), nil)
	if err != nil {
		return err
	}
	e.Submit = int64(value)

	err = clw.GetEventProfilingInfo(e.id, clw.ProfilingCommandStart, clw.Size(unsafe.Sizeof(value)),
		unsafe.Pointer(&value), nil)
	if err != nil {
		return err
	}
	e.Start = int64(value)

	err = clw.GetEventProfilingInfo(e.id, clw.ProfilingCommandEnd, clw.Size(unsafe.Sizeof(value)),
		unsafe.Pointer(&value), nil)
	if err != nil {
		return err
	}
	e.End = int64(value)

	return nil
}

// Registers a user callback function for a specific command execution status.
//
// The registered callback function will be called when the execution status of
// command associated with event changes to Complete or is abnormally terminated
// due to an error.
//
// Each call to SetCallback registers the specified user callback
// function on a callback stack associated with event. The order in which the
// registered user callback functions are called is undefined.
//
// All callbacks registered for an event object must be called. All enqueued
// callbacks shall be called before the event object is destroyed. Callbacks
// must return promptly. The behavior of calling expensive system routines,
// OpenCL API calls to create contexts or command-queues, or blocking OpenCL
// operations, in a callback is undefined.
func (e *Event) SetCallback(callback EventCallback, userData interface{}) error {
	return clw.SetEventCallback(e.id, clw.Complete,
		func(event clw.Event, ces clw.CommandExecutionStatus, _userData interface{}) {
			var err error
			if ces < 0 {
				err = clw.CodeToError(clw.Int(ces))
			}
			callback(e, err, _userData)
		},
		userData)
}

// Waits on the host thread for the event to complete. See WaitForEvents for
// more info.
func (e *Event) Wait() error {
	return clw.WaitForEvents([]clw.Event{e.id})
}

// Waits on the host thread for commands identified by event objects to
// complete.
//
// Waits on the host thread for commands identified by event objects in
// event_list to complete. A command is considered complete if its execution
// status is "complete" or abnormally terminated (an error occured).
//
// If the cl_khr_gl_event extension is enabled, event objects can also be used
// to reflect the status of an OpenGL sync object. The sync object in turn
// refers to a fence command executing in an OpenGL command stream. This
// provides another method of coordinating sharing of buffers and images between
// OpenGL and OpenCL.
func WaitForEvents(events ...*Event) error {
	waitList := make([]clw.Event, len(events))
	for i := range events {
		waitList[i] = events[i].id
	}
	return clw.WaitForEvents(waitList)
}

// Creates a user event object.
//
// User events allow applications to enqueue commands that wait on a user event
// to finish before the command is executed by the device. The execution status
// of the user event object created is set to Submitted.
//
// Enqueued commands that specify user events must ensure that the status of the
// user events be set before any OpenCL APIs that release OpenCL objects except
// for event objects are called.
func (c *Context) CreateUserEvent() (*Event, error) {

	event, err := clw.CreateUserEvent(c.id)
	if err != nil {
		return nil, err
	}

	return &Event{
		id:          event,
		Context:     c,
		CommandType: CommandUser,
	}, nil
}

// Sets the execution status of a user event object to Complete.
func (e *Event) SetComplete() error {
	return clw.SetUserEventStatus(e.id, clw.Int(clw.Complete))
}

// Sets the execution status of a user event object to an error state. All
// enqueued commands that wait on this user event will be terminated. Err must
// be negative.
func (e *Event) SetError(err int) error {
	return clw.SetUserEventStatus(e.id, clw.Int(err))
}

// Increments the event reference count.
//
// The OpenCL commands that return an event perform an implicit retain.
func (e *Event) Retain() error {
	return clw.RetainEvent(e.id)
}

// Decrements the event reference count.
//
// The event object is deleted once the reference count becomes zero, the
// specific command identified by this event has completed (or terminated) and
// there are no commands in the command-queues of a context that require a wait
// for this event to complete.
func (e *Event) Release() error {
	return clw.ReleaseEvent(e.id)
}

// The event reference count.
//
// The reference count returned should be considered immediately stale. It is
// unsuitable for general use in applications. This feature is provided for
// identifying memory leaks.
func (e *Event) ReferenceCount() (int, error) {
	var param clw.Uint
	err := clw.GetEventInfo(e.id, clw.EventReferenceCount, clw.Size(unsafe.Sizeof(param)), unsafe.Pointer(&param), nil)
	return int(param), err
}
<commit_msg>Removed explicit EventCallback type from noOpEventCallback declaration.<commit_after>package cl11

import (
	"fmt"
	"unsafe"

	clw "github.com/rdwilliamson/clw11"
)

// Event objects can be used to refer to a kernel execution command, read,
// write, map and copy commands on memory objects, EnqueueMarker, or user
// events.
//
// An event object can be used to track the execution status of a command. The
// API calls that enqueue commands to a command-queue create a new event object
// that is returned in the event argument.
type Event struct {
	id clw.Event

	// The context the event was created on.
	Context *Context

	// The command type the event represents.
	CommandType CommandType

	// The command queue the event was created on.
	CommandQueue *CommandQueue

	Queued int64 // Profiling information.
	Submit int64 // Profiling information.
	Start  int64 // Profiling information.
	End    int64 // Profiling information.
}

// Differs from clw.EventCallbackFunc because the command execution status is
// either Complete (success) or an error.
type EventCallback func(e *Event, err error, userData interface{})

var noOpEventCallback = func(e *Event, err error, userData interface{}) {
	// TODO how to report errors here?
	e.Release()
}

type CommandType int

const (
	CommandNDRangeKernel        = CommandType(clw.CommandNdrangeKernel)
	CommandTask                 = CommandType(clw.CommandTask)
	CommandNativeKernel         = CommandType(clw.CommandNativeKernel)
	CommandReadBuffer           = CommandType(clw.CommandReadBuffer)
	CommandWriteBuffer          = CommandType(clw.CommandWriteBuffer)
	CommandCopyBuffer           = CommandType(clw.CommandCopyBuffer)
	CommandReadImage            = CommandType(clw.CommandReadImage)
	CommandWriteImage           = CommandType(clw.CommandWriteImage)
	CommandCopyImage            = CommandType(clw.CommandCopyImage)
	CommandCopyImageToBuffer    = CommandType(clw.CommandCopyImageToBuffer)
	CommandCopyBufferToImage    = CommandType(clw.CommandCopyBufferToImage)
	CommandMapBuffer            = CommandType(clw.CommandMapBuffer)
	CommandMapImage             = CommandType(clw.CommandMapImage)
	CommandUnmapMemoryObject    = CommandType(clw.CommandUnmapMemoryObject)
	CommandMarker               = CommandType(clw.CommandMarker)
	CommandAcquireGlObjects     = CommandType(clw.CommandAcquireGlObjects)
	CommandReleaseGlObjects     = CommandType(clw.CommandReleaseGlObjects)
	CommandReadBufferRectangle  = CommandType(clw.CommandReadBufferRectangle)
	CommandWriteBufferRectangle = CommandType(clw.CommandWriteBufferRectangle)
	CommandCopyBufferRectangle  = CommandType(clw.CommandCopyBufferRectangle)
	CommandUser                 = CommandType(clw.CommandUser)
)

var commandTypeMap = map[CommandType]string{
	CommandNDRangeKernel:        "ND range kernel",
	CommandTask:                 "task",
	CommandNativeKernel:         "native kernel",
	CommandReadBuffer:           "read buffer",
	CommandWriteBuffer:          "write buffer",
	CommandCopyBuffer:           "copy buffer",
	CommandReadImage:            "read image",
	CommandWriteImage:           "write image",
	CommandCopyImage:            "copy image",
	CommandCopyImageToBuffer:    "copy image to buffer",
	CommandCopyBufferToImage:    "copy buffer to image",
	CommandMapBuffer:            "map buffer",
	CommandMapImage:             "map image",
	CommandUnmapMemoryObject:    "unmap memory object",
	CommandMarker:               "marker",
	CommandAcquireGlObjects:     "acquire GL objects",
	CommandReleaseGlObjects:     "release GL objects",
	CommandReadBufferRectangle:  "read buffer rectangle",
	CommandWriteBufferRectangle: "write buffer rectangle",
	CommandCopyBufferRectangle:  "copy buffer rectangle",
	CommandUser:                 "user",
}

func (ct CommandType) String() string {
	return commandTypeMap[ct]
}

type CommandExecutionStatus int

const (
	Queued    = CommandExecutionStatus(clw.Queued)
	Submitted = CommandExecutionStatus(clw.Submitted)
	Running   = CommandExecutionStatus(clw.Running)
	Complete  = CommandExecutionStatus(clw.Complete)
)

func (ces CommandExecutionStatus) String() string {
	switch ces {
	case Complete:
		return "complete"
	case Running:
		return "running"
	case Submitted:
		return "submitted"
	case Queued:
		return "queued"
	}
	return ""
}

// Return the execution status of the command identified by event.
//
// Statuses are: Queued (command has been enqueued in the command-queue),
// Submitted (enqueued command has been submitted by the host to the device
// associated with the command-queue), Running (device is currently executing
// this command), Complete (the command has completed).
//
// An eventErr is an error that cause the event to abnormally terminate. A
// getStatusErr is an error that occurred while trying to retrieve the event's
// status.
func (e *Event) Status() (ces CommandExecutionStatus, eventErr, getStatusErr error) {

	err := clw.GetEventInfo(e.id, clw.EventCommandExecutionStatus, clw.Size(unsafe.Sizeof(ces)),
		unsafe.Pointer(&ces), nil)
	if err != nil {
		return 0, nil, err
	}

	if ces < 0 {
		return 0, fmt.Errorf("cl: event abnormally terminated: %s", clw.CodeToError(clw.Int(ces)).Error()), nil
	}

	return CommandExecutionStatus(ces), nil, nil
}

// Gets profiling information for the command associated with event if profiling
// is enabled.
//
// The 64-bit values can be used to measure the time in nano-seconds consumed by
// OpenCL commands.
//
// OpenCL devices are required to correctly track time across changes in device
// frequency and power states. The Device.ProfilingTimerResolution specifies the
// resolution of the timer i.e. the number of nanoseconds elapsed before the
// timer is incremented.
//
// Event objects can be used to capture profiling information that measure
// execution time of a command. Profiling of OpenCL commands can be enabled
// either by using a command-queue created with QueueProfilingEnable flag set in
// properties argument to CreateCommandQueue.
func (e *Event) GetProfilingInfo() error {

	var value clw.Ulong
	err := clw.GetEventProfilingInfo(e.id, clw.ProfilingCommandQueued, clw.Size(unsafe.Sizeof(value)),
		unsafe.Pointer(&value), nil)
	if err != nil {
		return err
	}
	e.Queued = int64(value)

	err = clw.GetEventProfilingInfo(e.id, clw.ProfilingCommandSubmit, clw.Size(unsafe.Sizeof(value)),
		unsafe.Pointer(&value), nil)
	if err != nil {
		return err
	}
	e.Submit = int64(value)

	err = clw.GetEventProfilingInfo(e.id, clw.ProfilingCommandStart, clw.Size(unsafe.Sizeof(value)),
		unsafe.Pointer(&value), nil)
	if err != nil {
		return err
	}
	e.Start = int64(value)

	err = clw.GetEventProfilingInfo(e.id, clw.ProfilingCommandEnd, clw.Size(unsafe.Sizeof(value)),
		unsafe.Pointer(&value), nil)
	if err != nil {
		return err
	}
	e.End = int64(value)

	return nil
}

// Registers a user callback function for a specific command execution status.
//
// The registered callback function will be called when the execution status of
// command associated with event changes to Complete or is abnormally terminated
// due to an error.
//
// Each call to SetCallback registers the specified user callback
// function on a callback stack associated with event. The order in which the
// registered user callback functions are called is undefined.
//
// All callbacks registered for an event object must be called. All enqueued
// callbacks shall be called before the event object is destroyed. Callbacks
// must return promptly. The behavior of calling expensive system routines,
// OpenCL API calls to create contexts or command-queues, or blocking OpenCL
// operations, in a callback is undefined.
func (e *Event) SetCallback(callback EventCallback, userData interface{}) error {
	return clw.SetEventCallback(e.id, clw.Complete,
		func(event clw.Event, ces clw.CommandExecutionStatus, _userData interface{}) {
			var err error
			if ces < 0 {
				err = clw.CodeToError(clw.Int(ces))
			}
			callback(e, err, _userData)
		},
		userData)
}

// Waits on the host thread for the event to complete. See WaitForEvents for
// more info.
func (e *Event) Wait() error {
	return clw.WaitForEvents([]clw.Event{e.id})
}

// Waits on the host thread for commands identified by event objects to
// complete.
//
// Waits on the host thread for commands identified by event objects in
// event_list to complete. A command is considered complete if its execution
// status is "complete" or abnormally terminated (an error occured).
//
// If the cl_khr_gl_event extension is enabled, event objects can also be used
// to reflect the status of an OpenGL sync object. The sync object in turn
// refers to a fence command executing in an OpenGL command stream. This
// provides another method of coordinating sharing of buffers and images between
// OpenGL and OpenCL.
func WaitForEvents(events ...*Event) error {
	waitList := make([]clw.Event, len(events))
	for i := range events {
		waitList[i] = events[i].id
	}
	return clw.WaitForEvents(waitList)
}

// Creates a user event object.
//
// User events allow applications to enqueue commands that wait on a user event
// to finish before the command is executed by the device. The execution status
// of the user event object created is set to Submitted.
//
// Enqueued commands that specify user events must ensure that the status of the
// user events be set before any OpenCL APIs that release OpenCL objects except
// for event objects are called.
func (c *Context) CreateUserEvent() (*Event, error) {

	event, err := clw.CreateUserEvent(c.id)
	if err != nil {
		return nil, err
	}

	return &Event{
		id:          event,
		Context:     c,
		CommandType: CommandUser,
	}, nil
}

// Sets the execution status of a user event object to Complete.
func (e *Event) SetComplete() error {
	return clw.SetUserEventStatus(e.id, clw.Int(clw.Complete))
}

// Sets the execution status of a user event object to an error state. All
// enqueued commands that wait on this user event will be terminated. Err must
// be negative.
func (e *Event) SetError(err int) error {
	return clw.SetUserEventStatus(e.id, clw.Int(err))
}

// Increments the event reference count.
//
// The OpenCL commands that return an event perform an implicit retain.
func (e *Event) Retain() error {
	return clw.RetainEvent(e.id)
}

// Decrements the event reference count.
//
// The event object is deleted once the reference count becomes zero, the
// specific command identified by this event has completed (or terminated) and
// there are no commands in the command-queues of a context that require a wait
// for this event to complete.
func (e *Event) Release() error {
	return clw.ReleaseEvent(e.id)
}

// The event reference count.
//
// The reference count returned should be considered immediately stale. It is
// unsuitable for general use in applications. This feature is provided for
// identifying memory leaks.
func (e *Event) ReferenceCount() (int, error) {
	var param clw.Uint
	err := clw.GetEventInfo(e.id, clw.EventReferenceCount, clw.Size(unsafe.Sizeof(param)), unsafe.Pointer(&param), nil)
	return int(param), err
}
<|endoftext|>


<commit_before>package stripe

import (
	"encoding/json"
	"fmt"
	"strconv"
)

// Event is the resource representing a Stripe event.
// For more details see https://stripe.com/docs/api#events.
type Event struct {
	Account         string        `json:"account"`
	Created         int64         `json:"created"`
	Data            *EventData    `json:"data"`
	ID              string        `json:"id"`
	Livemode        bool          `json:"livemode"`
	PendingWebhooks int64         `json:"pending_webhooks"`
	Request         *EventRequest `json:"request"`
	Type            string        `json:"type"`
}

// EventRequest contains information on a request that created an event.
type EventRequest struct {
	// ID is the request ID of the request that created an event, if the event
	// was created by a request.
	ID string `json:"id"`

	// IdempotencyKey is the idempotency key of the request that created an
	// event, if the event was created by a request and if an idempotency key
	// was specified for that request.
	IdempotencyKey string `json:"idempotency_key"`
}

// EventData is the unmarshalled object as a map.
type EventData struct {
	Object             map[string]interface{}
	PreviousAttributes map[string]interface{} `json:"previous_attributes"`
	Raw                json.RawMessage        `json:"object"`
}

// EventParams is the set of parameters that can be used when retrieving events.
// For more details see https://stripe.com/docs/api#retrieve_events.
type EventParams struct {
	Params `form:"*"`
}

// EventList is a list of events as retrieved from a list endpoint.
type EventList struct {
	ListMeta
	Data []*Event `json:"data"`
}

// EventListParams is the set of parameters that can be used when listing events.
// For more details see https://stripe.com/docs/api#list_events.
type EventListParams struct {
	ListParams   `form:"*"`
	Created      *int64            `form:"created"`
	CreatedRange *RangeQueryParams `form:"created"`
	Type         *string           `form:"type"`
	Types        []*string         `form:"types"`
}

// GetObjectValue returns the value from the e.Data.Object bag based on the keys hierarchy.
func (e *Event) GetObjectValue(keys ...string) string {
	return getValue(e.Data.Object, keys)
}

// GetPreviousValue returns the value from the e.Data.Prev bag based on the keys hierarchy.
func (e *Event) GetPreviousValue(keys ...string) string {
	return getValue(e.Data.PreviousAttributes, keys)
}

// UnmarshalJSON handles deserialization of the EventData.
// This custom unmarshaling exists so that we can keep both the map and raw data.
func (e *EventData) UnmarshalJSON(data []byte) error {
	type eventdata EventData
	var ee eventdata
	err := json.Unmarshal(data, &ee)
	if err != nil {
		return err
	}

	*e = EventData(ee)
	return json.Unmarshal(e.Raw, &e.Object)
}

// getValue returns the value from the m map based on the keys.
func getValue(m map[string]interface{}, keys []string) string {
	node := m[keys[0]]

	for i := 1; i < len(keys); i++ {
		key := keys[i]

		sliceNode, ok := node.([]interface{})
		if ok {
			intKey, err := strconv.Atoi(key)
			if err != nil {
				panic(fmt.Sprintf(
					"Cannot access nested slice element with non-integer key: %s",
					key))
			}
			node = sliceNode[intKey]
			continue
		}

		mapNode, ok := node.(map[string]interface{})
		if ok {
			node = mapNode[key]
			continue
		}

		panic(fmt.Sprintf(
			"Cannot descend into non-map non-slice object with key: %s", key))
	}

	if node == nil {
		return ""
	}

	return fmt.Sprintf("%v", node)
}
<commit_msg>Add support for the `delivery_success` param on the list event endpoint<commit_after>package stripe

import (
	"encoding/json"
	"fmt"
	"strconv"
)

// Event is the resource representing a Stripe event.
// For more details see https://stripe.com/docs/api#events.
type Event struct {
	Account         string        `json:"account"`
	Created         int64         `json:"created"`
	Data            *EventData    `json:"data"`
	ID              string        `json:"id"`
	Livemode        bool          `json:"livemode"`
	PendingWebhooks int64         `json:"pending_webhooks"`
	Request         *EventRequest `json:"request"`
	Type            string        `json:"type"`
}

// EventRequest contains information on a request that created an event.
type EventRequest struct {
	// ID is the request ID of the request that created an event, if the event
	// was created by a request.
	ID string `json:"id"`

	// IdempotencyKey is the idempotency key of the request that created an
	// event, if the event was created by a request and if an idempotency key
	// was specified for that request.
	IdempotencyKey string `json:"idempotency_key"`
}

// EventData is the unmarshalled object as a map.
type EventData struct {
	Object             map[string]interface{}
	PreviousAttributes map[string]interface{} `json:"previous_attributes"`
	Raw                json.RawMessage        `json:"object"`
}

// EventParams is the set of parameters that can be used when retrieving events.
// For more details see https://stripe.com/docs/api#retrieve_events.
type EventParams struct {
	Params `form:"*"`
}

// EventList is a list of events as retrieved from a list endpoint.
type EventList struct {
	ListMeta
	Data []*Event `json:"data"`
}

// EventListParams is the set of parameters that can be used when listing events.
// For more details see https://stripe.com/docs/api#list_events.
type EventListParams struct {
	ListParams      `form:"*"`
	Created         *int64            `form:"created"`
	CreatedRange    *RangeQueryParams `form:"created"`
	DeliverySuccess *bool             `form:"delivery_success"`
	Type            *string           `form:"type"`
	Types           []*string         `form:"types"`
}

// GetObjectValue returns the value from the e.Data.Object bag based on the keys hierarchy.
func (e *Event) GetObjectValue(keys ...string) string {
	return getValue(e.Data.Object, keys)
}

// GetPreviousValue returns the value from the e.Data.Prev bag based on the keys hierarchy.
func (e *Event) GetPreviousValue(keys ...string) string {
	return getValue(e.Data.PreviousAttributes, keys)
}

// UnmarshalJSON handles deserialization of the EventData.
// This custom unmarshaling exists so that we can keep both the map and raw data.
func (e *EventData) UnmarshalJSON(data []byte) error {
	type eventdata EventData
	var ee eventdata
	err := json.Unmarshal(data, &ee)
	if err != nil {
		return err
	}

	*e = EventData(ee)
	return json.Unmarshal(e.Raw, &e.Object)
}

// getValue returns the value from the m map based on the keys.
func getValue(m map[string]interface{}, keys []string) string {
	node := m[keys[0]]

	for i := 1; i < len(keys); i++ {
		key := keys[i]

		sliceNode, ok := node.([]interface{})
		if ok {
			intKey, err := strconv.Atoi(key)
			if err != nil {
				panic(fmt.Sprintf(
					"Cannot access nested slice element with non-integer key: %s",
					key))
			}
			node = sliceNode[intKey]
			continue
		}

		mapNode, ok := node.(map[string]interface{})
		if ok {
			node = mapNode[key]
			continue
		}

		panic(fmt.Sprintf(
			"Cannot descend into non-map non-slice object with key: %s", key))
	}

	if node == nil {
		return ""
	}

	return fmt.Sprintf("%v", node)
}
<|endoftext|>


<commit_before>package clw11

/*
#cgo windows linux LDFLAGS: -lOpenCL
#cgo darwin LDFLAGS: -framework OpenCL

#ifdef __APPLE__
#include "OpenCL/opencl.h"
#else
#include "CL/opencl.h"
#endif
*/
import "C"
import "unsafe"

type (
	Event                  C.cl_event
	EventInfo              C.cl_event_info
	CommandType            C.cl_command_type
	CommandExecutionStatus C.cl_int
)

const (
	EventCommandQueue           EventInfo = C.CL_EVENT_COMMAND_QUEUE
	EventCommandType            EventInfo = C.CL_EVENT_COMMAND_TYPE
	EventReferenceCount         EventInfo = C.CL_EVENT_REFERENCE_COUNT
	EventCommandExecutionStatus EventInfo = C.CL_EVENT_COMMAND_EXECUTION_STATUS
	EventContext                EventInfo = C.CL_EVENT_CONTEXT
)

const (
	CommandNdrangeKernel        CommandType = C.CL_COMMAND_NDRANGE_KERNEL
	CommandTask                 CommandType = C.CL_COMMAND_TASK
	CommandNativeKernel         CommandType = C.CL_COMMAND_NATIVE_KERNEL
	CommandReadBuffer           CommandType = C.CL_COMMAND_READ_BUFFER
	CommandWriteBuffer          CommandType = C.CL_COMMAND_WRITE_BUFFER
	CommandCopyBuffer           CommandType = C.CL_COMMAND_COPY_BUFFER
	CommandReadImage            CommandType = C.CL_COMMAND_READ_IMAGE
	CommandWriteImage           CommandType = C.CL_COMMAND_WRITE_IMAGE
	CommandCopyImage            CommandType = C.CL_COMMAND_COPY_IMAGE
	CommandCopyImageToBuffer    CommandType = C.CL_COMMAND_COPY_IMAGE_TO_BUFFER
	CommandCopyBufferToImage    CommandType = C.CL_COMMAND_COPY_BUFFER_TO_IMAGE
	CommandMapBuffer            CommandType = C.CL_COMMAND_MAP_BUFFER
	CommandMapImage             CommandType = C.CL_COMMAND_MAP_IMAGE
	CommandUnmapMemoryObject    CommandType = C.CL_COMMAND_UNMAP_MEM_OBJECT
	CommandMarker               CommandType = C.CL_COMMAND_MARKER
	CommandAcquireGlObjects     CommandType = C.CL_COMMAND_ACQUIRE_GL_OBJECTS
	CommandReleaseGlObjects     CommandType = C.CL_COMMAND_RELEASE_GL_OBJECTS
	CommandReadBufferRectangle  CommandType = C.CL_COMMAND_READ_BUFFER_RECT
	CommandWriteBufferRectangle CommandType = C.CL_COMMAND_WRITE_BUFFER_RECT
	CommandCopyBufferRectangle  CommandType = C.CL_COMMAND_COPY_BUFFER_RECT
	CommandUser                 CommandType = C.CL_COMMAND_USER
)

const (
	Complete  CommandExecutionStatus = C.CL_COMPLETE
	Running   CommandExecutionStatus = C.CL_RUNNING
	Submitted CommandExecutionStatus = C.CL_SUBMITTED
	Queued    CommandExecutionStatus = C.CL_QUEUED
)

func Flush(cq CommandQueue) error {
	return toError(C.clFlush(cq))
}

func Finish(cq CommandQueue) error {
	return toError(C.clFinish(cq))
}

func toCWaitList(wait_list []Event) (event_wait_list *C.cl_event, num_events_in_wait_list C.cl_uint) {
	if wait_list != nil {
		event_wait_list = (*C.cl_event)(&wait_list[0])
		num_events_in_wait_list = C.cl_uint(len(wait_list))
	}
	return
}

func CreateUserEvent(context Context) (Event, error) {
	var err C.cl_int
	result := C.clCreateUserEvent(context, &err)
	return Event(result), toError(err)
}

func GetEventInfo(event Event, paramName EventInfo, paramValueSize Size, paramValue unsafe.Pointer,
	paramValueSizeRet *Size) error {

	return toError(C.clGetEventInfo(event, C.cl_event_info(paramName), C.size_t(paramValueSize), paramValue,
		(*C.size_t)(paramValueSizeRet)))
}

func SetEventCallback(event Event, command_exec_callback_type CommandExecutionStatus,
	callback func(event Event, event_command_exec_status CommandExecutionStatus, user_data interface{}),
	user_data interface{}) error {

	return nil
}
<commit_msg>Added event profiling.<commit_after>package clw11

/*
#cgo windows linux LDFLAGS: -lOpenCL
#cgo darwin LDFLAGS: -framework OpenCL

#ifdef __APPLE__
#include "OpenCL/opencl.h"
#else
#include "CL/opencl.h"
#endif
*/
import "C"
import "unsafe"

type (
	Event                  C.cl_event
	EventInfo              C.cl_event_info
	ProfilingInfo          C.cl_profiling_info
	CommandType            C.cl_command_type
	CommandExecutionStatus C.cl_int
)

const (
	EventCommandQueue           EventInfo = C.CL_EVENT_COMMAND_QUEUE
	EventCommandType            EventInfo = C.CL_EVENT_COMMAND_TYPE
	EventReferenceCount         EventInfo = C.CL_EVENT_REFERENCE_COUNT
	EventCommandExecutionStatus EventInfo = C.CL_EVENT_COMMAND_EXECUTION_STATUS
	EventContext                EventInfo = C.CL_EVENT_CONTEXT
)

const (
	CommandNdrangeKernel        CommandType = C.CL_COMMAND_NDRANGE_KERNEL
	CommandTask                 CommandType = C.CL_COMMAND_TASK
	CommandNativeKernel         CommandType = C.CL_COMMAND_NATIVE_KERNEL
	CommandReadBuffer           CommandType = C.CL_COMMAND_READ_BUFFER
	CommandWriteBuffer          CommandType = C.CL_COMMAND_WRITE_BUFFER
	CommandCopyBuffer           CommandType = C.CL_COMMAND_COPY_BUFFER
	CommandReadImage            CommandType = C.CL_COMMAND_READ_IMAGE
	CommandWriteImage           CommandType = C.CL_COMMAND_WRITE_IMAGE
	CommandCopyImage            CommandType = C.CL_COMMAND_COPY_IMAGE
	CommandCopyImageToBuffer    CommandType = C.CL_COMMAND_COPY_IMAGE_TO_BUFFER
	CommandCopyBufferToImage    CommandType = C.CL_COMMAND_COPY_BUFFER_TO_IMAGE
	CommandMapBuffer            CommandType = C.CL_COMMAND_MAP_BUFFER
	CommandMapImage             CommandType = C.CL_COMMAND_MAP_IMAGE
	CommandUnmapMemoryObject    CommandType = C.CL_COMMAND_UNMAP_MEM_OBJECT
	CommandMarker               CommandType = C.CL_COMMAND_MARKER
	CommandAcquireGlObjects     CommandType = C.CL_COMMAND_ACQUIRE_GL_OBJECTS
	CommandReleaseGlObjects     CommandType = C.CL_COMMAND_RELEASE_GL_OBJECTS
	CommandReadBufferRectangle  CommandType = C.CL_COMMAND_READ_BUFFER_RECT
	CommandWriteBufferRectangle CommandType = C.CL_COMMAND_WRITE_BUFFER_RECT
	CommandCopyBufferRectangle  CommandType = C.CL_COMMAND_COPY_BUFFER_RECT
	CommandUser                 CommandType = C.CL_COMMAND_USER
)

const (
	Complete  CommandExecutionStatus = C.CL_COMPLETE
	Running   CommandExecutionStatus = C.CL_RUNNING
	Submitted CommandExecutionStatus = C.CL_SUBMITTED
	Queued    CommandExecutionStatus = C.CL_QUEUED
)

const (
	ProfilingCommandQueued ProfilingInfo = C.CL_PROFILING_COMMAND_QUEUED
	ProfilingCommandSubmit ProfilingInfo = C.CL_PROFILING_COMMAND_SUBMIT
	ProfilingCommandStart  ProfilingInfo = C.CL_PROFILING_COMMAND_START
	ProfilingCommandEnd    ProfilingInfo = C.CL_PROFILING_COMMAND_END
)

func Flush(cq CommandQueue) error {
	return toError(C.clFlush(cq))
}

func Finish(cq CommandQueue) error {
	return toError(C.clFinish(cq))
}

func toCWaitList(wait_list []Event) (event_wait_list *C.cl_event, num_events_in_wait_list C.cl_uint) {
	if wait_list != nil {
		event_wait_list = (*C.cl_event)(&wait_list[0])
		num_events_in_wait_list = C.cl_uint(len(wait_list))
	}
	return
}

func CreateUserEvent(context Context) (Event, error) {
	var err C.cl_int
	result := C.clCreateUserEvent(context, &err)
	return Event(result), toError(err)
}

func GetEventInfo(event Event, paramName EventInfo, paramValueSize Size, paramValue unsafe.Pointer,
	paramValueSizeRet *Size) error {

	return toError(C.clGetEventInfo(event, C.cl_event_info(paramName), C.size_t(paramValueSize), paramValue,
		(*C.size_t)(paramValueSizeRet)))
}

func GetEventProfilingInfo(event Event, paramName ProfilingInfo, paramValueSize Size, paramValue unsafe.Pointer,
	paramValueSizeRet *Size) error {

	return toError(C.clGetEventProfilingInfo(event, C.cl_profiling_info(paramName), C.size_t(paramValueSize),
		paramValue, (*C.size_t)(paramValueSizeRet)))
}

func SetEventCallback(event Event, command_exec_callback_type CommandExecutionStatus,
	callback func(event Event, event_command_exec_status CommandExecutionStatus, user_data interface{}),
	user_data interface{}) error {

	return nil
}
<|endoftext|>


<commit_before>package main

import irc "github.com/fluffle/goirc/client"
import "math/rand"
import "regexp"

const channelName = "#poc_beta_test"

// Guilhem Bot core
func handleMessageGuilhem(conn *irc.Conn, line *irc.Line) {
	technicalAnswers := []string{
		"Mais ! C'est de la merde !",
		"On doit le réecrire en GO ça !",
		"Mais c'est pas du tout ça le problème, en fait […]",
		"C'est fait roulé sous les aisselles",
		"I have no *FRAKING* idea!",
		"NAN ! Je suis en copie, je suis perché !",
		"je veux pas devenir un SPOF",
		"'Tain IRC ! Protocole de merde ! Je vais mettre en place un XM Peuh Peuh",
		"Non mais ça c'est soooo 2011 !",
		"Les mecs de chez […] ont rien compris, j'te fouterai tout le monde à la porte moi.",
	}

	personalAnswers := []string{
		"Mais j'suis pas super fort, j'suis mieux qu'ça même. J'suis surpuissant.",
		"Je parle fort… J'ai du charisme, c'est tout !",
		"Yves, Yves, YVES ! Laisse nous parler",
		"Yves, Yves, YVES ! Après le daily stp !",
		"J'ai un super nom pour le deuxième DC ! WATTOO WATTOO",
		"Attends, y'a mon nom sur un t-shirt s'il-te-plaît !",
		"J'me vois pas me priver de bonheur parce que les autres veulent une vie de merde",
		"«Vous ne pouvez *résoudre* un problème avec le *même* type de *pensée* qui a créé le problème» A.Einstein",
		"Il faut que je me sente… Important",
		"Oula oui, au moins ça !",
		"«rm -Rf de-toute-l-équipe», oui !",
	}

	openstackRegexp, _ := regexp.Compile("jarvis|openstack|keystone|deploy|datacenter|bug|meeting|horizon|glance|cinder|contrail|coreos|dc|nova|neutron")
	technicalPoint := openstackRegexp.FindString(line.Text())
	randomLine := rand.Intn(30)

	if technicalPoint != "" {
		conn.Privmsg(
			channelName,
			technicalAnswers[rand.Intn(len(technicalAnswers))],
		)
	} else if randomLine < 3 {
		conn.Privmsg(
			channelName,
			personalAnswers[rand.Intn(len(personalAnswers))],
		)
	}
}

func main() {
	// Gentux (for concurency tests)
	//go connect(channelName, "GentuxBot", handleMessageGuilhem)
	// Guilhem
	connect(channelName, "GuilhemBot", handleMessageGuilhem)
}
<commit_msg>Added ygbot<commit_after>package main

import irc "github.com/fluffle/goirc/client"
import "math/rand"
import "regexp"

const channelName = "#poc_beta_test"

// Guilhem Bot core
func handleMessageGuilhem(conn *irc.Conn, line *irc.Line) {
	technicalAnswers := []string{
		"Mais ! C'est de la merde !",
		"On doit le réecrire en GO ça !",
		"Mais c'est pas du tout ça le problème, en fait […]",
		"C'est fait roulé sous les aisselles",
		"I have no *FRAKING* idea!",
		"NAN ! Je suis en copie, je suis perché !",
		"je veux pas devenir un SPOF",
		"'Tain IRC ! Protocole de merde ! Je vais mettre en place un XM Peuh Peuh",
		"Non mais ça c'est soooo 2011 !",
		"Les mecs de chez […] ont rien compris, j'te fouterai tout le monde à la porte moi.",
	}

	personalAnswers := []string{
		"Mais j'suis pas super fort, j'suis mieux qu'ça même. J'suis surpuissant.",
		"Je parle fort… J'ai du charisme, c'est tout !",
		"Yves, Yves, YVES ! Laisse nous parler",
		"Yves, Yves, YVES ! Après le daily stp !",
		"J'ai un super nom pour le deuxième DC ! WATTOO WATTOO",
		"Attends, y'a mon nom sur un t-shirt s'il-te-plaît !",
		"J'me vois pas me priver de bonheur parce que les autres veulent une vie de merde",
		"«Vous ne pouvez *résoudre* un problème avec le *même* type de *pensée* qui a créé le problème» A.Einstein",
		"Il faut que je me sente… Important",
		"Oula oui, au moins ça !",
		"«rm -Rf de-toute-l-équipe», oui !",
	}

	openstackRegexp, _ := regexp.Compile("jarvis|openstack|keystone|deploy|datacenter|bug|meeting|horizon|glance|cinder|contrail|coreos|dc|nova|neutron")
	technicalPoint := openstackRegexp.FindString(line.Text())
	randomLine := rand.Intn(30)

	if technicalPoint != "" {
		conn.Privmsg(
			channelName,
			technicalAnswers[rand.Intn(len(technicalAnswers))],
		)
	} else if randomLine < 3 {
		conn.Privmsg(
			channelName,
			personalAnswers[rand.Intn(len(personalAnswers))],
		)
	}
}

// ygbo Bot core
func handleMessageYgbot(conn *irc.Conn, line *irc.Line) {
	technicalAnswers := []string{
		"Ça a été codé avec le cul!",
		"C'est fait par un mec qu'a le QI d'un annus artificiel!",
		"J'y crois pas! jamais vu une horreur pareille!",
	}

	personalAnswers := []string{
		"Hein?",
		"Hein?",
		"Hein?",
		"Tu disait?",
	}

	personalAnswersFix := []string{
		"",
		"",
		"",
		"s/disait/disias/",
	}

	personalAnswersFixFix := []string{
		"",
		"",
		"",
		"t'ain d'clavire!",
	}

	openstackRegexp, _ := regexp.Compile("openstack|réseau|network|bug")
	technicalPoint := openstackRegexp.FindString(line.Text())
	randomLine := rand.Intn(30)

	if technicalPoint != "" {
		randomAnswer := rand.Intn(len(technicalAnswers))
		conn.Privmsg(
			channelName,
			technicalAnswers[randomAnswer],
		)
	} else if randomLine < 3 {
		randomAnswer := rand.Intn(len(personalAnswers))
		conn.Privmsg(
			channelName,
			personalAnswers[randomAnswer],
		)
		if personalAnswersFix[randomAnswer] != "" {
			conn.Privmsg(
				channelName,
				personalAnswersFix[randomAnswer],
			)
			if personalAnswersFixFix[randomAnswer] != "" {
				conn.Privmsg(
					channelName,
					personalAnswersFixFix[randomAnswer],
				)
			}
		}
	}
}

func main() {
	// Gentux (for concurency tests)
	//go connect(channelName, "GentuxBot", handleMessageGuilhem)
	// Guilhem
	connect(channelName, "GuilhemBot", handleMessageGuilhem)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	vlc "github.com/kestein/go-vlc"
	"html/template"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
)

const videoPath string = "/home/kestein/Videos"
const referer string = "Referer"
const secToMilli int64 = 1000
const pageStart string = `

`
const content string = `
			{{block "links" .}}
				{{range .}}

{{.Filename}}

				{{end}}
			{{end}}
`
const pageEnd string = `

`
const playerPage string = `

		<button id="playback">Pause</button>
		<button id="stop">Stop</button>
		<button id="rewind">Back 10 seconds</button>
		<input type="range" id="volume" min="0" max="100" step="1" value="{{.vol}}">
		<input type="range" id="seek" min="0" max="{{.secs}}" step="1" value="0">
		<button id="timestamp">Timestamp</button>

`

type videoLine struct {
	Action, Url, Filename string
}

type cartoon struct {
	inst    *vlc.Instance
	player  *vlc.Player
	playing bool
}

type videoLineList []videoLine

func (a videoLineList) Len() int           { return len(a) }
func (a videoLineList) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a videoLineList) Less(i, j int) bool { return a[i].Url = len(videoPath) {
		if fullPath[0:len(videoPath)] != videoPath {
			http.Error(w, "Not in the video path", http.StatusUnauthorized)
		}
	}
	dir, err := os.Open(fullPath)
	if err != nil {
		log.Fatal("Unable to open video path %s", err)
	}
	files, err := dir.Readdir(0)
	if err != nil {
		log.Fatal("Unable to read dir %s", err)
	}
	// Write the HTML. Sort out by directories and files
	subDirs := []videoLine{}
	orphanFiles := []videoLine{}
	for i := 0; i < len(files); i++ {
		// For printing
		fileName := files[i].Name()
		// For RESTing
		vidURL := ""
		if len(req.URL.String()) > 0 {
			vidURL = fmt.Sprintf("%s/%s", req.URL.String(), url.QueryEscape(fileName))
		} else {
			vidURL = fmt.Sprintf("%s", url.QueryEscape(fileName))
		}
		if files[i].IsDir() {
			url := videoLine{"list", vidURL, fileName}
			subDirs = append(subDirs, url)
		} else {
			url := videoLine{"play", vidURL, fileName}
			orphanFiles = append(orphanFiles, url)
		}
	}
	// Write HTML to the reponse
	sort.Sort(videoLineList(subDirs))
	// Make the '..' directory at the top
	prev := strings.Split(req.URL.String(), "/")
	back := ""
	if len(prev) > 1 {
		back = strings.Join(prev[:len(prev)-1], "/")
	}
	previousLink := []videoLine{videoLine{"list", back, ".."}}
	subDirs = append(previousLink, subDirs...)
	sort.Sort(videoLineList(orphanFiles))
	// Write the HTML
	io.WriteString(w, pageStart)
	t := template.Must(template.New("content").Parse(content))
	err = t.Execute(w, subDirs)
	if err != nil {
		panic(err)
	}
	err = t.Execute(w, orphanFiles)
	if err != nil {
		panic(err)
	}
	io.WriteString(w, pageEnd)
}

func play(state *cartoon, w http.ResponseWriter, req *http.Request) {
	var media *vlc.Media
	// var evt *vlc.EventManager
	var err error

	// Obtain the name of the video to view
	rawVideo := req.RequestURI[6:] // Take out the '/play'
	video, err := url.QueryUnescape(rawVideo)
	if err != nil {
		fmt.Println("WRONG")
		return
	}
	// Make VLC instance
	if state.inst, err = vlc.New([]string{}); err != nil {
		fmt.Println(err)
		return
	}
	// Open the video file
	if media, err = state.inst.OpenMediaFile(fmt.Sprintf("%s/%s", videoPath, video)); err != nil {
		fmt.Println(err)
		return
	}
	// Create the media player
	if state.player, err = media.NewPlayer(); err != nil {
		fmt.Println(err)
		return
	}
	// Initialize player state
	state.player.SetVolume(25)
	//state.player.SetFullscreen(true)
	// Do not need media anymore since player now owns it
	media.Release()
	media = nil

	// Make the page to control the video
	state.player.Play()
	// Wait for the player to start playing
	for {
		t, err := state.player.Length()
		if err != nil {
			panic(err)
		}
		if t > 0 {
			break
		}
	}
	vidLen, err := state.player.Length()
	vidLen = vidLen / secToMilli
	state.playing = true
	t := template.Must(template.New("player").Parse(playerPage))
	vals := map[string]int64{
		"vol":  25,
		"secs": vidLen,
	}
	t.Execute(w, vals)
	//io.WriteString(w, playerPage)
}

func stop(state *cartoon, w http.ResponseWriter, req *http.Request) {
	if state.player == nil {
		return
	}
	state.player.Stop()
	state.playing = false
	closePlayer(state)
}

func closePlayer(state *cartoon) {
	if state.player == nil {
		return
	}
	state.player.Release()
	state.inst.Release()
	state.player = nil
	state.inst = nil
}

func pausePlay(state *cartoon) {
	if state.player == nil {
		return
	}
	state.player.TogglePause(state.playing)
	state.playing = !state.playing
}

func rewind(state *cartoon) {
	if state.player == nil {
		return
	}
	var secsRewound int64 = 10
	curTime, err := state.player.Time()
	if err != nil {
		panic(err)
	}
	rTime := curTime - (secsRewound * secToMilli)
	if rTime < 0 {
		state.player.SetTime(0)
	} else {
		state.player.SetTime(rTime)
	}
}

func setVolume(state *cartoon, toVol int) {
	if state.player == nil {
		return
	}
	state.player.SetVolume(toVol)
}

func setTime(state *cartoon, seek int64) {
	if state.player == nil {
		return
	}
	state.player.SetTime(seek * secToMilli)
}

func main() {
	port := flag.String("p", "8100", "port to serve on")
	directory := flag.String("d", ".", "the directory of static file to host")
	flag.Parse()

	state := cartoon{
		inst:    nil,
		player:  nil,
		playing: false,
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "list", 301)
	})
	http.Handle("/list/", http.StripPrefix("/list/", http.HandlerFunc(list)))
	http.Handle("/play/", http.StripPrefix("/play/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			play(&state, w, req)
		})))
	http.Handle("/playback/", http.StripPrefix("/playback/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			pausePlay(&state)
		})))
	http.Handle("/rewind/", http.StripPrefix("/rewind/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			rewind(&state)
		})))
	http.Handle("/stop/", http.StripPrefix("/stop/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			stop(&state, w, req)
		})))
	// If this API endpoint is called "seek" it breaks if you try to seek to 0.
	// WTF
	http.Handle("/time/", http.StripPrefix("/time/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			seekPos, err := strconv.ParseInt(req.URL.String(), 10, 64)
			if err != nil {
				fmt.Println("NaN")
				return
			}
			setTime(&state, seekPos)
		})))
	http.Handle("/volume/", http.StripPrefix("/volume/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			toVol, err := strconv.ParseInt(req.URL.String(), 10, 64)
			if err != nil {
				fmt.Println("NaN")
				return
			}
			setVolume(&state, int(toVol))
		})))
	http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {})

	log.Printf("Serving %s on HTTP port: %s\n", *directory, *port)
	log.Fatal(http.ListenAndServe("localhost:"+*port, nil))
}
<commit_msg>Write timestamps to page<commit_after>package main

import (
	"flag"
	"fmt"
	vlc "github.com/kestein/go-vlc"
	"html/template"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
)

const videoPath string = "/home/kestein/Videos"
const referer string = "Referer"
const secToMilli int64 = 1000
const pageStart string = `

`
const content string = `
			{{block "links" .}}
				{{range .}}

{{.Filename}}

				{{end}}
			{{end}}
`
const pageEnd string = `

`
const playerPage string = `

		<button id="playback">Pause</button>
		<button id="stop">Stop</button>
		<button id="rewind">Back 10 seconds</button>
		<input type="range" id="volume" min="0" max="100" step="1" value="{{.vol}}">
		<input type="range" id="seek" min="0" max="{{.secs}}" step="1" value="0">
		<button id="timestamp">Timestamp</button>

`

type videoLine struct {
	Action, Url, Filename string
}

type cartoon struct {
	inst    *vlc.Instance
	player  *vlc.Player
	playing bool
}

type videoLineList []videoLine

func (a videoLineList) Len() int           { return len(a) }
func (a videoLineList) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a videoLineList) Less(i, j int) bool { return a[i].Url = len(videoPath) {
		if fullPath[0:len(videoPath)] != videoPath {
			http.Error(w, "Not in the video path", http.StatusUnauthorized)
		}
	}
	dir, err := os.Open(fullPath)
	if err != nil {
		log.Fatal("Unable to open video path %s", err)
	}
	files, err := dir.Readdir(0)
	if err != nil {
		log.Fatal("Unable to read dir %s", err)
	}
	// Write the HTML. Sort out by directories and files
	subDirs := []videoLine{}
	orphanFiles := []videoLine{}
	for i := 0; i < len(files); i++ {
		// For printing
		fileName := files[i].Name()
		// For RESTing
		vidURL := ""
		if len(req.URL.String()) > 0 {
			vidURL = fmt.Sprintf("%s/%s", req.URL.String(), url.QueryEscape(fileName))
		} else {
			vidURL = fmt.Sprintf("%s", url.QueryEscape(fileName))
		}
		if files[i].IsDir() {
			url := videoLine{"list", vidURL, fileName}
			subDirs = append(subDirs, url)
		} else {
			url := videoLine{"play", vidURL, fileName}
			orphanFiles = append(orphanFiles, url)
		}
	}
	// Write HTML to the reponse
	sort.Sort(videoLineList(subDirs))
	// Make the '..' directory at the top
	prev := strings.Split(req.URL.String(), "/")
	back := ""
	if len(prev) > 1 {
		back = strings.Join(prev[:len(prev)-1], "/")
	}
	previousLink := []videoLine{videoLine{"list", back, ".."}}
	subDirs = append(previousLink, subDirs...)
	sort.Sort(videoLineList(orphanFiles))
	// Write the HTML
	io.WriteString(w, pageStart)
	t := template.Must(template.New("content").Parse(content))
	err = t.Execute(w, subDirs)
	if err != nil {
		panic(err)
	}
	err = t.Execute(w, orphanFiles)
	if err != nil {
		panic(err)
	}
	io.WriteString(w, pageEnd)
}

func play(state *cartoon, w http.ResponseWriter, req *http.Request) {
	var media *vlc.Media
	// var evt *vlc.EventManager
	var err error

	// Obtain the name of the video to view
	rawVideo := req.RequestURI[6:] // Take out the '/play'
	video, err := url.QueryUnescape(rawVideo)
	if err != nil {
		fmt.Println("WRONG")
		return
	}
	// Make VLC instance
	if state.inst, err = vlc.New([]string{}); err != nil {
		fmt.Println(err)
		return
	}
	// Open the video file
	if media, err = state.inst.OpenMediaFile(fmt.Sprintf("%s/%s", videoPath, video)); err != nil {
		fmt.Println(err)
		return
	}
	// Create the media player
	if state.player, err = media.NewPlayer(); err != nil {
		fmt.Println(err)
		return
	}
	// Initialize player state
	state.player.SetVolume(25)
	//state.player.SetFullscreen(true)
	// Do not need media anymore since player now owns it
	media.Release()
	media = nil

	// Make the page to control the video
	state.player.Play()
	// Wait for the player to start playing
	for {
		t, err := state.player.Length()
		if err != nil {
			panic(err)
		}
		if t > 0 {
			break
		}
	}
	vidLen, err := state.player.Length()
	vidLen = vidLen / secToMilli
	state.playing = true
	t := template.Must(template.New("player").Parse(playerPage))
	vals := map[string]int64{
		"vol":  25,
		"secs": vidLen,
	}
	t.Execute(w, vals)
	//io.WriteString(w, playerPage)
}

func stop(state *cartoon, w http.ResponseWriter, req *http.Request) {
	if state.player == nil {
		return
	}
	state.player.Stop()
	state.playing = false
	closePlayer(state)
}

func closePlayer(state *cartoon) {
	if state.player == nil {
		return
	}
	state.player.Release()
	state.inst.Release()
	state.player = nil
	state.inst = nil
}

func pausePlay(state *cartoon) {
	if state.player == nil {
		return
	}
	state.player.TogglePause(state.playing)
	state.playing = !state.playing
}

func rewind(state *cartoon) {
	if state.player == nil {
		return
	}
	var secsRewound int64 = 10
	curTime, err := state.player.Time()
	if err != nil {
		panic(err)
	}
	rTime := curTime - (secsRewound * secToMilli)
	if rTime < 0 {
		state.player.SetTime(0)
	} else {
		state.player.SetTime(rTime)
	}
}

func setVolume(state *cartoon, toVol int) {
	if state.player == nil {
		return
	}
	state.player.SetVolume(toVol)
}

func setTime(state *cartoon, seek int64) {
	if state.player == nil {
		return
	}
	state.player.SetTime(seek * secToMilli)
}

func main() {
	port := flag.String("p", "8100", "port to serve on")
	directory := flag.String("d", ".", "the directory of static file to host")
	flag.Parse()

	state := cartoon{
		inst:    nil,
		player:  nil,
		playing: false,
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "list", 301)
	})
	http.Handle("/list/", http.StripPrefix("/list/", http.HandlerFunc(list)))
	http.Handle("/play/", http.StripPrefix("/play/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			play(&state, w, req)
		})))
	http.Handle("/playback/", http.StripPrefix("/playback/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			pausePlay(&state)
		})))
	http.Handle("/rewind/", http.StripPrefix("/rewind/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			rewind(&state)
		})))
	http.Handle("/stop/", http.StripPrefix("/stop/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			stop(&state, w, req)
		})))
	// If this API endpoint is called "seek" it breaks if you try to seek to 0.
	// WTF
	http.Handle("/time/", http.StripPrefix("/time/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			seekPos, err := strconv.ParseInt(req.URL.String(), 10, 64)
			if err != nil {
				fmt.Println("NaN")
				return
			}
			setTime(&state, seekPos)
		})))
	http.Handle("/volume/", http.StripPrefix("/volume/",
		http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			toVol, err := strconv.ParseInt(req.URL.String(), 10, 64)
			if err != nil {
				fmt.Println("NaN")
				return
			}
			setVolume(&state, int(toVol))
		})))
	http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {})

	log.Printf("Serving %s on HTTP port: %s\n", *directory, *port)
	log.Fatal(http.ListenAndServe("localhost:"+*port, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
	"log"
	"sync"
	"os"
	"runtime/pprof"
	"math"

	"golang.org/x/time/rate"
	"github.com/valyala/fasthttp"
	"github.com/hagen1778/fasthttploader/metrics"
	"github.com/hagen1778/fasthttploader/pushgateway"
	"github.com/hagen1778/fasthttploader/report"
)

const (
	// Duration of burst-testing, without qps-limit. Used to estimate start test conditions
	calibrateDuration = 10 * time.Second

	// Duration of adjustable testing, while trying to reach max qps with minimal lvl of errors
	adjustmentDuration = 40 * time.Second

	// Period of sample taking, while testing
	samplePeriod = 500 * time.Millisecond
)

type Loader struct {
	// Request is the request to be made.
	Request *fasthttp.Request

	// Qps is the rate limit.
	Qps rate.Limit

	// C is number of workers (clients)
	C int

	// Duration is the duration of test running.
	Duration time.Duration

	er uint64
	t time.Time
	throttle *rate.Limiter

	sync.Mutex
}

func (l *Loader) startProgress() {
	l.t = time.Now()
	fmt.Println("Loading start!")
}

type prevState struct {
	// Qps is the rate limit.
	qps rate.Limit

	// Number of workers
	workers int

	// True if there was any errors while testing
	flawed bool
}

var (
	prev *prevState
	stopCh = make(chan struct{})

	c *metrics.Client
	r *report.Page
)

func (l *Loader) Run() {
	prev = &prevState{}
	r = &report.Page{
		Title: string(l.Request.URI().Host()),
		RequestDuration: make(map[float64][]float64),
		Interval: samplePeriod.Seconds(),
	}
	c = metrics.Init(l.Request, *t)
	pushgateway.Init()
	l.throttle = rate.NewLimiter(1, 1)

	if l.Qps == 0 {
		l.makeAdjustment()
	} else {
		prev.qps = l.Qps
		prev.workers = l.C
	}
	l.makeTest()
	l.makeReport()

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}
}

func (l *Loader) makeAdjustment() {
	l.calibrateQPS()

	go func(){
		l.startProgress()
		timeout := time.After(adjustmentDuration)
		tick := time.Tick(samplePeriod)
		for {
			select {
			case <-timeout:
				stopCh <- struct{}{}
				return
			case <-tick:
				l.calibrate()
			}
		}
	}()

	if prev.flawed {
		c.AddWorkers(prev.workers/2)
		l.setQPS(prev.qps/2)
	} else {
		c.AddWorkers(prev.workers)
		l.setQPS(prev.qps)
	}

	multiplier = 0.1
	l.load()

	fmt.Println("Adjustment Finished!")
}

func (l *Loader) calibrateQPS() {
	fmt.Println("Run initial callibrate QPS phase")
	timeout := time.After(calibrateDuration)
	c.AddWorkers(*cl)
	for {
		select {
		case <-timeout:
			prev.flawed = (metrics.Errors()/metrics.RequestSum())*100 > 2 // just more than 3% of errors
			prev.qps = rate.Limit(float64(metrics.RequestSum())/calibrateDuration.Seconds())
			prev.workers = c.Amount()
			fmt.Printf("Average QPS for %d workers is: %f; Errs: %d; Req done: %d\n", c.Amount(), prev.qps, metrics.Errors(), metrics.RequestSum())
			c.Flush()
			return
		default:
			c.Jobsch <- struct{}{}
		}
	}
}

func (l *Loader) makeTest() {
	s := time.Duration(l.Duration.Seconds()/2/10)
	stepTick := time.Tick(time.Second * s) // half of the time, 10 steps in first half
	stateTick := time.Tick(samplePeriod)
	workerStep := prev.workers
	qpsStep := prev.qps
	l.setQPS(qpsStep)
	c.AddWorkers(workerStep)
	fmt.Printf("Start test with - qps: %f; connections: %d\n", qpsStep, workerStep)
	go func(){
		l.startProgress()
		timeout := time.After(l.Duration)
		steps := 0
		for {
			select {
			case <-timeout:
				stopCh <- struct{}{}
				return
			case <-stepTick:
				if steps >= 10-1 {
					continue
				}
				//l.setQPS(l.Qps + qpsStep)
				//c.AddWorkers(workerStep)
				steps++
			case <-stateTick:
				l.printState()

			//if err := pushgateway.Push(c.Metrics()); err != nil {
			//	fmt.Printf("%s\n", err)
			//}
			}
		}
	}()
	l.load()
}

var multiplier float64
var await = 0
func (l *Loader) calibrate(){
	l.printState()
	if await > 0 {
		await -=1
		return
	}

	if math.Abs(multiplier) < 0.0001 {
		fmt.Println("Multiplier is negligible now. Stoping adjustment")
		stopCh <- struct{}{}
		return
	}
	if !l.isFlawed() {
		if len(c.Jobsch) > 0 {
			n := int(float64(c.Amount()) * multiplier)
			c.AddWorkers(n)
			await += 1
		} else {
			l.adjustQPS()
			await += 1
		}
	} else {
		multiplier /= 1.2
		await += 3
	}
}

func (l *Loader) printState() {
	if *debug {
		since := time.Since(l.t).Seconds()
		fmt.Println("------------")
		fmt.Printf("[ Multiplier = %f ]\n", multiplier)
		fmt.Printf("QPS was increased to: %f\nWorkers: %d\nJobsch len: %d\n", l.Qps, c.Amount(), len(c.Jobsch))
		fmt.Printf(" >> Num of cons: %d; Req done: %d; Errors: %d; Timeouts: %d\n", metrics.ConnOpen(), metrics.RequestSum(), metrics.Errors(), metrics.Timeouts())
		fmt.Printf(" >> Real Req/s: %f; Transfer/s: %f kb;\n", float64(metrics.RequestSum())/since, float64(metrics.BytesWritten())/(since*1024))
		fmt.Println("------------")
	}

	r.Lock()
	r.Connections = append(r.Connections, metrics.ConnOpen())
	r.Errors = append(r.Errors, metrics.Errors())
	r.Timeouts = append(r.Timeouts, metrics.Timeouts())
	r.RequestSum = append(r.RequestSum, metrics.RequestSum())
	r.RequestSuccess = append(r.RequestSuccess, metrics.RequestSuccess())
	r.BytesWritten = append(r.BytesWritten, metrics.BytesWritten())
	r.BytesRead = append(r.BytesRead, metrics.BytesRead())
	r.Qps = append(r.Qps, uint64(l.Qps))
	r.UpdateRequestDuration(metrics.RequestDuration())
	r.Unlock()
}

func (l *Loader) adjustQPS() {
	l.setQPS(l.Qps * rate.Limit(1+multiplier))
}

func (l *Loader) setQPS(qps rate.Limit) {
	l.Qps = qps
	l.throttle.SetLimit(qps)
}

func (l *Loader) isFlawed() bool {
	if metrics.Errors() > 0 && l.er != metrics.Errors() {
		l.er = metrics.Errors()
		return true
	}

	return false
}

func (l *Loader) load() {
	for {
		select {
		case <-stopCh:
			prev.qps = l.Qps
			prev.workers = c.Amount()
			c.Flush()
			fmt.Println("Loading done. Data flushed")
			return
		default:
			if l.throttle.Allow(){
				c.Jobsch <- struct{}{}
			}
		}
	}
}

func (l *Loader) makeReport() {
	f, err := os.Create(*fileName)
	if err != nil {
		log.Fatalf("Error while trying to create file: %s", err)
	}
	defer f.Close()

	f.WriteString(report.PrintPage(r))
	fmt.Printf("Check test results at %s\n", *fileName)
}<commit_msg>add summary printing<commit_after>package main

import (
	"fmt"
	"time"
	"log"
	"sync"
	"os"
	"runtime/pprof"
	"math"

	"golang.org/x/time/rate"
	"github.com/valyala/fasthttp"
	"github.com/hagen1778/fasthttploader/metrics"
	"github.com/hagen1778/fasthttploader/pushgateway"
	"github.com/hagen1778/fasthttploader/report"
)

const (
	// Duration of burst-testing, without qps-limit. Used to estimate start test conditions
	calibrateDuration = 10 * time.Second

	// Duration of adjustable testing, while trying to reach max qps with minimal lvl of errors
	adjustmentDuration = 40 * time.Second

	// Period of sample taking, while testing
	samplePeriod = 1000 * time.Millisecond
)

type Loader struct {
	// Request is the request to be made.
	Request *fasthttp.Request

	// Qps is the rate limit.
	Qps rate.Limit

	// C is number of workers (clients)
	C int

	// Duration is the duration of test running.
	Duration time.Duration

	er uint64
	t time.Time
	throttle *rate.Limiter

	sync.Mutex
}

func (l *Loader) startProgress() {
	l.t = time.Now()
	fmt.Println("Loading start!")
}

type prevState struct {
	// Qps is the rate limit.
	qps rate.Limit

	// Number of workers
	workers int

	// True if there was any errors while testing
	flawed bool
}

var (
	testTime time.Time
	prev *prevState
	stopCh = make(chan struct{})

	c *metrics.Client
	r *report.Page
)

func (l *Loader) Run() {
	testTime = time.Now()
	prev = &prevState{}
	r = &report.Page{
		Title: string(l.Request.URI().Host()),
		RequestDuration: make(map[float64][]float64),
		Interval: samplePeriod.Seconds(),
	}
	c = metrics.Init(l.Request, *t)
	pushgateway.Init()
	l.throttle = rate.NewLimiter(1, 1)

	if l.Qps == 0 {
		l.makeAdjustment()
	} else {
		prev.qps = l.Qps
		prev.workers = l.C
	}
	l.makeTest()
	l.makeReport()

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}
}

func (l *Loader) makeAdjustment() {
	l.calibrateQPS()

	go func(){
		l.startProgress()
		timeout := time.After(adjustmentDuration)
		tick := time.Tick(samplePeriod)
		for {
			select {
			case <-timeout:
				stopCh <- struct{}{}
				printSummary("Adjustment test")
				return
			case <-tick:
				l.calibrate()
			}
		}
	}()

	if prev.flawed {
		c.AddWorkers(prev.workers/2)
		l.setQPS(prev.qps/2)
	} else {
		c.AddWorkers(prev.workers)
		l.setQPS(prev.qps)
	}

	multiplier = 0.1
	l.load()

	fmt.Println("Adjustment Finished!")
}

func (l *Loader) calibrateQPS() {
	fmt.Println("Run initial callibrate QPS phase")
	timeout := time.After(calibrateDuration)
	c.AddWorkers(*cl)
	for {
		select {
		case <-timeout:
			prev.flawed = (metrics.Errors()/metrics.RequestSum())*100 > 2 // just more than 3% of errors
			prev.qps = rate.Limit(float64(metrics.RequestSum())/calibrateDuration.Seconds())
			prev.workers = c.Amount()
			fmt.Printf("Average QPS for %d workers is: %f; Errs: %d; Req done: %d\n", c.Amount(), prev.qps, metrics.Errors(), metrics.RequestSum())
			c.Flush()
			return
		default:
			c.Jobsch <- struct{}{}
		}
	}
}

func (l *Loader) makeTest() {
	s := time.Duration(l.Duration.Seconds()/2/10)
	stepTick := time.Tick(time.Second * s) // half of the time, 10 steps in first half
	stateTick := time.Tick(samplePeriod)
	workerStep := prev.workers/10
	qpsStep := prev.qps/10
	l.setQPS(qpsStep)
	c.AddWorkers(workerStep)
	fmt.Printf("Start test with - qps: %f; connections: %d\n", qpsStep, workerStep)
	go func(){
		l.startProgress()
		timeout := time.After(l.Duration)
		steps := 0
		for {
			select {
			case <-timeout:
				stopCh <- struct{}{}
				printSummary("Loading test")
				return
			case <-stepTick:
				if steps >= 10-1 {
					continue
				}
				l.setQPS(l.Qps + qpsStep)
				c.AddWorkers(workerStep)
				steps++
			case <-stateTick:
				l.printState()

			//if err := pushgateway.Push(c.Metrics()); err != nil {
			//	fmt.Printf("%s\n", err)
			//}
			}
		}
	}()
	l.load()
}

var multiplier float64
var await = 0
func (l *Loader) calibrate(){
	l.printState()
	if await > 0 {
		await -=1
		return
	}

	if math.Abs(multiplier) < 0.0001 {
		fmt.Println("Multiplier is negligible now. Stoping adjustment")
		stopCh <- struct{}{}
		return
	}
	if !l.isFlawed() {
		if len(c.Jobsch) > 0 {
			n := int(float64(c.Amount()) * multiplier)
			c.AddWorkers(n)
			await += 1
		} else {
			l.adjustQPS()
			await += 1
		}
	} else {
		multiplier /= 1.2
		await += 3
	}
}

func (l *Loader) printState() {
	if *debug {
		since := time.Since(l.t).Seconds()
		fmt.Println("------------")
		fmt.Printf("[ Multiplier = %f ]\n", multiplier)
		fmt.Printf("QPS was increased to: %f\nWorkers: %d\nJobsch len: %d\n", l.Qps, c.Amount(), len(c.Jobsch))
		fmt.Printf(" >> Num of cons: %d; Req done: %d; Errors: %d; Timeouts: %d\n", metrics.ConnOpen(), metrics.RequestSum(), metrics.Errors(), metrics.Timeouts())
		fmt.Printf(" >> Real Req/s: %f; Transfer/s: %f kb;\n", float64(metrics.RequestSum())/since, float64(metrics.BytesWritten())/(since*1024))
		fmt.Println("------------")
	}

	r.Lock()
	r.Connections = append(r.Connections, metrics.ConnOpen())
	r.Errors = append(r.Errors, metrics.Errors())
	r.Timeouts = append(r.Timeouts, metrics.Timeouts())
	r.RequestSum = append(r.RequestSum, metrics.RequestSum())
	r.RequestSuccess = append(r.RequestSuccess, metrics.RequestSuccess())
	r.BytesWritten = append(r.BytesWritten, metrics.BytesWritten())
	r.BytesRead = append(r.BytesRead, metrics.BytesRead())
	r.Qps = append(r.Qps, uint64(l.Qps))
	r.UpdateRequestDuration(metrics.RequestDuration())
	r.Unlock()
}

func (l *Loader) adjustQPS() {
	l.setQPS(l.Qps * rate.Limit(1+multiplier))
}

func (l *Loader) setQPS(qps rate.Limit) {
	l.Qps = qps
	l.throttle.SetLimit(qps)
}

func (l *Loader) isFlawed() bool {
	if metrics.Errors() > 0 && l.er != metrics.Errors() {
		l.er = metrics.Errors()
		return true
	}

	return false
}

func (l *Loader) load() {
	for {
		select {
		case <-stopCh:
			prev.qps = l.Qps
			prev.workers = c.Amount()
			c.Flush()
			fmt.Println("Loading done. Data flushed")
			return
		default:
			if l.throttle.Allow(){
				c.Jobsch <- struct{}{}
			}
		}
	}
}

func (l *Loader) makeReport() {
	f, err := os.Create(*fileName)
	if err != nil {
		log.Fatalf("Error while trying to create file: %s", err)
	}
	defer f.Close()

	f.WriteString(report.PrintPage(r))
	fmt.Printf("Check test results at %s\n", *fileName)
}

func printSummary(stage string) {
	since := time.Since(testTime).Seconds()
	fmt.Printf("\n------ %s ------\n", stage)
	fmt.Printf("Elapsed time: %fs\n", since)
	fmt.Printf("Req done: %d; Success: %f %%\n", metrics.RequestSum(), (float64(metrics.RequestSuccess())/float64(metrics.RequestSum()))*100)
	fmt.Printf("Rps: %f; Connections: %d\n", float64(metrics.RequestSum())/since, metrics.ConnOpen())
	fmt.Printf("Errors: %d; Timeouts: %d\n\n", metrics.Errors(), metrics.Timeouts())
	testTime = time.Now()
}
<|endoftext|>


<commit_before>// Package goawk is an implementation of AWK written in Go.
//
// You can use the command-line "goawk" command or run AWK from your
// Go programs using the "interp" package. The command-line program
// has the same interface as regular awk:
//
//     goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]
//
// The -F flag specifies the field separator (the default is to split
// on whitespace). The -v flag allows you to set a variable to a
// given value (multiple -v flags allowed). The -f flag allows you to
// read AWK source from a file instead of the 'prog' command-line
// argument. The rest of the arguments are input filenames (default
// is to read from stdin).
//
// A simple example (prints the sum of the numbers in the file's
// second column):
//
//     $ echo 'foo 12
//     > bar 34
//     > baz 56' >file.txt
//     $ goawk '{ sum += $2 } END { print sum }' file.txt
//     102
//
// To use GoAWK in your Go programs, see README.md or the "interp"
// docs.
//
package main

/*

TODO:
- performance testing: I/O, allocations, CPU
  + PoC: is interpreting via a "heavy AST" faster?
    i.e., with execute functions on the AST elements instead of the switch/case
  + benchmark against awk/gawk with some real awk scripts
  + do a bit more cpu and mem profiling
- do some more fuzz testing
- release 1.0.0 (do anything for Go modules?)
- remove notice about "beta" from README.md

*/ // This comment intentionally left blank

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"
	"unicode/utf8"

	"github.com/benhoyt/goawk/interp"
	"github.com/benhoyt/goawk/lexer"
	"github.com/benhoyt/goawk/parser"
)

func main() {
	// Main AWK arguments
	var progFiles multiString
	flag.Var(&progFiles, "f", "load AWK source from `progfile` (multiple allowed)")
	fieldSep := flag.String("F", " ", "field separator")
	var vars multiString
	flag.Var(&vars, "v", "name=value variable `assignment` (multiple allowed)")

	// Debugging and profiling arguments
	debug := flag.Bool("d", false, "debug mode (print parsed AST to stderr)")
	debugTypes := flag.Bool("dt", false, "show variable types debug info")
	cpuprofile := flag.String("cpuprofile", "", "write CPU profile to `file`")
	memprofile := flag.String("memprofile", "", "write memory profile to `file`")

	flag.Parse()
	args := flag.Args()

	var src []byte
	if len(progFiles) > 0 {
		// Read source: the concatenation of all source files specified
		buf := &bytes.Buffer{}
		for _, progFile := range progFiles {
			if progFile == "-" {
				_, err := buf.ReadFrom(os.Stdin)
				if err != nil {
					errorExit("%s", err)
				}
			} else {
				f, err := os.Open(progFile)
				if err != nil {
					errorExit("%s", err)
				}
				_, err = buf.ReadFrom(f)
				if err != nil {
					f.Close()
					errorExit("%s", err)
				}
				f.Close()
			}
			// Append newline to file in case it doesn't end with one
			buf.WriteByte('\n')
		}
		src = buf.Bytes()
	} else {
		if len(args) < 1 {
			errorExit("usage: goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]")
		}
		src = []byte(args[0])
		args = args[1:]
	}

	// Parse source code and setup interpreter
	parserConfig := &parser.ParserConfig{
		DebugTypes:  *debugTypes,
		DebugWriter: os.Stderr,
	}
	prog, err := parser.ParseProgram(src, parserConfig)
	if err != nil {
		errMsg := fmt.Sprintf("%s", err)
		if err, ok := err.(*parser.ParseError); ok {
			showSourceLine(src, err.Position, len(errMsg))
		}
		errorExit("%s", errMsg)
	}
	if *debug {
		fmt.Fprintln(os.Stderr, prog)
	}
	config := &interp.Config{
		Argv0: filepath.Base(os.Args[0]),
		Args:  args,
		Vars:  []string{"FS", *fieldSep},
	}
	for _, v := range vars {
		parts := strings.SplitN(v, "=", 2)
		if len(parts) != 2 {
			errorExit("-v flag must be in format name=value")
		}
		config.Vars = append(config.Vars, parts[0], parts[1])
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			errorExit("could not create CPU profile: %v", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			errorExit("could not start CPU profile: %v", err)
		}
	}

	status, err := interp.ExecProgram(prog, config)
	if err != nil {
		errorExit("%s", err)
	}

	if *cpuprofile != "" {
		pprof.StopCPUProfile()
	}

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			errorExit("could not create memory profile: %v", err)
		}
		runtime.GC() // get up-to-date statistics
		if err := pprof.WriteHeapProfile(f); err != nil {
			errorExit("could not write memory profile: %v", err)
		}
		f.Close()
	}

	os.Exit(status)
}

// For parse errors, show source line and position of error, eg:
//
// -----------------------------------------------------
// BEGIN { x*; }
//           ^
// -----------------------------------------------------
// parse error at 1:11: expected expression instead of ;
//
func showSourceLine(src []byte, pos lexer.Position, dividerLen int) {
	divider := strings.Repeat("-", dividerLen)
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
	lines := bytes.Split(src, []byte{'\n'})
	srcLine := string(lines[pos.Line-1])
	numTabs := strings.Count(srcLine[:pos.Column-1], "\t")
	runeColumn := utf8.RuneCountInString(srcLine[:pos.Column-1])
	fmt.Fprintln(os.Stderr, strings.Replace(srcLine, "\t", "    ", -1))
	fmt.Fprintln(os.Stderr, strings.Repeat(" ", runeColumn)+strings.Repeat("   ", numTabs)+"^")
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
}

func errorExit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
	os.Exit(1)
}

// Helper type for flag parsing to allow multiple -f and -v arguments
type multiString []string

func (m *multiString) String() string {
	return fmt.Sprintf("%v", []string(*m))
}

func (m *multiString) Set(value string) error {
	*m = append(*m, value)
	return nil
}
<commit_msg>Tweak README<commit_after>// Package goawk is an implementation of AWK written in Go.
//
// You can use the command-line "goawk" command or run AWK from your
// Go programs using the "interp" package. The command-line program
// has the same interface as regular awk:
//
//     goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]
//
// The -F flag specifies the field separator (the default is to split
// on whitespace). The -v flag allows you to set a variable to a
// given value (multiple -v flags allowed). The -f flag allows you to
// read AWK source from a file instead of the 'prog' command-line
// argument. The rest of the arguments are input filenames (default
// is to read from stdin).
//
// A simple example (prints the sum of the numbers in the file's
// second column):
//
//     $ echo 'foo 12
//     > bar 34
//     > baz 56' >file.txt
//     $ goawk '{ sum += $2 } END { print sum }' file.txt
//     102
//
// To use GoAWK in your Go programs, see README.md or the "interp"
// docs.
//
package main

/*

TODO:
- address Travis build error:
    --- FAIL: TestInterp/BEGIN_{_print_|"out";_getline_<"out"_}__#_!awk_!gawk (0.00s)
        interp_test.go:590: expected error "can't read from writer stream", got "write |1: broken pipe"
- performance testing: I/O, allocations, CPU
  + PoC: is interpreting via a "heavy AST" faster?
    i.e., with execute functions on the AST elements instead of the switch/case
  + profile goawk with some more real-world AWK scripts
- do some more fuzz testing
- release 1.0.0 (do anything for Go modules?)
- remove notice about "beta" from README.md

*/ // This comment intentionally left blank

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"
	"unicode/utf8"

	"github.com/benhoyt/goawk/interp"
	"github.com/benhoyt/goawk/lexer"
	"github.com/benhoyt/goawk/parser"
)

func main() {
	// Main AWK arguments
	var progFiles multiString
	flag.Var(&progFiles, "f", "load AWK source from `progfile` (multiple allowed)")
	fieldSep := flag.String("F", " ", "field separator")
	var vars multiString
	flag.Var(&vars, "v", "name=value variable `assignment` (multiple allowed)")

	// Debugging and profiling arguments
	debug := flag.Bool("d", false, "debug mode (print parsed AST to stderr)")
	debugTypes := flag.Bool("dt", false, "show variable types debug info")
	cpuprofile := flag.String("cpuprofile", "", "write CPU profile to `file`")
	memprofile := flag.String("memprofile", "", "write memory profile to `file`")

	flag.Parse()
	args := flag.Args()

	var src []byte
	if len(progFiles) > 0 {
		// Read source: the concatenation of all source files specified
		buf := &bytes.Buffer{}
		for _, progFile := range progFiles {
			if progFile == "-" {
				_, err := buf.ReadFrom(os.Stdin)
				if err != nil {
					errorExit("%s", err)
				}
			} else {
				f, err := os.Open(progFile)
				if err != nil {
					errorExit("%s", err)
				}
				_, err = buf.ReadFrom(f)
				if err != nil {
					f.Close()
					errorExit("%s", err)
				}
				f.Close()
			}
			// Append newline to file in case it doesn't end with one
			buf.WriteByte('\n')
		}
		src = buf.Bytes()
	} else {
		if len(args) < 1 {
			errorExit("usage: goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]")
		}
		src = []byte(args[0])
		args = args[1:]
	}

	// Parse source code and setup interpreter
	parserConfig := &parser.ParserConfig{
		DebugTypes:  *debugTypes,
		DebugWriter: os.Stderr,
	}
	prog, err := parser.ParseProgram(src, parserConfig)
	if err != nil {
		errMsg := fmt.Sprintf("%s", err)
		if err, ok := err.(*parser.ParseError); ok {
			showSourceLine(src, err.Position, len(errMsg))
		}
		errorExit("%s", errMsg)
	}
	if *debug {
		fmt.Fprintln(os.Stderr, prog)
	}
	config := &interp.Config{
		Argv0: filepath.Base(os.Args[0]),
		Args:  args,
		Vars:  []string{"FS", *fieldSep},
	}
	for _, v := range vars {
		parts := strings.SplitN(v, "=", 2)
		if len(parts) != 2 {
			errorExit("-v flag must be in format name=value")
		}
		config.Vars = append(config.Vars, parts[0], parts[1])
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			errorExit("could not create CPU profile: %v", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			errorExit("could not start CPU profile: %v", err)
		}
	}

	status, err := interp.ExecProgram(prog, config)
	if err != nil {
		errorExit("%s", err)
	}

	if *cpuprofile != "" {
		pprof.StopCPUProfile()
	}

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			errorExit("could not create memory profile: %v", err)
		}
		runtime.GC() // get up-to-date statistics
		if err := pprof.WriteHeapProfile(f); err != nil {
			errorExit("could not write memory profile: %v", err)
		}
		f.Close()
	}

	os.Exit(status)
}

// For parse errors, show source line and position of error, eg:
//
// -----------------------------------------------------
// BEGIN { x*; }
//           ^
// -----------------------------------------------------
// parse error at 1:11: expected expression instead of ;
//
func showSourceLine(src []byte, pos lexer.Position, dividerLen int) {
	divider := strings.Repeat("-", dividerLen)
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
	lines := bytes.Split(src, []byte{'\n'})
	srcLine := string(lines[pos.Line-1])
	numTabs := strings.Count(srcLine[:pos.Column-1], "\t")
	runeColumn := utf8.RuneCountInString(srcLine[:pos.Column-1])
	fmt.Fprintln(os.Stderr, strings.Replace(srcLine, "\t", "    ", -1))
	fmt.Fprintln(os.Stderr, strings.Repeat(" ", runeColumn)+strings.Repeat("   ", numTabs)+"^")
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
}

func errorExit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
	os.Exit(1)
}

// Helper type for flag parsing to allow multiple -f and -v arguments
type multiString []string

func (m *multiString) String() string {
	return fmt.Sprintf("%v", []string(*m))
}

func (m *multiString) Set(value string) error {
	*m = append(*m, value)
	return nil
}
<|endoftext|>


<commit_before>package godbg

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"regexp"
	"runtime/debug"
	"strings"
)

var rxDbgLine, _ = regexp.Compile(`^.*[Vv]on[Cc](?:/prog/git)?/senvgo/main.go:(\d+)\s`)
var rxDbgFnct, _ = regexp.Compile(`^\s+(?:com/VonC/senvgo)?(?:\.\(([^\)]+)\))?\.?([^:]+)`)

// http://stackoverflow.com/a/23554672/6309 https://vividcortex.com/blog/2013/12/03/go-idiom-package-and-object/
// you design a type with methods as usual, and then you also place matching functions at the package level itself.
// These functions simply delegate to a default instance of the type that’s a private package-level variable, created in an init() function.

// Pdbg allows to print debug message with indent and function name added
type Pdbg struct {
	bout *bytes.Buffer
	berr *bytes.Buffer
	sout *bufio.Writer
	serr *bufio.Writer
}

// Out returns a writer for normal messages.
// By default, os.StdOut
func Out() io.Writer {
	return pdbg.Out()
}

// Out returns a writer for normal messages for a given pdbg instance.
// By default, os.StdOut
func (pdbg *Pdbg) Out() io.Writer {
	if pdbg.sout == nil {
		return os.Stdout
	}
	return pdbg.sout
}

// Err returns a writer for error messages.
// By default, os.StdErr
func Err() io.Writer {
	return pdbg.Err()
}

// Err returns a writer for error messages for a given pdbg instance.
// By default, os.StdErr
func (pdbg *Pdbg) Err() io.Writer {
	if pdbg.serr == nil {
		return os.Stderr
	}
	return pdbg.serr
}

// global pdbg used for printing
var pdbg = &Pdbg{}

// Option set an option for a Pdbg
// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
type Option func(*Pdbg)

func pdbgInc(scanner *bufio.Scanner, line string) string {
	m := rxDbgLine.FindSubmatchIndex([]byte(line))
	if len(m) == 0 {
		return ""
	}
	dbgLine := line[m[2]:m[3]]
	// fmt.Printf("line '%v', m '%+v'\n", line, m)
	scanner.Scan()
	line = scanner.Text()
	mf := rxDbgFnct.FindSubmatchIndex([]byte(line))
	// fmt.Printf("lineF '%v', mf '%+v'\n", line, mf)
	if len(mf) == 0 {
		return ""
	}
	dbgFnct := ""
	if mf[2] > -1 {
		dbgFnct = line[mf[2]:mf[3]]
	}
	if dbgFnct != "" {
		dbgFnct = dbgFnct + "."
	}
	dbgFnct = dbgFnct + line[mf[4]:mf[5]]

	return dbgFnct + ":" + dbgLine
}

func pdbgExcluded(dbg string) bool {
	if strings.Contains(dbg, "ReadConfig:") {
		return false
	}
	return false
}

// Pdbgf uses global Pdbg variable for printing strings, with indent and function name
func Pdbgf(format string, args ...interface{}) string {
	msg := fmt.Sprintf(format+"\n", args...)
	msg = strings.TrimSpace(msg)
	bstack := bytes.NewBuffer(debug.Stack())
	// fmt.Printf("%+v", bstack)

	scanner := bufio.NewScanner(bstack)
	pmsg := ""
	depth := 0
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, "smartystreets") {
			break
		}
		m := rxDbgLine.FindSubmatchIndex([]byte(line))
		if len(m) == 0 {
			continue
		}
		if depth > 0 && depth < 4 {
			dbg := pdbgInc(scanner, line)
			if dbg == "" {
				continue
			}
			if depth == 1 {
				if pdbgExcluded(dbg) {
					return ""
				}
				pmsg = "[" + dbg + "]"
			} else {
				pmsg = pmsg + " (" + dbg + ")"
			}
		}
		depth = depth + 1
	}
	spaces := ""
	if depth >= 2 {
		spaces = strings.Repeat(" ", depth-2)
	}
	res := pmsg
	pmsg = spaces + pmsg
	msg = pmsg + "\n" + spaces + "  " + msg + "\n"
	// fmt.Printf("MSG '%v'\n", msg)
	fmt.Fprint(os.Stderr, fmt.Sprint(msg))
	return res
}
<commit_msg>Defines an Option: SetBuffers<commit_after>package godbg

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"regexp"
	"runtime/debug"
	"strings"
)

var rxDbgLine, _ = regexp.Compile(`^.*[Vv]on[Cc](?:/prog/git)?/senvgo/main.go:(\d+)\s`)
var rxDbgFnct, _ = regexp.Compile(`^\s+(?:com/VonC/senvgo)?(?:\.\(([^\)]+)\))?\.?([^:]+)`)

// http://stackoverflow.com/a/23554672/6309 https://vividcortex.com/blog/2013/12/03/go-idiom-package-and-object/
// you design a type with methods as usual, and then you also place matching functions at the package level itself.
// These functions simply delegate to a default instance of the type that’s a private package-level variable, created in an init() function.

// Pdbg allows to print debug message with indent and function name added
type Pdbg struct {
	bout *bytes.Buffer
	berr *bytes.Buffer
	sout *bufio.Writer
	serr *bufio.Writer
}

// Out returns a writer for normal messages.
// By default, os.StdOut
func Out() io.Writer {
	return pdbg.Out()
}

// Out returns a writer for normal messages for a given pdbg instance.
// By default, os.StdOut
func (pdbg *Pdbg) Out() io.Writer {
	if pdbg.sout == nil {
		return os.Stdout
	}
	return pdbg.sout
}

// Err returns a writer for error messages.
// By default, os.StdErr
func Err() io.Writer {
	return pdbg.Err()
}

// Err returns a writer for error messages for a given pdbg instance.
// By default, os.StdErr
func (pdbg *Pdbg) Err() io.Writer {
	if pdbg.serr == nil {
		return os.Stderr
	}
	return pdbg.serr
}

// global pdbg used for printing
var pdbg = &Pdbg{}

// Option set an option for a Pdbg
// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
type Option func(*Pdbg)

// SetBuffers is an option for replacing stdout and stderr by
// bytes buffers (in a bufio.Writer)
func SetBuffers(apdbg *Pdbg) {
	apdbg.bout = bytes.NewBuffer(nil)
	apdbg.sout = bufio.NewWriter(apdbg.bout)
	apdbg.berr = bytes.NewBuffer(nil)
	apdbg.serr = bufio.NewWriter(apdbg.berr)
}

func pdbgInc(scanner *bufio.Scanner, line string) string {
	m := rxDbgLine.FindSubmatchIndex([]byte(line))
	if len(m) == 0 {
		return ""
	}
	dbgLine := line[m[2]:m[3]]
	// fmt.Printf("line '%v', m '%+v'\n", line, m)
	scanner.Scan()
	line = scanner.Text()
	mf := rxDbgFnct.FindSubmatchIndex([]byte(line))
	// fmt.Printf("lineF '%v', mf '%+v'\n", line, mf)
	if len(mf) == 0 {
		return ""
	}
	dbgFnct := ""
	if mf[2] > -1 {
		dbgFnct = line[mf[2]:mf[3]]
	}
	if dbgFnct != "" {
		dbgFnct = dbgFnct + "."
	}
	dbgFnct = dbgFnct + line[mf[4]:mf[5]]

	return dbgFnct + ":" + dbgLine
}

func pdbgExcluded(dbg string) bool {
	if strings.Contains(dbg, "ReadConfig:") {
		return false
	}
	return false
}

// Pdbgf uses global Pdbg variable for printing strings, with indent and function name
func Pdbgf(format string, args ...interface{}) string {
	msg := fmt.Sprintf(format+"\n", args...)
	msg = strings.TrimSpace(msg)
	bstack := bytes.NewBuffer(debug.Stack())
	// fmt.Printf("%+v", bstack)

	scanner := bufio.NewScanner(bstack)
	pmsg := ""
	depth := 0
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, "smartystreets") {
			break
		}
		m := rxDbgLine.FindSubmatchIndex([]byte(line))
		if len(m) == 0 {
			continue
		}
		if depth > 0 && depth < 4 {
			dbg := pdbgInc(scanner, line)
			if dbg == "" {
				continue
			}
			if depth == 1 {
				if pdbgExcluded(dbg) {
					return ""
				}
				pmsg = "[" + dbg + "]"
			} else {
				pmsg = pmsg + " (" + dbg + ")"
			}
		}
		depth = depth + 1
	}
	spaces := ""
	if depth >= 2 {
		spaces = strings.Repeat(" ", depth-2)
	}
	res := pmsg
	pmsg = spaces + pmsg
	msg = pmsg + "\n" + spaces + "  " + msg + "\n"
	// fmt.Printf("MSG '%v'\n", msg)
	fmt.Fprint(os.Stderr, fmt.Sprint(msg))
	return res
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/defeated/going/commands"
	"github.com/defeated/going/storage"
	"os"
)

func main() {
	stor := storage.NewStorage(os.Getenv("HOME") + "/.going/data.json")
	cmd := os.Args[1]
	if cmd == "--add" {
		path := os.Args[2]
		commands.CmdAdd(stor, path)
	} else if cmd == "--prune" {
		commands.CmdPrune(stor)
	} else {
		commands.CmdDefault(stor, cmd)
	}
}
<commit_msg>use switch() for subcommands (TODO use flag/flagset instead)<commit_after>package main

import (
	"github.com/defeated/going/commands"
	"github.com/defeated/going/storage"
	"os"
)

func main() {
	stor := storage.NewStorage(os.Getenv("HOME") + "/.going/data.json")
	cmd := os.Args[1]
	switch cmd {
	default:
		commands.CmdDefault(stor, cmd)
	case "--add":
		path := os.Args[2]
		commands.CmdAdd(stor, path)
	case "--prune":
		commands.CmdPrune(stor)
	}
}
<|endoftext|>