<commit_before>package glib

// #include <glib.h>
// #include <glib-object.h>
// #include "glib.go.h"
import "C"
import (
	"reflect"
	"unsafe"

	"github.com/gotk3/gotk3/internal/closure"
)

/*
 * Events
 */

// SignalHandle is the ID of a signal handler.
type SignalHandle uint

// Connect is a wrapper around g_signal_connect_closure(). f must be a function
// with at least one parameter matching the type it is connected to.
//
// It is optional to list the rest of the required types from Gtk, as values
// that don't fit into the function parameter will simply be ignored; however,
// extraneous types will trigger a runtime panic. Arguments for f must be a
// matching Go equivalent type for the C callback, or an interface type which
// the value may be packed in. If the type is not suitable, a runtime panic will
// occur when the signal is emitted.
//
// Circular References
//
// To prevent circular references, prefer declaring Connect functions like so:
//
//    obj.Connect(func(obj *ObjType) { obj.Do() })
//
// Instead of directly referencing the object from outside like so:
//
//    obj.Connect(func() { obj.Do() })
//
// By default, the direct referencing piece of code will trigger a runtime panic
// upon registering, unless ClosureCheckReceiver is set to false. This is to
// ensure the minimum correct behavior in most scenarios.
//
// When using Connect, beware of referencing variables outside the closure that
// may cause a circular reference that prevents both Go from garbage collecting
// the callback and GTK from successfully unreferencing its values.
//
// Below is an example piece of code that is considered "leaky":
//
//    type ChatBox struct {
//        gtk.TextView
//        Loader *gdk.PixbufLoader
//
//        State State
//    }
//
//    func (box *ChatBox) Method() {
//        box.Loader.Connect("size-allocate", func(loader *gdk.PixbufLoader) {
//            // Here, we're dereferencing box to get the state, which might
//            // keep box alive along with the PixbufLoader, causing a circular
//            // reference.
//            loader.SetSize(box.State.Width, box.State.Height)
//        })
//    }
//
// There are many solutions to fix the above piece of code. For example,
// box.Loader could be discarded manually immediately after it's done by setting
// it to nil, or the signal handle could be disconnected manually, or box could
// be set to nil after its first call in the callback.
func (v *Object) Connect(detailedSignal string, f interface{}) SignalHandle {
	return v.connectClosure(false, detailedSignal, f)
}

// ConnectAfter is a wrapper around g_signal_connect_closure(). The difference
// between Connect and ConnectAfter is that the latter will be invoked after the
// default handler, not before. For more information, refer to Connect.
func (v *Object) ConnectAfter(detailedSignal string, f interface{}) SignalHandle {
	return v.connectClosure(true, detailedSignal, f)
}

// ClosureCheckReceiver, if true, will make GLib check for every single
// closure's first argument to ensure that it is correct, otherwise it will
// panic with a message warning about the possible circular references. The
// receiver in this case is most often the first argument of the callback.
var ClosureCheckReceiver = true

func (v *Object) connectClosure(after bool, detailedSignal string, f interface{}) SignalHandle {
	fs := closure.NewFuncStack(f, 2)

	if ClosureCheckReceiver {
		// This is a bit slow, but we could be careful.
		objValue, err := v.goValue()
		if err == nil {
			fsType := fs.Func.Type()
			if fsType.NumIn() < 1 {
				fs.Panicf("callback should have the object receiver to avoid circular references")
			}
			objType := reflect.TypeOf(objValue)
			if first := fsType.In(0); !objType.ConvertibleTo(first) {
				fs.Panicf("receiver not convertible to expected type %s, got %s", objType, first)
			}
		}

		// Allow the type check to fail if we can't get a value marshaler. This
		// rarely happens, but it might, and we want to at least allow working
		// around it.
	}

	cstr := C.CString(detailedSignal)
	defer C.free(unsafe.Pointer(cstr))

	gclosure := ClosureNewFunc(fs)
	c := C.g_signal_connect_closure(C.gpointer(v.native()), (*C.gchar)(cstr), gclosure, gbool(after))

	// TODO: There's a slight race condition here, where
	// g_signal_connect_closure may trigger signal callbacks before the signal
	// is registered. It is therefore ideal to have another intermediate ID to
	// pass into the connect function. This is not a big issue though, since
	// there isn't really any guarantee that signals should arrive until after
	// the Connect functions return successfully.
	closure.RegisterSignal(uint(c), unsafe.Pointer(gclosure))

	return SignalHandle(c)
}

// ClosureNew creates a new GClosure and adds its callback function to the
// internal registry. It's exported for visibility to other gotk3 packages and
// should not be used in a regular application.
func ClosureNew(f interface{}) *C.GClosure {
	return ClosureNewFunc(closure.NewFuncStack(f, 2))
}

// ClosureNewFunc creates a new GClosure and adds its callback function to the
// internal registry. It's exported for visibility to other gotk3 packages; it
// cannot be used in application code, as package closure is part of the
// internals.
func ClosureNewFunc(funcStack closure.FuncStack) *C.GClosure {
	gclosure := C._g_closure_new()
	C._g_closure_add_finalize_notifier(gclosure)
	closure.Assign(unsafe.Pointer(gclosure), funcStack)

	return gclosure
}

// removeClosure removes a closure from the internal closures map. This is
// needed to prevent a leak where Go code can access the closure context
// (along with rf and userdata) even after an object has been destroyed and
// the GClosure is invalidated and will never run.
//
//export removeClosure
func removeClosure(_ C.gpointer, gclosure *C.GClosure) {
	closure.Delete(unsafe.Pointer(gclosure))
}
<commit_msg>ClosureCheckReceiver default to false<commit_after>package glib

// #include <glib.h>
// #include <glib-object.h>
// #include "glib.go.h"
import "C"
import (
	"reflect"
	"unsafe"

	"github.com/gotk3/gotk3/internal/closure"
)

/*
 * Events
 */

// SignalHandle is the ID of a signal handler.
type SignalHandle uint

// Connect is a wrapper around g_signal_connect_closure(). f must be a function
// with at least one parameter matching the type it is connected to.
//
// It is optional to list the rest of the required types from Gtk, as values
// that don't fit into the function parameter will simply be ignored; however,
// extraneous types will trigger a runtime panic. Arguments for f must be a
// matching Go equivalent type for the C callback, or an interface type which
// the value may be packed in. If the type is not suitable, a runtime panic will
// occur when the signal is emitted.
//
// Circular References
//
// To prevent circular references, prefer declaring Connect functions like so:
//
//    obj.Connect(func(obj *ObjType) { obj.Do() })
//
// Instead of directly referencing the object from outside like so:
//
//    obj.Connect(func() { obj.Do() })
//
// When using Connect, beware of referencing variables outside the closure that
// may cause a circular reference that prevents both Go from garbage collecting
// the callback and GTK from successfully unreferencing its values.
//
// Below is an example piece of code that is considered "leaky":
//
//    type ChatBox struct {
//        gtk.TextView
//        Loader *gdk.PixbufLoader
//
//        State State
//    }
//
//    func (box *ChatBox) Method() {
//        box.Loader.Connect("size-allocate", func(loader *gdk.PixbufLoader) {
//            // Here, we're dereferencing box to get the state, which might
//            // keep box alive along with the PixbufLoader, causing a circular
//            // reference.
//            loader.SetSize(box.State.Width, box.State.Height)
//        })
//    }
//
// There are many solutions to fix the above piece of code. For example,
// box.Loader could be discarded manually immediately after it's done by setting
// it to nil, or the signal handle could be disconnected manually, or box could
// be set to nil after its first call in the callback.
func (v *Object) Connect(detailedSignal string, f interface{}) SignalHandle {
	return v.connectClosure(false, detailedSignal, f)
}

// ConnectAfter is a wrapper around g_signal_connect_closure(). The difference
// between Connect and ConnectAfter is that the latter will be invoked after the
// default handler, not before. For more information, refer to Connect.
func (v *Object) ConnectAfter(detailedSignal string, f interface{}) SignalHandle {
	return v.connectClosure(true, detailedSignal, f)
}

// ClosureCheckReceiver, if true, will make GLib check for every single
// closure's first argument to ensure that it is correct, otherwise it will
// panic with a message warning about the possible circular references. The
// receiver in this case is most often the first argument of the callback.
//
// This constant can be changed by using go.mod's replace directive for
// debugging purposes.
const ClosureCheckReceiver = false

func (v *Object) connectClosure(after bool, detailedSignal string, f interface{}) SignalHandle {
	fs := closure.NewFuncStack(f, 2)

	if ClosureCheckReceiver {
		// This is a bit slow, but we could be careful.
		objValue, err := v.goValue()
		if err == nil {
			fsType := fs.Func.Type()
			if fsType.NumIn() < 1 {
				fs.Panicf("callback should have the object receiver to avoid circular references")
			}
			objType := reflect.TypeOf(objValue)
			if first := fsType.In(0); !objType.ConvertibleTo(first) {
				fs.Panicf("receiver not convertible to expected type %s, got %s", objType, first)
			}
		}

		// Allow the type check to fail if we can't get a value marshaler. This
		// rarely happens, but it might, and we want to at least allow working
		// around it.
	}

	cstr := C.CString(detailedSignal)
	defer C.free(unsafe.Pointer(cstr))

	gclosure := ClosureNewFunc(fs)
	c := C.g_signal_connect_closure(C.gpointer(v.native()), (*C.gchar)(cstr), gclosure, gbool(after))

	// TODO: There's a slight race condition here, where
	// g_signal_connect_closure may trigger signal callbacks before the signal
	// is registered. It is therefore ideal to have another intermediate ID to
	// pass into the connect function. This is not a big issue though, since
	// there isn't really any guarantee that signals should arrive until after
	// the Connect functions return successfully.
	closure.RegisterSignal(uint(c), unsafe.Pointer(gclosure))

	return SignalHandle(c)
}

// ClosureNew creates a new GClosure and adds its callback function to the
// internal registry. It's exported for visibility to other gotk3 packages and
// should not be used in a regular application.
func ClosureNew(f interface{}) *C.GClosure {
	return ClosureNewFunc(closure.NewFuncStack(f, 2))
}

// ClosureNewFunc creates a new GClosure and adds its callback function to the
// internal registry. It's exported for visibility to other gotk3 packages; it
// cannot be used in application code, as package closure is part of the
// internals.
func ClosureNewFunc(funcStack closure.FuncStack) *C.GClosure {
	gclosure := C._g_closure_new()
	C._g_closure_add_finalize_notifier(gclosure)
	closure.Assign(unsafe.Pointer(gclosure), funcStack)

	return gclosure
}

// removeClosure removes a closure from the internal closures map. This is
// needed to prevent a leak where Go code can access the closure context
// (along with rf and userdata) even after an object has been destroyed and
// the GClosure is invalidated and will never run.
//
//export removeClosure
func removeClosure(_ C.gpointer, gclosure *C.GClosure) {
	closure.Delete(unsafe.Pointer(gclosure))
}
<|endoftext|>


<commit_before>package main

// Config holds global configuration, defaults are provided in main.
// Agent config is populated from startup flag.
type Config struct {
	Environment            string `m:"Environment"`
	LogLevel               string `m:"LogLevel"`
	Port                   int    `m:"Port"`
	CollectInterval        int    `m:"CollectInterval"`
	DockerApiAddresses     string `m:"DockerApiAddresses"`
	ConsulApiAddresses     string `m:"ConsulApiAddresses"`
	VSphereApiAddress      string `m:"VSphereApiAddresses"`
	VSphereInclude         string `m:"VSphereInclude"`
	VSphereExclude         string `m:"VSphereExclude"`
	VSphereCollectInterval int    `m:"VSphereCollectInterval"`
	Nats                   string `m:"Nats"`
}
<commit_msg>yaml collector config<commit_after>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"
)

// Config holds global configuration, defaults are provided in main.
// Agent config is populated from startup flag.
type Config struct {
	Environment            string `m:"Environment"`
	LogLevel               string `m:"LogLevel"`
	Port                   int    `m:"Port"`
	CollectInterval        int    `m:"CollectInterval"`
	DockerApiAddresses     string `m:"DockerApiAddresses"`
	ConsulApiAddresses     string `m:"ConsulApiAddresses"`
	VSphereApiAddress      string `m:"VSphereApiAddresses"`
	VSphereInclude         string `m:"VSphereInclude"`
	VSphereExclude         string `m:"VSphereExclude"`
	VSphereCollectInterval int    `m:"VSphereCollectInterval"`
	Nats                   string `m:"Nats"`
}

type CollectorConfig struct {
	Docker  ApiCollectorConfig `json:"docker" yaml:"docker"`
	Consul  ApiCollectorConfig `json:"consul" yaml:"consul"`
	VSphere ApiCollectorConfig `json:"vsphere" yaml:"vsphere"`
}

type ApiCollectorConfig struct {
	Endpoints []string `json:"endpoints" yaml:"endpoints"`
	Include   []string `json:"include" yaml:"include"`
	Exclude   []string `json:"exclude" yaml:"exclude"`
	Cron      string   `json:"cron" yaml:"cron"`
}

func LoadCollectorConfig(dir string, name string) (*CollectorConfig, error) {
	cfg := &CollectorConfig{}
	cfgPath := ""
	err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
		if strings.Contains(path, name+".yml") || strings.Contains(path, name+".yaml") {
			cfgPath = path
		}
		return nil
	})

	if err != nil {
		return nil, errors.Wrapf(err, "Reading from %v failed", dir)
	}

	if len(cfgPath) < 1 {
		return nil, errors.Errorf("Collector config %v not found", name)
	}

	data, err := ioutil.ReadFile(cfgPath)
	if err != nil {
		return nil, errors.Wrapf(err, "Reading %v failed", cfgPath)
	}

	if err := yaml.Unmarshal(data, cfg); err != nil {
		return nil, errors.Wrapf(err, "Parsing %v failed", cfgPath)
	}

	return cfg, nil
}
<|endoftext|>


<commit_before>package mixpanel

import (
	"fmt"
	"errors"
	"io"
	"strconv"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"net/http"
	"net/url"
	"time"
)

type P map[string]interface{}

type Event struct {
	Event      string `json:"event"`
	Properties *P     `json:"properties"`
}

type Consumer interface {
	Send(endpoint string, json_msg []byte) error
}

type Mixpanel struct {
	Token string `json:token`
	verbose bool
	c Consumer
}

const events_endpoint string = "https://api.mixpanel.com/track"
const people_endpoint string = "https://api.mixpanel.com/engage"

func b64(payload []byte) []byte {
	var b bytes.Buffer
	encoder := base64.NewEncoder(base64.URLEncoding, &b)
	encoder.Write(payload)
	encoder.Close()
	return b.Bytes()[:b.Len()]
}

func NewMixpanel(token string) *Mixpanel {
	return &Mixpanel{
		Token: token,
		verbose: true,
		c: NewStdConsumer(),
	}
}

func (this *P) Update(other *P) *P {
	if other == nil{
		return this
	}
	for k, v := range *other {
		(*this)[k] = v
	}
	return this
}

/*
Notes that an event has occurred, along with a distinct_id
representing the source of that event (for example, a user id),
an event name describing the event and a set of properties
describing that event. Properties are provided as a Hash with
string keys and strings, numbers or booleans as values.

// Track that user "12345"'s credit card was declined
mp.Track("12345", "Credit Card Declined", nil)

// Properties describe the circumstances of the event,
// or aspects of the source or user associated with the event
mp.Track("12345", "Welcome Email Sent", &P{
  "Email Template" : "Pretty Pink Welcome",
  "User Sign-up Cohort" : "July 2013",
 })
*/
func (mp *Mixpanel) Track(distinct_id, event string, prop *P) error {
	properties := &P{
		"token":        mp.Token,
		"distinct_id":  distinct_id,
		"time":         strconv.FormatInt(time.Now().UTC().Unix(), 10),
		"mp_lib":       "go",
		"$lib_version": "0.1",
	}
	if prop == nil {
		prop = &P{}
	}

	properties.Update(prop)

	data, err := json.Marshal(&Event{
		Event:      event,
		Properties: properties,
	})
	if err != nil {
		return err
	}

	return mp.c.Send("events", data)
}

/*
Alias gives custom alias to a people record.

Alias sends an update to our servers linking an existing distinct_id
with a new id, so that events and profile updates associated with the
new id will be associated with the existing user's profile and behavior.
Example:
    mp.Alias("amy@mixpanel.com", "13793")
*/
func (mp *Mixpanel) Alias(alias_id, original_id string) error {
	return mp.Track(original_id, "$create_alias", &P{
            "distinct_id": original_id,
            "alias": alias_id,
        })
}

/*
PeopleUpdate sends a generic update to Mixpanel people analytics.
Caller is responsible for formatting the update message, as
documented in the Mixpanel HTTP specification, and passing
the message as a dict to update. This
method might be useful if you want to use very new
or experimental features of people analytics from python
The Mixpanel HTTP tracking API is documented at
https://mixpanel.com/help/reference/http
*/
func (mp *Mixpanel) PeopleUpdate(properties *P) error {
	record := &P{
		"$token": mp.Token,
		"$time": int(time.Now().UTC().Unix()),
	}
	record.Update(properties)

	data, err := json.Marshal(record)
	if err != nil {
		return err
	}
	return mp.c.Send("people", data)
}

/*
PeopleSet set properties of a people record.

PeopleSet sets properties of a people record given in JSON object. If the profile
does not exist, creates new profile with these properties.
Example:
    mp.PeopleSet("12345", &P{"Address": "1313 Mockingbird Lane",
                            "Birthday": "1948-01-01"})
*/
func (mp *Mixpanel) PeopleSet(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$set" : properties,
		})
}

/*
PeopleSetOnce sets immutable properties of a people record.

PeopleSetOnce sets properties of a people record given in JSON object. If the profile
does not exist, creates new profile with these properties. Does not
overwrite existing property values.
Example:
    mp.PeopleSetOnce("12345", &P{"First Login": "2013-04-01T13:20:00"})
*/
func (mp *Mixpanel) PeopleSetOnce(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$set" : properties,
	})
}

/*
PeopleIncrement Increments/decrements numerical properties of people record.

Takes in JSON object with keys and numerical values. Adds numerical
values to current property of profile. If property doesn't exist adds
value to zero. Takes in negative values for subtraction.
Example:
    mp.PeopleIncrement("12345", &P{"Coins Gathered": 12})
*/
func (mp *Mixpanel) PeopleIncrement(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$add" : properties,
	})
}

/*
PeopleAppend appends to the list associated with a property.

Takes a JSON object containing keys and values, and appends each to a
list associated with the corresponding property name. $appending to a
property that doesn't exist will result in assigning a list with one
element to that property.
Example:
    mp.PeopleAppend("12345", &P{ "Power Ups": "Bubble Lead" })
*/
func (mp *Mixpanel) PeopleAppend(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$append" : properties,
	})
}

/*
PeopleUnion Merges the values for a list associated with a property.

Takes a JSON object containing keys and list values. The list values in
the request are merged with the existing list on the user profile,
ignoring duplicate list values.
Example:
    mp.PeopleUnion("12345", &P{ "Items purchased": ["socks", "shirts"] } )
*/
func (mp *Mixpanel) PeopleUnion(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$union" : properties,
	})
}

/*
PeopleUnset removes properties from a profile.

Takes a JSON list of string property names, and permanently removes the
properties and their values from a profile.
Example:
    mp.PeopleUnset("12345", ["Days Overdue"])
*/
func (mp *Mixpanel) PeopleUnset(id string, properties []string) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$unset" : properties,
	})
}

/*
PeopleDelete permanently deletes a profile.

Permanently delete the profile from Mixpanel, along with all of its
properties.
Example:
    mp.PeopleDelete("12345")
*/
func (mp *Mixpanel) PeopleDelete(id string) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$delete":"",
	})
}

/*
PeopleTrackCharge Tracks a charge to a user.

Record that you have charged the current user a certain amount of
money. Charges recorded with track_charge will appear in the Mixpanel
revenue report.
Example:
    //tracks a charge of $50 to user '1234'
    mp.PeopleTrackCharge("1234", 50, nil)

    //tracks a charge of $50 to user '1234' at a specific time
    mp.PeopleTrackCharge("1234", 50, {"$time": "2013-04-01T09:02:00"})
*/
func (mp *Mixpanel) PeopleTrackCharge(id string, amount float64, prop *P) error {
	if prop == nil {
		prop = &P{}
	}
	prop.Update(&P{"$amount": amount})
	return mp.PeopleAppend(id, &P{
		"$transactions": prop,
	})
}

func parseJsonResponse(resp *http.Response) error {
	type jsonResponseT map[string]interface{}
	var response jsonResponseT
	var buff bytes.Buffer
	io.Copy(&buff, resp.Body)

	if err := json.Unmarshal(buff.Bytes(), &response); err == nil{
		if value, ok := response["status"]; ok {
			if value.(float64) == 1 {
				return nil
			} else {
				return errors.New( fmt.Sprintf("Mixpanel error: %s", response["error"]))
			}
		} else {
			return errors.New("Could not find field 'status' api change ?")
		}
	}
	return errors.New("Cannot interpret Mixpanel server response: "+buff.String())
}

type StdConsumer struct {
	endpoints map[string]string
}

func NewStdConsumer() Consumer {
	c := new(StdConsumer)
	c.endpoints = make(map[string]string)
	c.endpoints["events"] = events_endpoint
	c.endpoints["people"] = people_endpoint
	return c
}

func (c *StdConsumer) Send(endpoint string, msg []byte) error {

	if url, ok := c.endpoints[endpoint]; !ok {
		return errors.New(fmt.Sprintf("No such endpoint '%s'. Valid endpoints are one of %#v", endpoint, c.endpoints))
	} else {
		return c.write(url, msg)
	}
}

func (c *StdConsumer) write(endpoint string, msg []byte) error {
	track_url, err := url.Parse(endpoint)
	if err != nil {
		return err
	}

	q := track_url.Query()
	q.Add("data", string(b64(msg)))
	q.Add("verbose", "1")

	track_url.RawQuery = q.Encode()

	resp, err := http.Get(track_url.String())

	if err != nil {
		return err
	}

	return parseJsonResponse(resp)
}
<commit_msg>more docs<commit_after>package mixpanel

import (
	"fmt"
	"errors"
	"io"
	"strconv"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"net/http"
	"net/url"
	"time"
)

type P map[string]interface{}

// Update replaces all the elements of the map
func (this *P) Update(other *P) *P {
	if other == nil{
		return this
	}
	for k, v := range *other {
		(*this)[k] = v
	}
	return this
}

type Event struct {
	Event      string `json:"event"`
	Properties *P     `json:"properties"`
}

type Consumer interface {
	Send(endpoint string, json_msg []byte) error
}

type Mixpanel struct {
	Token string `json:token`
	verbose bool
	c Consumer
}

const events_endpoint string = "https://api.mixpanel.com/track"
const people_endpoint string = "https://api.mixpanel.com/engage"

func b64(payload []byte) []byte {
	var b bytes.Buffer
	encoder := base64.NewEncoder(base64.URLEncoding, &b)
	encoder.Write(payload)
	encoder.Close()
	return b.Bytes()[:b.Len()]
}

/*
NewMixpanel Creates a new Mixpanel object, which can be used for all tracking.

To use mixpanel, create a new Mixpanel object using your
token.  Takes in a user token and uses a StdConsumer
 */
func NewMixpanel(token string) *Mixpanel {
	return NewMixpanelWithConsumer(token, NewStdConsumer())
}

/*
NewMixpanelWithConsumer Creates a new Mixpanel object, which can be used for all tracking.

To use mixpanel, create a new Mixpanel object using your
token.  Takes in a user token and an optional Consumer (or
anything else with a send() method). If no consumer is
provided, Mixpanel will use the default Consumer, which
communicates one synchronous request for every message.
 */
func NewMixpanelWithConsumer(token string, c Consumer) *Mixpanel {
	return &Mixpanel{
		Token: token,
		verbose: true,
		c: c,
	}
}

/*
Notes that an event has occurred, along with a distinct_id
representing the source of that event (for example, a user id),
an event name describing the event and a set of properties
describing that event. Properties are provided as a Hash with
string keys and strings, numbers or booleans as values.

// Track that user "12345"'s credit card was declined
mp.Track("12345", "Credit Card Declined", nil)

// Properties describe the circumstances of the event,
// or aspects of the source or user associated with the event
mp.Track("12345", "Welcome Email Sent", &P{
  "Email Template" : "Pretty Pink Welcome",
  "User Sign-up Cohort" : "July 2013",
 })
*/
func (mp *Mixpanel) Track(distinct_id, event string, prop *P) error {
	properties := &P{
		"token":        mp.Token,
		"distinct_id":  distinct_id,
		"time":         strconv.FormatInt(time.Now().UTC().Unix(), 10),
		"mp_lib":       "go",
		"$lib_version": "0.1",
	}
	if prop == nil {
		prop = &P{}
	}

	properties.Update(prop)

	data, err := json.Marshal(&Event{
		Event:      event,
		Properties: properties,
	})
	if err != nil {
		return err
	}

	return mp.c.Send("events", data)
}

/*
Alias gives custom alias to a people record.

Alias sends an update to our servers linking an existing distinct_id
with a new id, so that events and profile updates associated with the
new id will be associated with the existing user's profile and behavior.
Example:
    mp.Alias("amy@mixpanel.com", "13793")
*/
func (mp *Mixpanel) Alias(alias_id, original_id string) error {
	return mp.Track(original_id, "$create_alias", &P{
            "distinct_id": original_id,
            "alias": alias_id,
        })
}

/*
PeopleUpdate sends a generic update to Mixpanel people analytics.
Caller is responsible for formatting the update message, as
documented in the Mixpanel HTTP specification, and passing
the message as a dict to update. This
method might be useful if you want to use very new
or experimental features of people analytics from python
The Mixpanel HTTP tracking API is documented at
https://mixpanel.com/help/reference/http
*/
func (mp *Mixpanel) PeopleUpdate(properties *P) error {
	record := &P{
		"$token": mp.Token,
		"$time": int(time.Now().UTC().Unix()),
	}
	record.Update(properties)

	data, err := json.Marshal(record)
	if err != nil {
		return err
	}
	return mp.c.Send("people", data)
}

/*
PeopleSet set properties of a people record.

PeopleSet sets properties of a people record given in JSON object. If the profile
does not exist, creates new profile with these properties.
Example:
    mp.PeopleSet("12345", &P{"Address": "1313 Mockingbird Lane",
                            "Birthday": "1948-01-01"})
*/
func (mp *Mixpanel) PeopleSet(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$set" : properties,
		})
}

/*
PeopleSetOnce sets immutable properties of a people record.

PeopleSetOnce sets properties of a people record given in JSON object. If the profile
does not exist, creates new profile with these properties. Does not
overwrite existing property values.
Example:
    mp.PeopleSetOnce("12345", &P{"First Login": "2013-04-01T13:20:00"})
*/
func (mp *Mixpanel) PeopleSetOnce(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$set" : properties,
	})
}

/*
PeopleIncrement Increments/decrements numerical properties of people record.

Takes in JSON object with keys and numerical values. Adds numerical
values to current property of profile. If property doesn't exist adds
value to zero. Takes in negative values for subtraction.
Example:
    mp.PeopleIncrement("12345", &P{"Coins Gathered": 12})
*/
func (mp *Mixpanel) PeopleIncrement(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$add" : properties,
	})
}

/*
PeopleAppend appends to the list associated with a property.

Takes a JSON object containing keys and values, and appends each to a
list associated with the corresponding property name. $appending to a
property that doesn't exist will result in assigning a list with one
element to that property.
Example:
    mp.PeopleAppend("12345", &P{ "Power Ups": "Bubble Lead" })
*/
func (mp *Mixpanel) PeopleAppend(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$append" : properties,
	})
}

/*
PeopleUnion Merges the values for a list associated with a property.

Takes a JSON object containing keys and list values. The list values in
the request are merged with the existing list on the user profile,
ignoring duplicate list values.
Example:
    mp.PeopleUnion("12345", &P{ "Items purchased": ["socks", "shirts"] } )
*/
func (mp *Mixpanel) PeopleUnion(id string, properties *P) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$union" : properties,
	})
}

/*
PeopleUnset removes properties from a profile.

Takes a JSON list of string property names, and permanently removes the
properties and their values from a profile.
Example:
    mp.PeopleUnset("12345", ["Days Overdue"])
*/
func (mp *Mixpanel) PeopleUnset(id string, properties []string) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$unset" : properties,
	})
}

/*
PeopleDelete permanently deletes a profile.

Permanently delete the profile from Mixpanel, along with all of its
properties.
Example:
    mp.PeopleDelete("12345")
*/
func (mp *Mixpanel) PeopleDelete(id string) error {
	return mp.PeopleUpdate(&P{
		"$distinct_id": id,
		"$delete":"",
	})
}

/*
PeopleTrackCharge Tracks a charge to a user.

Record that you have charged the current user a certain amount of
money. Charges recorded with track_charge will appear in the Mixpanel
revenue report.
Example:
    //tracks a charge of $50 to user '1234'
    mp.PeopleTrackCharge("1234", 50, nil)

    //tracks a charge of $50 to user '1234' at a specific time
    mp.PeopleTrackCharge("1234", 50, {"$time": "2013-04-01T09:02:00"})
*/
func (mp *Mixpanel) PeopleTrackCharge(id string, amount float64, prop *P) error {
	if prop == nil {
		prop = &P{}
	}
	prop.Update(&P{"$amount": amount})
	return mp.PeopleAppend(id, &P{
		"$transactions": prop,
	})
}

func parseJsonResponse(resp *http.Response) error {
	type jsonResponseT map[string]interface{}
	var response jsonResponseT
	var buff bytes.Buffer
	io.Copy(&buff, resp.Body)

	if err := json.Unmarshal(buff.Bytes(), &response); err == nil{
		if value, ok := response["status"]; ok {
			if value.(float64) == 1 {
				return nil
			} else {
				return errors.New( fmt.Sprintf("Mixpanel error: %s", response["error"]))
			}
		} else {
			return errors.New("Could not find field 'status' api change ?")
		}
	}
	return errors.New("Cannot interpret Mixpanel server response: "+buff.String())
}

type StdConsumer struct {
	endpoints map[string]string
}

func NewStdConsumer() Consumer {
	c := new(StdConsumer)
	c.endpoints = make(map[string]string)
	c.endpoints["events"] = events_endpoint
	c.endpoints["people"] = people_endpoint
	return c
}

func (c *StdConsumer) Send(endpoint string, msg []byte) error {

	if url, ok := c.endpoints[endpoint]; !ok {
		return errors.New(fmt.Sprintf("No such endpoint '%s'. Valid endpoints are one of %#v", endpoint, c.endpoints))
	} else {
		return c.write(url, msg)
	}
}

func (c *StdConsumer) write(endpoint string, msg []byte) error {
	track_url, err := url.Parse(endpoint)
	if err != nil {
		return err
	}

	q := track_url.Query()
	q.Add("data", string(b64(msg)))
	q.Add("verbose", "1")

	track_url.RawQuery = q.Encode()

	resp, err := http.Get(track_url.String())

	if err != nil {
		return err
	}

	return parseJsonResponse(resp)
}
<|endoftext|>


<commit_before>package compressor

import (
	"archive/zip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"time"
)

type ZipCompressor struct{}

func NewZipCompressor() *ZipCompressor {
	return &ZipCompressor{}
}

func (c *ZipCompressor) Compress(compressedFile io.Writer, targetDir string, files []string) error {
	w := zip.NewWriter(compressedFile)

	for _, filename := range files {
		filepath := fmt.Sprintf("%s/%s", targetDir, filename)
		info, err := os.Stat(filepath)
		if err != nil {
			return err
		}

		if info.IsDir() {
			continue
		}

		hdr, err := createFileHeader(filename, info)

		f, err := w.CreateHeader(hdr)
		if err != nil {
			return err
		}

		contents, _ := ioutil.ReadFile(filepath)
		_, err = f.Write(contents)
		if err != nil {
			return err
		}
	}

	if err := w.Close(); err != nil {
		return err
	}

	return nil
}

func createFileHeader(filename string, info os.FileInfo) (*zip.FileHeader, error) {
	hdr, err := zip.FileInfoHeader(info)
	if err != nil {
		return nil, err
	}

	hdr.Name = filename

	local := time.Now().Local()

	//現時刻のオフセットを取得
	_, offset := local.Zone()

	//差分を追加
	hdr.SetModTime(hdr.ModTime().Add(time.Duration(offset) * time.Second))

	return hdr, nil
}
<commit_msg>ZIP用とわかりにくいのでfunction名変更<commit_after>package compressor

import (
	"archive/zip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"time"
)

type ZipCompressor struct{}

func NewZipCompressor() *ZipCompressor {
	return &ZipCompressor{}
}

func (c *ZipCompressor) Compress(compressedFile io.Writer, targetDir string, files []string) error {
	w := zip.NewWriter(compressedFile)

	for _, filename := range files {
		filepath := fmt.Sprintf("%s/%s", targetDir, filename)
		info, err := os.Stat(filepath)
		if err != nil {
			return err
		}

		if info.IsDir() {
			continue
		}

		hdr, err := createZipFileHeader(filename, info)

		f, err := w.CreateHeader(hdr)
		if err != nil {
			return err
		}

		contents, _ := ioutil.ReadFile(filepath)
		_, err = f.Write(contents)
		if err != nil {
			return err
		}
	}

	if err := w.Close(); err != nil {
		return err
	}

	return nil
}

func createZipFileHeader(filename string, info os.FileInfo) (*zip.FileHeader, error) {
	hdr, err := zip.FileInfoHeader(info)
	if err != nil {
		return nil, err
	}

	hdr.Name = filename

	local := time.Now().Local()

	//現時刻のオフセットを取得
	_, offset := local.Zone()

	//差分を追加
	hdr.SetModTime(hdr.ModTime().Add(time.Duration(offset) * time.Second))

	return hdr, nil
}
<|endoftext|>


<commit_before>package aiff

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"log"
	"sync"
	"time"

	"github.com/mattetti/audio"
	"github.com/mattetti/audio/misc"
)

var (
	defaultChunkDecoderTimeout = 2 * time.Second
)

// Decoder is the wrapper structure for the AIFF container
type Decoder struct {
	r io.Reader
	// Chan is an Optional channel of chunks that is used to parse chunks
	Chan chan *Chunk
	// ChunkDecoderTimeout is the duration after which the main parser keeps going
	// if the dev hasn't reported the chunk parsing to be done.
	// By default: 2s
	ChunkDecoderTimeout time.Duration
	// The waitgroup is used to let the parser that it's ok to continue
	// after a chunk was passed to the optional parser channel.
	Wg sync.WaitGroup

	// ID is always 'FORM'. This indicates that this is a FORM chunk
	ID [4]byte
	// Size contains the size of data portion of the 'FORM' chunk.
	// Note that the data portion has been
	// broken into two parts, formType and chunks
	Size uint32
	// Format describes what's in the 'FORM' chunk. For Audio IFF files,
	// formType (aka Format) is always 'AIFF'.
	// This indicates that the chunks within the FORM pertain to sampled sound.
	Format [4]byte

	// Data coming from the COMM chunk
	commSize        uint32
	NumChans        uint16
	NumSampleFrames uint32
	SampleSize      uint16
	SampleRate      int

	// AIFC data
	Encoding     [4]byte
	EncodingName string
}

// NewDecoder creates a new reader reading the given reader and pushing audio data to the given channel.
// It is the caller's responsibility to call Close on the Decoder when done.
func NewDecoder(r io.Reader, c chan *Chunk) *Decoder {
	return &Decoder{r: r, Chan: c}
}

// Decode reads from a Read Seeker and converts the input to a PCM
// clip output.
func Decode(r io.ReadSeeker) (audio.Clipper, error) {
	d := &Decoder{r: r}
	if err := d.readHeaders(); err != nil {
		return nil, err
	}

	// read the file information to setup the audio clip
	// find the beginning of the SSND chunk and set the clip reader to it.
	clip := &audio.Clip{}

	var err error
	var rewindBytes int64
	for err != io.EOF {
		id, size, err := d.IDnSize()
		if err != nil {
			break
		}
		switch id {
		case commID:
			d.parseCommChunk(size)
			clip.Channels = int(d.NumChans)
			clip.BitDepth = int(d.SampleSize)
			clip.SampleRate = int64(d.SampleRate)
			// if we found the sound data before the COMM,
			// we need to rewind the reader so we can properly
			// set the clip reader.
			if rewindBytes > 0 {
				r.Seek(-rewindBytes, 1)
				break
			}
		case ssndID:
			clip.DataSize = int64(size)
			// if we didn't read the COMM, we are going to need to come back
			if clip.SampleRate == 0 {
				rewindBytes += int64(size)
				d.dispatchToChan(id, size)
			} else {
				break
			}
		default:
			// if we read SSN but didn't read the COMM, we need to track location
			if clip.DataSize != 0 {
				rewindBytes += int64(size)
			}
			d.dispatchToChan(id, size)
		}
	}
	clip.R = r
	return clip, nil
}

func (p *Decoder) readHeaders() error {
	if err := binary.Read(p.r, binary.BigEndian, &p.ID); err != nil {
		return err
	}
	// Must start by a FORM header/ID
	if p.ID != formID {
		return fmt.Errorf("%s - %s", ErrFmtNotSupported, p.ID)
	}

	if err := binary.Read(p.r, binary.BigEndian, &p.Size); err != nil {
		return err
	}
	if err := binary.Read(p.r, binary.BigEndian, &p.Format); err != nil {
		return err
	}

	// Must be a AIFF or AIFC form type
	if p.Format != aiffID && p.Format != aifcID {
		return fmt.Errorf("%s - %s", ErrFmtNotSupported, p.Format)
	}

	return nil
}

// Parse reads the aiff reader and populates the container structure with found information.
// The sound data or unknown chunks are passed to the optional channel if available.
func (p *Decoder) Parse() error {
	if err := p.readHeaders(); err != nil {
		return err
	}

	var err error
	for err != io.EOF {
		id, size, err := p.IDnSize()
		if err != nil {
			break
		}
		switch id {
		case commID:
			p.parseCommChunk(size)
		default:
			p.dispatchToChan(id, size)
		}
	}

	if p.Chan != nil {
		close(p.Chan)
	}

	if err == io.EOF {
		return nil
	}
	return err
}

// Frames processes the reader and returns the basic data and LPCM audio frames.
// Very naive and inneficient approach loading the entire data set in memory.
func (r *Decoder) Frames() (info *Info, frames [][]int, err error) {
	ch := make(chan *Chunk)
	r.Chan = ch
	var sndDataFrames [][]int
	go func() {
		if err := r.Parse(); err != nil {
			panic(err)
		}
	}()

	for chunk := range ch {
		if sndDataFrames == nil {
			sndDataFrames = make([][]int, r.NumSampleFrames, r.NumSampleFrames)
		}
		id := string(chunk.ID[:])
		if id == "SSND" {
			var offset uint32
			var blockSize uint32
			// TODO: BE might depend on the encoding used to generate the aiff data.
			// check encSowt or encTwos
			chunk.ReadBE(&offset)
			chunk.ReadBE(&blockSize)

			// TODO: might want to use io.NewSectionDecoder
			bufData := make([]byte, chunk.Size-8)
			chunk.ReadBE(bufData)
			buf := bytes.NewReader(bufData)

			bytesPerSample := (r.SampleSize-1)/8 + 1
			frameCount := int(r.NumSampleFrames)

			if r.NumSampleFrames == 0 {
				chunk.Done()
				continue
			}

			for i := 0; i < frameCount; i++ {
				sampleBufData := make([]byte, bytesPerSample)
				frame := make([]int, r.NumChans)

				for j := uint16(0); j < r.NumChans; j++ {
					_, err := buf.Read(sampleBufData)
					if err != nil {
						if err == io.EOF {
							break
						}
						log.Println("error reading the buffer")
						log.Fatal(err)
					}

					sampleBuf := bytes.NewBuffer(sampleBufData)
					switch r.SampleSize {
					case 8:
						var v uint8
						binary.Read(sampleBuf, binary.BigEndian, &v)
						frame[j] = int(v)
					case 16:
						var v int16
						binary.Read(sampleBuf, binary.BigEndian, &v)
						frame[j] = int(v)
					case 24:
						// TODO: check if the conversion might not be inversed depending on
						// the encoding (BE vs LE)
						var output int32
						output |= int32(sampleBufData[2]) << 0
						output |= int32(sampleBufData[1]) << 8
						output |= int32(sampleBufData[0]) << 16
						frame[j] = int(output)
					case 32:
						var v int32
						binary.Read(sampleBuf, binary.BigEndian, &v)
						frame[j] = int(v)
					default:
						// TODO: nicer error instead of crashing
						log.Fatalf("%v bitrate not supported", r.SampleSize)
					}
				}
				sndDataFrames[i] = frame

			}
		}

		chunk.Done()
	}

	duration, err := r.Duration()
	if err != nil {
		return nil, sndDataFrames, err
	}

	info = &Info{
		NumChannels: int(r.NumChans),
		SampleRate:  r.SampleRate,
		BitDepth:    int(r.SampleSize),
		Duration:    duration,
	}

	return info, sndDataFrames, err
}

func (p *Decoder) parseCommChunk(size uint32) error {
	p.commSize = size

	if err := binary.Read(p.r, binary.BigEndian, &p.NumChans); err != nil {
		return fmt.Errorf("num of channels failed to parse - %s", err.Error())
	}
	if err := binary.Read(p.r, binary.BigEndian, &p.NumSampleFrames); err != nil {
		return fmt.Errorf("num of sample frames failed to parse - %s", err.Error())
	}
	if err := binary.Read(p.r, binary.BigEndian, &p.SampleSize); err != nil {
		return fmt.Errorf("sample size failed to parse - %s", err.Error())
	}
	var srBytes [10]byte
	if err := binary.Read(p.r, binary.BigEndian, &srBytes); err != nil {
		return fmt.Errorf("sample rate failed to parse - %s", err.Error())
	}
	p.SampleRate = misc.IeeeFloatToInt(srBytes)

	if p.Format == aifcID {
		if err := binary.Read(p.r, binary.BigEndian, &p.Encoding); err != nil {
			return fmt.Errorf("AIFC encoding failed to parse - %s", err)
		}
		// pascal style string with the description of the encoding
		var size uint8
		if err := binary.Read(p.r, binary.BigEndian, &size); err != nil {
			return fmt.Errorf("AIFC encoding failed to parse - %s", err)
		}

		desc := make([]byte, size)
		if err := binary.Read(p.r, binary.BigEndian, &desc); err != nil {
			return fmt.Errorf("AIFC encoding failed to parse - %s", err)
		}
		p.EncodingName = string(desc)
	}

	return nil

}

func (p *Decoder) dispatchToChan(id [4]byte, size uint32) error {
	if p.Chan == nil {
		if err := p.jumpTo(int(size)); err != nil {
			return err
		}
		return nil
	}
	okC := make(chan bool)
	p.Wg.Add(1)
	p.Chan <- &Chunk{ID: id, Size: int(size), R: p.r, okChan: okC, Wg: &p.Wg}
	p.Wg.Wait()
	// TODO: timeout
	return nil
}

// Duration returns the time duration for the current AIFF container
func (p *Decoder) Duration() (time.Duration, error) {
	if p == nil {
		return 0, errors.New("can't calculate the duration of a nil pointer")
	}
	duration := time.Duration(float64(p.NumSampleFrames) / float64(p.SampleRate) * float64(time.Second))
	return duration, nil
}

// String implements the Stringer interface.
func (c *Decoder) String() string {
	out := fmt.Sprintf("Format: %s - ", c.Format)
	if c.Format == aifcID {
		out += fmt.Sprintf("%s - ", c.EncodingName)
	}
	if c.SampleRate != 0 {
		out += fmt.Sprintf("%d channels @ %d / %d bits - ", c.NumChans, c.SampleRate, c.SampleSize)
		d, _ := c.Duration()
		out += fmt.Sprintf("Duration: %f seconds\n", d.Seconds())
	}
	return out
}

// IDnSize returns the next ID + block size
func (c *Decoder) IDnSize() ([4]byte, uint32, error) {
	var ID [4]byte
	var blockSize uint32
	if err := binary.Read(c.r, binary.BigEndian, &ID); err != nil {
		return ID, blockSize, err
	}
	if err := binary.Read(c.r, binary.BigEndian, &blockSize); err != err {
		return ID, blockSize, err
	}
	return ID, blockSize, nil
}

// jumpTo advances the reader to the amount of bytes provided
func (c *Decoder) jumpTo(bytesAhead int) error {
	var err error
	for bytesAhead > 0 {
		readSize := bytesAhead
		if readSize > 4000 {
			readSize = 4000
		}

		buf := make([]byte, readSize)
		err = binary.Read(c.r, binary.LittleEndian, &buf)
		if err != nil {
			return nil
		}
		bytesAhead -= readSize
	}
	return nil
}
<commit_msg>use a LimitReader when reading chunks so the channel processor can get an EOF when the chunk is done being read.<commit_after>package aiff

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"log"
	"sync"
	"time"

	"github.com/mattetti/audio"
	"github.com/mattetti/audio/misc"
)

var (
	defaultChunkDecoderTimeout = 2 * time.Second
)

// Decoder is the wrapper structure for the AIFF container
type Decoder struct {
	r io.Reader
	// Chan is an Optional channel of chunks that is used to parse chunks
	Chan chan *Chunk
	// ChunkDecoderTimeout is the duration after which the main parser keeps going
	// if the dev hasn't reported the chunk parsing to be done.
	// By default: 2s
	ChunkDecoderTimeout time.Duration
	// The waitgroup is used to let the parser that it's ok to continue
	// after a chunk was passed to the optional parser channel.
	Wg sync.WaitGroup

	// ID is always 'FORM'. This indicates that this is a FORM chunk
	ID [4]byte
	// Size contains the size of data portion of the 'FORM' chunk.
	// Note that the data portion has been
	// broken into two parts, formType and chunks
	Size uint32
	// Format describes what's in the 'FORM' chunk. For Audio IFF files,
	// formType (aka Format) is always 'AIFF'.
	// This indicates that the chunks within the FORM pertain to sampled sound.
	Format [4]byte

	// Data coming from the COMM chunk
	commSize        uint32
	NumChans        uint16
	NumSampleFrames uint32
	SampleSize      uint16
	SampleRate      int

	// AIFC data
	Encoding     [4]byte
	EncodingName string
}

// NewDecoder creates a new reader reading the given reader and pushing audio data to the given channel.
// It is the caller's responsibility to call Close on the Decoder when done.
func NewDecoder(r io.Reader, c chan *Chunk) *Decoder {
	return &Decoder{r: r, Chan: c}
}

// Decode reads from a Read Seeker and converts the input to a PCM
// clip output.
func Decode(r io.ReadSeeker) (audio.Clipper, error) {
	d := &Decoder{r: r}
	if err := d.readHeaders(); err != nil {
		return nil, err
	}

	// read the file information to setup the audio clip
	// find the beginning of the SSND chunk and set the clip reader to it.
	clip := &audio.Clip{}

	var err error
	var rewindBytes int64
	for err != io.EOF {
		id, size, err := d.IDnSize()
		if err != nil {
			break
		}
		switch id {
		case commID:
			d.parseCommChunk(size)
			clip.Channels = int(d.NumChans)
			clip.BitDepth = int(d.SampleSize)
			clip.SampleRate = int64(d.SampleRate)
			// if we found the sound data before the COMM,
			// we need to rewind the reader so we can properly
			// set the clip reader.
			if rewindBytes > 0 {
				r.Seek(-rewindBytes, 1)
				break
			}
		case ssndID:
			clip.DataSize = int64(size)
			// if we didn't read the COMM, we are going to need to come back
			if clip.SampleRate == 0 {
				rewindBytes += int64(size)
				d.dispatchToChan(id, size)
			} else {
				break
			}
		default:
			// if we read SSN but didn't read the COMM, we need to track location
			if clip.DataSize != 0 {
				rewindBytes += int64(size)
			}
			d.dispatchToChan(id, size)
		}
	}
	clip.R = r
	return clip, nil
}

func (p *Decoder) readHeaders() error {
	if err := binary.Read(p.r, binary.BigEndian, &p.ID); err != nil {
		return err
	}
	// Must start by a FORM header/ID
	if p.ID != formID {
		return fmt.Errorf("%s - %s", ErrFmtNotSupported, p.ID)
	}

	if err := binary.Read(p.r, binary.BigEndian, &p.Size); err != nil {
		return err
	}
	if err := binary.Read(p.r, binary.BigEndian, &p.Format); err != nil {
		return err
	}

	// Must be a AIFF or AIFC form type
	if p.Format != aiffID && p.Format != aifcID {
		return fmt.Errorf("%s - %s", ErrFmtNotSupported, p.Format)
	}

	return nil
}

// Parse reads the aiff reader and populates the container structure with found information.
// The sound data or unknown chunks are passed to the optional channel if available.
func (p *Decoder) Parse() error {
	if err := p.readHeaders(); err != nil {
		return err
	}

	var err error
	for err != io.EOF {
		id, size, err := p.IDnSize()
		if err != nil {
			break
		}
		switch id {
		case commID:
			p.parseCommChunk(size)
		default:
			p.dispatchToChan(id, size)
		}
	}

	if p.Chan != nil {
		close(p.Chan)
	}

	if err == io.EOF {
		return nil
	}
	return err
}

// Frames processes the reader and returns the basic data and LPCM audio frames.
// Very naive and inneficient approach loading the entire data set in memory.
func (r *Decoder) Frames() (info *Info, frames [][]int, err error) {
	ch := make(chan *Chunk)
	r.Chan = ch
	var sndDataFrames [][]int
	go func() {
		if err := r.Parse(); err != nil {
			panic(err)
		}
	}()

	for chunk := range ch {
		if sndDataFrames == nil {
			sndDataFrames = make([][]int, r.NumSampleFrames, r.NumSampleFrames)
		}
		id := string(chunk.ID[:])
		if id == "SSND" {
			var offset uint32
			var blockSize uint32
			// TODO: BE might depend on the encoding used to generate the aiff data.
			// check encSowt or encTwos
			chunk.ReadBE(&offset)
			chunk.ReadBE(&blockSize)

			// TODO: might want to use io.NewSectionDecoder
			bufData := make([]byte, chunk.Size-8)
			chunk.ReadBE(bufData)
			buf := bytes.NewReader(bufData)

			bytesPerSample := (r.SampleSize-1)/8 + 1
			frameCount := int(r.NumSampleFrames)

			if r.NumSampleFrames == 0 {
				chunk.Done()
				continue
			}

			for i := 0; i < frameCount; i++ {
				sampleBufData := make([]byte, bytesPerSample)
				frame := make([]int, r.NumChans)

				for j := uint16(0); j < r.NumChans; j++ {
					_, err := buf.Read(sampleBufData)
					if err != nil {
						if err == io.EOF {
							break
						}
						log.Println("error reading the buffer")
						log.Fatal(err)
					}

					sampleBuf := bytes.NewBuffer(sampleBufData)
					switch r.SampleSize {
					case 8:
						var v uint8
						binary.Read(sampleBuf, binary.BigEndian, &v)
						frame[j] = int(v)
					case 16:
						var v int16
						binary.Read(sampleBuf, binary.BigEndian, &v)
						frame[j] = int(v)
					case 24:
						// TODO: check if the conversion might not be inversed depending on
						// the encoding (BE vs LE)
						var output int32
						output |= int32(sampleBufData[2]) << 0
						output |= int32(sampleBufData[1]) << 8
						output |= int32(sampleBufData[0]) << 16
						frame[j] = int(output)
					case 32:
						var v int32
						binary.Read(sampleBuf, binary.BigEndian, &v)
						frame[j] = int(v)
					default:
						// TODO: nicer error instead of crashing
						log.Fatalf("%v bitrate not supported", r.SampleSize)
					}
				}
				sndDataFrames[i] = frame

			}
		}

		chunk.Done()
	}

	duration, err := r.Duration()
	if err != nil {
		return nil, sndDataFrames, err
	}

	info = &Info{
		NumChannels: int(r.NumChans),
		SampleRate:  r.SampleRate,
		BitDepth:    int(r.SampleSize),
		Duration:    duration,
	}

	return info, sndDataFrames, err
}

func (p *Decoder) parseCommChunk(size uint32) error {
	p.commSize = size

	if err := binary.Read(p.r, binary.BigEndian, &p.NumChans); err != nil {
		return fmt.Errorf("num of channels failed to parse - %s", err.Error())
	}
	if err := binary.Read(p.r, binary.BigEndian, &p.NumSampleFrames); err != nil {
		return fmt.Errorf("num of sample frames failed to parse - %s", err.Error())
	}
	if err := binary.Read(p.r, binary.BigEndian, &p.SampleSize); err != nil {
		return fmt.Errorf("sample size failed to parse - %s", err.Error())
	}
	var srBytes [10]byte
	if err := binary.Read(p.r, binary.BigEndian, &srBytes); err != nil {
		return fmt.Errorf("sample rate failed to parse - %s", err.Error())
	}
	p.SampleRate = misc.IeeeFloatToInt(srBytes)

	if p.Format == aifcID {
		if err := binary.Read(p.r, binary.BigEndian, &p.Encoding); err != nil {
			return fmt.Errorf("AIFC encoding failed to parse - %s", err)
		}
		// pascal style string with the description of the encoding
		var size uint8
		if err := binary.Read(p.r, binary.BigEndian, &size); err != nil {
			return fmt.Errorf("AIFC encoding failed to parse - %s", err)
		}

		desc := make([]byte, size)
		if err := binary.Read(p.r, binary.BigEndian, &desc); err != nil {
			return fmt.Errorf("AIFC encoding failed to parse - %s", err)
		}
		p.EncodingName = string(desc)
	}

	return nil

}

func (p *Decoder) dispatchToChan(id [4]byte, size uint32) error {
	if p.Chan == nil {
		if err := p.jumpTo(int(size)); err != nil {
			return err
		}
		return nil
	}
	okC := make(chan bool)
	p.Wg.Add(1)
	p.Chan <- &Chunk{
		ID:     id,
		Size:   int(size),
		R:      io.LimitReader(p.r, int64(size)),
		okChan: okC,
		Wg:     &p.Wg,
	}
	p.Wg.Wait()
	// TODO: timeout
	return nil
}

// Duration returns the time duration for the current AIFF container
func (p *Decoder) Duration() (time.Duration, error) {
	if p == nil {
		return 0, errors.New("can't calculate the duration of a nil pointer")
	}
	duration := time.Duration(float64(p.NumSampleFrames) / float64(p.SampleRate) * float64(time.Second))
	return duration, nil
}

// String implements the Stringer interface.
func (c *Decoder) String() string {
	out := fmt.Sprintf("Format: %s - ", c.Format)
	if c.Format == aifcID {
		out += fmt.Sprintf("%s - ", c.EncodingName)
	}
	if c.SampleRate != 0 {
		out += fmt.Sprintf("%d channels @ %d / %d bits - ", c.NumChans, c.SampleRate, c.SampleSize)
		d, _ := c.Duration()
		out += fmt.Sprintf("Duration: %f seconds\n", d.Seconds())
	}
	return out
}

// IDnSize returns the next ID + block size
func (c *Decoder) IDnSize() ([4]byte, uint32, error) {
	var ID [4]byte
	var blockSize uint32
	if err := binary.Read(c.r, binary.BigEndian, &ID); err != nil {
		return ID, blockSize, err
	}
	if err := binary.Read(c.r, binary.BigEndian, &blockSize); err != err {
		return ID, blockSize, err
	}
	return ID, blockSize, nil
}

// jumpTo advances the reader to the amount of bytes provided
func (c *Decoder) jumpTo(bytesAhead int) error {
	var err error
	for bytesAhead > 0 {
		readSize := bytesAhead
		if readSize > 4000 {
			readSize = 4000
		}

		buf := make([]byte, readSize)
		err = binary.Read(c.r, binary.LittleEndian, &buf)
		if err != nil {
			return nil
		}
		bytesAhead -= readSize
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"

	"github.com/cockroachdb/examples-orms/go/gopg/model"
	"github.com/go-pg/pg/v9"
	"github.com/go-pg/pg/v9/orm"
	"github.com/julienschmidt/httprouter"
)

var (
	addr = flag.String("addr", "postgresql://root@localhost:26257/company_gopg?sslmode=disable", "the address of the database")
)

func main() {
	flag.Parse()

	db := setupDB(*addr)
	defer db.Close()

	router := httprouter.New()

	server := NewServer(db)
	server.RegisterRouter(router)

	log.Fatal(http.ListenAndServe(":6543", router))
}

func setupDB(addr string) *pg.DB {
	opt, err := pg.ParseURL(addr)
	if err != nil {
		panic(fmt.Sprintf("failed to parse addr URL: %v", err))
	}
	db := pg.Connect(opt)
	for _, model := range []interface{}{
		(*model.Customer)(nil),
		(*model.Order)(nil),
		(*model.Product)(nil),
		(*model.OrderProduct)(nil),
	} {
		err := db.CreateTable(model, &orm.CreateTableOptions{
			IfNotExists:   true,
			FKConstraints: true,
		})
		if err != nil {
			panic(fmt.Sprintf("failed to create a table: %v", err))
		}
	}
	return db
}
<commit_msg>gopg: print addr on error<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"

	"github.com/cockroachdb/examples-orms/go/gopg/model"
	"github.com/go-pg/pg/v9"
	"github.com/go-pg/pg/v9/orm"
	"github.com/julienschmidt/httprouter"
)

var (
	addr = flag.String("addr", "postgresql://root@localhost:26257/company_gopg?sslmode=disable", "the address of the database")
)

func main() {
	flag.Parse()

	db := setupDB(*addr)
	defer db.Close()

	router := httprouter.New()

	server := NewServer(db)
	server.RegisterRouter(router)

	log.Fatal(http.ListenAndServe(":6543", router))
}

func setupDB(addr string) *pg.DB {
	opt, err := pg.ParseURL(addr)
	if err != nil {
		panic(fmt.Sprintf("failed to parse addr URL %s: %v", addr, err))
	}
	db := pg.Connect(opt)
	for _, model := range []interface{}{
		(*model.Customer)(nil),
		(*model.Order)(nil),
		(*model.Product)(nil),
		(*model.OrderProduct)(nil),
	} {
		err := db.CreateTable(model, &orm.CreateTableOptions{
			IfNotExists:   true,
			FKConstraints: true,
		})
		if err != nil {
			panic(fmt.Sprintf("failed to create a table: %v", err))
		}
	}
	return db
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
	"net/http"

	"google.golang.org/grpc"

	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms"
	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms/mappers"
	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms/reducers"
	"github.com/apoydence/loggrebutterfly/analyst/internal/config"
	"github.com/apoydence/loggrebutterfly/analyst/internal/filesystem"
	"github.com/apoydence/loggrebutterfly/analyst/internal/network"
	"github.com/apoydence/loggrebutterfly/analyst/internal/network/intra"
	"github.com/apoydence/loggrebutterfly/analyst/internal/network/server"
	apiintra "github.com/apoydence/loggrebutterfly/api/intra"
	v1 "github.com/apoydence/loggrebutterfly/api/v1"
	"github.com/apoydence/mapreduce"
	"github.com/apoydence/talaria/api/v1"
)

func main() {
	log.Printf("Starting analyst...")
	defer log.Printf("Closing analyst.")

	conf := config.Load()

	nodeClient := setupTalariaNodeClient(conf.TalariaNodeAddr)
	schedClient := setupTalariaSchedulerClient(conf.TalariaSchedulerAddr)

	algFetcher := setupAlgorithmFetcher()
	hasher := filesystem.NewHasher()
	filter := filesystem.NewRouteFilter(hasher)
	fs := filesystem.New(filter, schedClient, nodeClient, conf.ToAnalyst)
	network := network.New()

	mr := mapreduce.New(fs, network, algFetcher)
	exec := mapreduce.NewExecutor(algFetcher, fs)

	go startIntraServer(intra.New(exec), conf.IntraAddr)
	go startServer(server.New(mr), conf.Addr)

	log.Printf("Starting pprof on %s.", conf.PprofAddr)
	log.Println(http.ListenAndServe(conf.PprofAddr, nil))
}

func setupAlgorithmFetcher() *algorithms.Fetcher {
	return algorithms.NewFetcher(map[string]algorithms.AlgBuilder{
		"timerange": algorithms.AlgBuilder(func(info *v1.QueryInfo) mapreduce.Algorithm {
			return mapreduce.Algorithm{
				Mapper:  mappers.NewTimeRange(info),
				Reducer: reducers.NewFirst(),
			}
		}),
	})
}

func setupTalariaNodeClient(addr string) talaria.NodeClient {
	conn, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect to talaria: %s", err)
	}
	return talaria.NewNodeClient(conn)
}

func setupTalariaSchedulerClient(addr string) talaria.SchedulerClient {
	conn, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect to talaria: %s", err)
	}
	return talaria.NewSchedulerClient(conn)
}

func startIntraServer(server *intra.Server, addr string) {
	log.Printf("Starting intra server (addr=%s)...", addr)

	lis, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	apiintra.RegisterAnalystServer(s, server)
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve intra: %s", err)
	}
}

func startServer(server *server.Server, addr string) {
	log.Printf("Starting server (addr=%s)...", addr)

	lis, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	v1.RegisterAnalystServer(s, server)
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve intra: %s", err)
	}
}
<commit_msg>Set analyst IPs to IPv4<commit_after>package main

import (
	"log"
	"net"
	"net/http"

	"google.golang.org/grpc"

	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms"
	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms/mappers"
	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms/reducers"
	"github.com/apoydence/loggrebutterfly/analyst/internal/config"
	"github.com/apoydence/loggrebutterfly/analyst/internal/filesystem"
	"github.com/apoydence/loggrebutterfly/analyst/internal/network"
	"github.com/apoydence/loggrebutterfly/analyst/internal/network/intra"
	"github.com/apoydence/loggrebutterfly/analyst/internal/network/server"
	apiintra "github.com/apoydence/loggrebutterfly/api/intra"
	v1 "github.com/apoydence/loggrebutterfly/api/v1"
	"github.com/apoydence/mapreduce"
	"github.com/apoydence/talaria/api/v1"
)

func main() {
	log.Printf("Starting analyst...")
	defer log.Printf("Closing analyst.")

	conf := config.Load()

	nodeClient := setupTalariaNodeClient(conf.TalariaNodeAddr)
	schedClient := setupTalariaSchedulerClient(conf.TalariaSchedulerAddr)

	algFetcher := setupAlgorithmFetcher()
	hasher := filesystem.NewHasher()
	filter := filesystem.NewRouteFilter(hasher)
	fs := filesystem.New(filter, schedClient, nodeClient, conf.ToAnalyst)
	network := network.New()

	mr := mapreduce.New(fs, network, algFetcher)
	exec := mapreduce.NewExecutor(algFetcher, fs)

	go startIntraServer(intra.New(exec), conf.IntraAddr)
	go startServer(server.New(mr), conf.Addr)

	log.Printf("Starting pprof on %s.", conf.PprofAddr)
	log.Println(http.ListenAndServe(conf.PprofAddr, nil))
}

func setupAlgorithmFetcher() *algorithms.Fetcher {
	return algorithms.NewFetcher(map[string]algorithms.AlgBuilder{
		"timerange": algorithms.AlgBuilder(func(info *v1.QueryInfo) mapreduce.Algorithm {
			return mapreduce.Algorithm{
				Mapper:  mappers.NewTimeRange(info),
				Reducer: reducers.NewFirst(),
			}
		}),
	})
}

func setupTalariaNodeClient(addr string) talaria.NodeClient {
	conn, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect to talaria: %s", err)
	}
	return talaria.NewNodeClient(conn)
}

func setupTalariaSchedulerClient(addr string) talaria.SchedulerClient {
	conn, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect to talaria: %s", err)
	}
	return talaria.NewSchedulerClient(conn)
}

func startIntraServer(server *intra.Server, addr string) {
	log.Printf("Starting intra server (addr=%s)...", addr)

	lis, err := net.Listen("tcp4", addr)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	apiintra.RegisterAnalystServer(s, server)
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve intra: %s", err)
	}
}

func startServer(server *server.Server, addr string) {
	log.Printf("Starting server (addr=%s)...", addr)

	lis, err := net.Listen("tcp4", addr)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	v1.RegisterAnalystServer(s, server)
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve intra: %s", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package types declares the data types and implements
// the algorithms for type-checking of Go packages.
// Use Check and Config.Check to invoke the type-checker.
//
// Type-checking consists of several interdependent phases:
//
// Name resolution maps each identifier (ast.Ident) in the program to the
// language object (Object) it denotes.
// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
//
// Constant folding computes the exact constant value (exact.Value) for
// every expression (ast.Expr) that is a compile-time constant.
// Use Info.Types[expr].Value for the results of constant folding.
//
// Type inference computes the type (Type) of every expression (ast.Expr)
// and checks for compliance with the language specification.
// Use Info.Types[expr].Type for the results of type inference.
//
package types

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"

	"code.google.com/p/go.tools/go/exact"
)

// Check type-checks a package and returns the resulting complete package
// object, or a nil package and the first error. The package is specified
// by a list of *ast.Files and corresponding file set, and the import path
// the package is identified with. The clean path must not be empty or dot (".").
//
// For more control over type-checking and results, use Config.Check.
func Check(path string, fset *token.FileSet, files []*ast.File) (*Package, error) {
	var conf Config
	pkg, err := conf.Check(path, fset, files, nil)
	if err != nil {
		return nil, err
	}
	return pkg, nil
}

// An Error describes a type-checking error; it implements the error interface.
// A "soft" error is an error that still permits a valid interpretation of a
// package (such as "unused variable"); "hard" errors may lead to unpredictable
// behavior if ignored.
type Error struct {
	Fset *token.FileSet // file set for interpretation of Pos
	Pos  token.Pos      // error position
	Msg  string         // error message
	Soft bool           // if set, error is "soft"
}

// Error returns an error string formatted as follows:
// filename:line:column: message
func (err Error) Error() string {
	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
}

// An importer resolves import paths to Packages.
// The imports map records packages already known,
// indexed by package path. The type-checker
// will invoke Import with Config.Packages.
// An importer must determine the canonical package path and
// check imports to see if it is already present in the map.
// If so, the Importer can return the map entry.  Otherwise,
// the importer must load the package data for the given path
// into a new *Package, record it in imports map, and return
// the package.
// TODO(gri) Need to be clearer about requirements of completeness.
type Importer func(map[string]*Package, string) (*Package, error)

// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
	// If IgnoreFuncBodies is set, function bodies are not
	// type-checked.
	IgnoreFuncBodies bool

	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
	// declares an empty "C" package and errors are omitted for qualified
	// identifiers referring to package C (which won't find an object).
	// This feature is intended for the standard library cmd/api tool.
	//
	// Caution: Effects may be unpredictable due to follow-up errors.
	//          Do not use casually!
	FakeImportC bool

	// Packages is used to look up (and thus canonicalize) packages by
	// package path. If Packages is nil, it is set to a new empty map.
	// During type-checking, imported packages are added to the map.
	Packages map[string]*Package

	// If Error != nil, it is called with each error found
	// during type checking; err has dynamic type Error.
	// Secondary errors (for instance, to enumerate all types
	// involved in an invalid recursive type declaration) have
	// error strings that start with a '\t' character.
	Error func(err error)

	// If Import != nil, it is called for each imported package.
	// Otherwise, DefaultImport is called.
	Import Importer

	// If Sizes != nil, it provides the sizing functions for package unsafe.
	// Otherwise &StdSize{WordSize: 8, MaxAlign: 8} is used instead.
	Sizes Sizes
}

// DefaultImport is the default importer invoked if Config.Import == nil.
// The declaration:
//
//	import _ "code.google.com/p/go.tools/go/gcimporter"
//
// in a client of go/types will initialize DefaultImport to gcimporter.Import.
var DefaultImport Importer

type TypeAndValue struct {
	Type  Type
	Value exact.Value
}

// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
	// Types maps expressions to their types, and for constant
	// expressions, their values.
	// Identifiers are collected in Defs and Uses, not Types.
	//
	// For an expression denoting a predeclared built-in function
	// the recorded signature is call-site specific. If the call
	// result is not a constant, the recorded type is an argument-
	// specific signature. Otherwise, the recorded type is invalid.
	Types map[ast.Expr]TypeAndValue

	// Defs maps identifiers to the objects they define (including
	// package names, dots "." of dot-imports, and blank "_" identifiers).
	// For identifiers that do not denote objects (e.g., the package name
	// in package clauses, blank identifiers on the lhs of assignments, or
	// symbolic variables t in t := x.(type) of type switch headers), the
	// corresponding objects are nil.
	//
	// For an anonymous field, Defs returns the field *Var it defines.
	//
	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
	Defs map[*ast.Ident]Object

	// Uses maps identifiers to the objects they denote.
	//
	// For an anonymous field, Uses returns the *TypeName it denotes.
	//
	// Invariant: Uses[id].Pos() != id.Pos()
	Uses map[*ast.Ident]Object

	// Implicits maps nodes to their implicitly declared objects, if any.
	// The following node and object types may appear:
	//
	//	node               declared object
	//
	//	*ast.ImportSpec    *PkgName for dot-imports and imports without renames
	//	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
	//      *ast.Field         anonymous struct field or parameter *Var
	//
	Implicits map[ast.Node]Object

	// Selections maps selector expressions to their corresponding selections.
	Selections map[*ast.SelectorExpr]*Selection

	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
	// associated with a specific node but with all files belonging to a package.
	// Thus, the package scope can be found in the type-checked Package object.
	// Scopes nest, with the Universe scope being the outermost scope, enclosing
	// the package scope, which contains (one or more) files scopes, which enclose
	// function scopes which in turn enclose statement and function literal scopes.
	// Note that even though package-level functions are declared in the package
	// scope, the function scopes are embedded in the file scope of the file
	// containing the function declaration.
	//
	// The following node types may appear in Scopes:
	//
	//	*ast.File
	//	*ast.FuncType
	//	*ast.BlockStmt
	//	*ast.IfStmt
	//	*ast.SwitchStmt
	//	*ast.TypeSwitchStmt
	//	*ast.CaseClause
	//	*ast.CommClause
	//	*ast.ForStmt
	//	*ast.RangeStmt
	//
	Scopes map[ast.Node]*Scope

	// InitOrder is the list of package-level initializers in the order in which
	// they must be executed. Initializers referring to variables related by an
	// initialization dependency appear in topological order, the others appear
	// in source order. Variables without an initialization expression do not
	// appear in this list.
	InitOrder []*Initializer
}

// An Initializer describes a package-level variable, or a list of variables in case
// of a multi-valued initialization expression, and the corresponding initialization
// expression.
type Initializer struct {
	Lhs []*Var // var Lhs = Rhs
	Rhs ast.Expr
}

func (init *Initializer) String() string {
	var buf bytes.Buffer
	for i, lhs := range init.Lhs {
		if i > 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(lhs.Name())
	}
	buf.WriteString(" = ")
	WriteExpr(&buf, init.Rhs)
	return buf.String()
}

// Check type-checks a package and returns the resulting package object,
// the first error if any, and if info != nil, additional type information.
// The package is marked as complete if no errors occurred, otherwise it is
// incomplete.
//
// The package is specified by a list of *ast.Files and corresponding
// file set, and the package path the package is identified with.
// The clean path must not be empty or dot (".").
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
	pkg := NewPackage(path, "")
	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
}

// AssertableTo reports whether a value of type V can be asserted to have type T.
func AssertableTo(V *Interface, T Type) bool {
	f, _ := MissingMethod(T, V, false)
	return f == nil
}

// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.assignableTo(nil, T) // config not needed for non-constant x
}

// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
func ConvertibleTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.convertibleTo(nil, T) // config not needed for non-constant x
}

// Implements reports whether type V implements interface T.
func Implements(V Type, T *Interface) bool {
	f, _ := MissingMethod(V, T, true)
	return f == nil
}
<commit_msg>go.tools/go/types: fix doc comment<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package types declares the data types and implements
// the algorithms for type-checking of Go packages.
// Use Check and Config.Check to invoke the type-checker.
//
// Type-checking consists of several interdependent phases:
//
// Name resolution maps each identifier (ast.Ident) in the program to the
// language object (Object) it denotes.
// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
//
// Constant folding computes the exact constant value (exact.Value) for
// every expression (ast.Expr) that is a compile-time constant.
// Use Info.Types[expr].Value for the results of constant folding.
//
// Type inference computes the type (Type) of every expression (ast.Expr)
// and checks for compliance with the language specification.
// Use Info.Types[expr].Type for the results of type inference.
//
package types

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"

	"code.google.com/p/go.tools/go/exact"
)

// Check type-checks a package and returns the resulting complete package
// object, or a nil package and the first error. The package is specified
// by a list of *ast.Files and corresponding file set, and the import path
// the package is identified with. The clean path must not be empty or dot (".").
//
// For more control over type-checking and results, use Config.Check.
func Check(path string, fset *token.FileSet, files []*ast.File) (*Package, error) {
	var conf Config
	pkg, err := conf.Check(path, fset, files, nil)
	if err != nil {
		return nil, err
	}
	return pkg, nil
}

// An Error describes a type-checking error; it implements the error interface.
// A "soft" error is an error that still permits a valid interpretation of a
// package (such as "unused variable"); "hard" errors may lead to unpredictable
// behavior if ignored.
type Error struct {
	Fset *token.FileSet // file set for interpretation of Pos
	Pos  token.Pos      // error position
	Msg  string         // error message
	Soft bool           // if set, error is "soft"
}

// Error returns an error string formatted as follows:
// filename:line:column: message
func (err Error) Error() string {
	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
}

// An importer resolves import paths to Packages.
// The imports map records packages already known,
// indexed by package path. The type-checker
// will invoke Import with Config.Packages.
// An importer must determine the canonical package path and
// check imports to see if it is already present in the map.
// If so, the Importer can return the map entry.  Otherwise,
// the importer must load the package data for the given path
// into a new *Package, record it in imports map, and return
// the package.
// TODO(gri) Need to be clearer about requirements of completeness.
type Importer func(map[string]*Package, string) (*Package, error)

// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
	// If IgnoreFuncBodies is set, function bodies are not
	// type-checked.
	IgnoreFuncBodies bool

	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
	// declares an empty "C" package and errors are omitted for qualified
	// identifiers referring to package C (which won't find an object).
	// This feature is intended for the standard library cmd/api tool.
	//
	// Caution: Effects may be unpredictable due to follow-up errors.
	//          Do not use casually!
	FakeImportC bool

	// Packages is used to look up (and thus canonicalize) packages by
	// package path. If Packages is nil, it is set to a new empty map.
	// During type-checking, imported packages are added to the map.
	Packages map[string]*Package

	// If Error != nil, it is called with each error found
	// during type checking; err has dynamic type Error.
	// Secondary errors (for instance, to enumerate all types
	// involved in an invalid recursive type declaration) have
	// error strings that start with a '\t' character.
	Error func(err error)

	// If Import != nil, it is called for each imported package.
	// Otherwise, DefaultImport is called.
	Import Importer

	// If Sizes != nil, it provides the sizing functions for package unsafe.
	// Otherwise &StdSize{WordSize: 8, MaxAlign: 8} is used instead.
	Sizes Sizes
}

// DefaultImport is the default importer invoked if Config.Import == nil.
// The declaration:
//
//	import _ "code.google.com/p/go.tools/go/gcimporter"
//
// in a client of go/types will initialize DefaultImport to gcimporter.Import.
var DefaultImport Importer

type TypeAndValue struct {
	Type  Type
	Value exact.Value
}

// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
	// Types maps expressions to their types, and for constant
	// expressions, their values.
	// Identifiers are collected in Defs and Uses, not Types.
	//
	// For an expression denoting a predeclared built-in function
	// the recorded signature is call-site specific. If the call
	// result is not a constant, the recorded type is an argument-
	// specific signature. Otherwise, the recorded type is invalid.
	Types map[ast.Expr]TypeAndValue

	// Defs maps identifiers to the objects they define (including
	// package names, dots "." of dot-imports, and blank "_" identifiers).
	// For identifiers that do not denote objects (e.g., the package name
	// in package clauses, or symbolic variables t in t := x.(type) of
	// type switch headers), the corresponding objects are nil.
	//
	// For an anonymous field, Defs returns the field *Var it defines.
	//
	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
	Defs map[*ast.Ident]Object

	// Uses maps identifiers to the objects they denote.
	//
	// For an anonymous field, Uses returns the *TypeName it denotes.
	//
	// Invariant: Uses[id].Pos() != id.Pos()
	Uses map[*ast.Ident]Object

	// Implicits maps nodes to their implicitly declared objects, if any.
	// The following node and object types may appear:
	//
	//	node               declared object
	//
	//	*ast.ImportSpec    *PkgName for dot-imports and imports without renames
	//	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
	//      *ast.Field         anonymous struct field or parameter *Var
	//
	Implicits map[ast.Node]Object

	// Selections maps selector expressions to their corresponding selections.
	Selections map[*ast.SelectorExpr]*Selection

	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
	// associated with a specific node but with all files belonging to a package.
	// Thus, the package scope can be found in the type-checked Package object.
	// Scopes nest, with the Universe scope being the outermost scope, enclosing
	// the package scope, which contains (one or more) files scopes, which enclose
	// function scopes which in turn enclose statement and function literal scopes.
	// Note that even though package-level functions are declared in the package
	// scope, the function scopes are embedded in the file scope of the file
	// containing the function declaration.
	//
	// The following node types may appear in Scopes:
	//
	//	*ast.File
	//	*ast.FuncType
	//	*ast.BlockStmt
	//	*ast.IfStmt
	//	*ast.SwitchStmt
	//	*ast.TypeSwitchStmt
	//	*ast.CaseClause
	//	*ast.CommClause
	//	*ast.ForStmt
	//	*ast.RangeStmt
	//
	Scopes map[ast.Node]*Scope

	// InitOrder is the list of package-level initializers in the order in which
	// they must be executed. Initializers referring to variables related by an
	// initialization dependency appear in topological order, the others appear
	// in source order. Variables without an initialization expression do not
	// appear in this list.
	InitOrder []*Initializer
}

// An Initializer describes a package-level variable, or a list of variables in case
// of a multi-valued initialization expression, and the corresponding initialization
// expression.
type Initializer struct {
	Lhs []*Var // var Lhs = Rhs
	Rhs ast.Expr
}

func (init *Initializer) String() string {
	var buf bytes.Buffer
	for i, lhs := range init.Lhs {
		if i > 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(lhs.Name())
	}
	buf.WriteString(" = ")
	WriteExpr(&buf, init.Rhs)
	return buf.String()
}

// Check type-checks a package and returns the resulting package object,
// the first error if any, and if info != nil, additional type information.
// The package is marked as complete if no errors occurred, otherwise it is
// incomplete.
//
// The package is specified by a list of *ast.Files and corresponding
// file set, and the package path the package is identified with.
// The clean path must not be empty or dot (".").
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
	pkg := NewPackage(path, "")
	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
}

// AssertableTo reports whether a value of type V can be asserted to have type T.
func AssertableTo(V *Interface, T Type) bool {
	f, _ := MissingMethod(T, V, false)
	return f == nil
}

// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.assignableTo(nil, T) // config not needed for non-constant x
}

// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
func ConvertibleTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.convertibleTo(nil, T) // config not needed for non-constant x
}

// Implements reports whether type V implements interface T.
func Implements(V Type, T *Interface) bool {
	f, _ := MissingMethod(V, T, true)
	return f == nil
}
<|endoftext|>


<commit_before>package gobreak

import (
	"context"
	"errors"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestDo(t *testing.T) {
	ctx := context.TODO()
	err := Do(ctx, "test do", func(context.Context) error {
		return nil
	}, nil)
	assert.Nil(t, err)

	err = Do(ctx, "test do", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("failed"), err)

	err = Do(ctx, "test do", func(context.Context) error {
		return errors.New("failed")
	}, func(context.Context, error) error {
		return nil
	})
	assert.Nil(t, err)

	err = Do(ctx, "test do", func(context.Context) error {
		return errors.New("failed")
	}, func(context.Context, error) error {
		return errors.New("fallback")
	})
	assert.Equal(t, errors.New("fallback"), err)

	err = Do(ctx, "test do", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("circuit breaker is open"), err)
}

func TestDoDelay(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)
	defer cancel()
	err := Do(ctx, "delay", func(context.Context) error {
		time.Sleep(2 * time.Second)
		return nil
	}, nil)
	assert.Equal(t, context.DeadlineExceeded, err)
}

func TestGoCancel(t *testing.T) {
	ctx, cancel := context.WithCancel(context.TODO())
	err := Go(ctx, "go cancel", func(context.Context) error {
		time.Sleep(1 * time.Second)
		return nil
	}, nil)
	cancel()
	assert.Equal(t, context.Canceled, <-err)
}

func TestDoPanic(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Do(ctx, "TestDoPanic", func(context.Context) error {
		panic("panic")
		return nil
	}, nil)

	assert.Equal(t, errors.New("command panics"), err)
	t.Fail()
}

func TestGo(t *testing.T) {
	ctx := context.TODO()
	err := Go(ctx, "test go", func(context.Context) error {
		return nil
	}, nil)
	assert.Nil(t, <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("failed"), <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, func(context.Context, error) error {
		return nil
	})
	assert.Nil(t, <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, func(context.Context, error) error {
		return errors.New("fallback")
	})
	assert.Equal(t, errors.New("fallback"), <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("circuit breaker is open"), <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("circuit breaker is open"), <-err)
}
func TestGoNormal(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 2*time.Second)
	err := Go(ctx, "normal", func(context.Context) error {
		time.Sleep(1 * time.Second)
		return nil
	}, nil)

	assert.Equal(t, nil, <-err)
}

func TestGoDelay(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Go(ctx, "delay", func(context.Context) error {
		time.Sleep(2 * time.Second)
		return nil
	}, nil)

	assert.Equal(t, context.DeadlineExceeded, <-err)
}

func TestGoDelayFallback(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Go(ctx, "delay and fallback", func(context.Context) error {
		time.Sleep(2 * time.Second)
		return nil
	}, func(context.Context, error) error {
		return nil
	})

	assert.Equal(t, nil, <-err)
}

func TestGoPanic(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Go(ctx, "panic", func(context.Context) error {
		panic("panic")
		return nil
	}, nil)

	assert.Equal(t, errors.New("command panics"), <-err)
}

func TestGoPanicFallBack(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Go(ctx, "panic and fallback", func(context.Context) error {
		panic("panic")
		return nil
	}, func(context.Context, error) error {
		return errors.New("fallback")
	})

	assert.Equal(t, errors.New("fallback"), <-err)
}

func BenchmarkNormal(b *testing.B) {
	for i := 0; i < b.N; i++ {
		func() error {
			return nil
		}()
	}
}

func BenchmarkDo(b *testing.B) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	for i := 0; i < b.N; i++ {
		Do(ctx, "test", func(context.Context) error {
			return nil
		}, nil)
	}
}

func BenchmarkGo(b *testing.B) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	for i := 0; i < b.N; i++ {
		<-Go(ctx, "test", func(context.Context) error {
			return nil
		}, nil)
	}
}

func BenchmarkDoFail(b *testing.B) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	for i := 0; i < b.N; i++ {
		Do(ctx, "test", func(context.Context) error {
			return errors.New("fail")
		}, nil)
	}
}

func BenchmarkGoFail(b *testing.B) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	for i := 0; i < b.N; i++ {
		<-Go(ctx, "test", func(context.Context) error {
			return errors.New("fail")
		}, nil)
	}
}
<commit_msg>fix test case<commit_after>package gobreak

import (
	"context"
	"errors"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestDo(t *testing.T) {
	ctx := context.TODO()
	err := Do(ctx, "test do", func(context.Context) error {
		return nil
	}, nil)
	assert.Nil(t, err)

	err = Do(ctx, "test do", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("failed"), err)

	err = Do(ctx, "test do", func(context.Context) error {
		return errors.New("failed")
	}, func(context.Context, error) error {
		return nil
	})
	assert.Nil(t, err)

	err = Do(ctx, "test do", func(context.Context) error {
		return errors.New("failed")
	}, func(context.Context, error) error {
		return errors.New("fallback")
	})
	assert.Equal(t, errors.New("fallback"), err)

	err = Do(ctx, "test do", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("circuit breaker is open"), err)
}

func TestDoDelay(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)
	defer cancel()
	err := Do(ctx, "delay", func(context.Context) error {
		time.Sleep(2 * time.Second)
		return nil
	}, nil)
	assert.Equal(t, context.DeadlineExceeded, err)
}

func TestGoCancel(t *testing.T) {
	ctx, cancel := context.WithCancel(context.TODO())
	err := Go(ctx, "go cancel", func(context.Context) error {
		time.Sleep(1 * time.Second)
		return nil
	}, nil)
	cancel()
	assert.Equal(t, context.Canceled, <-err)
}

func TestDoPanic(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Do(ctx, "TestDoPanic", func(context.Context) error {
		panic("panic")
		return nil
	}, nil)

	assert.Equal(t, errors.New("command panics"), err)
}

func TestGo(t *testing.T) {
	ctx := context.TODO()
	err := Go(ctx, "test go", func(context.Context) error {
		return nil
	}, nil)
	assert.Nil(t, <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("failed"), <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, func(context.Context, error) error {
		return nil
	})
	assert.Nil(t, <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, func(context.Context, error) error {
		return errors.New("fallback")
	})
	assert.Equal(t, errors.New("fallback"), <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("circuit breaker is open"), <-err)

	err = Go(ctx, "test go", func(context.Context) error {
		return errors.New("failed")
	}, nil)
	assert.Equal(t, errors.New("circuit breaker is open"), <-err)
}
func TestGoNormal(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 2*time.Second)
	err := Go(ctx, "normal", func(context.Context) error {
		time.Sleep(1 * time.Second)
		return nil
	}, nil)

	assert.Equal(t, nil, <-err)
}

func TestGoDelay(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Go(ctx, "delay", func(context.Context) error {
		time.Sleep(2 * time.Second)
		return nil
	}, nil)

	assert.Equal(t, context.DeadlineExceeded, <-err)
}

func TestGoDelayFallback(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Go(ctx, "delay and fallback", func(context.Context) error {
		time.Sleep(2 * time.Second)
		return nil
	}, func(context.Context, error) error {
		return nil
	})

	assert.Equal(t, nil, <-err)
}

func TestGoPanic(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Go(ctx, "panic", func(context.Context) error {
		panic("panic")
		return nil
	}, nil)

	assert.Equal(t, errors.New("command panics"), <-err)
}

func TestGoPanicFallBack(t *testing.T) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	err := Go(ctx, "panic and fallback", func(context.Context) error {
		panic("panic")
		return nil
	}, func(context.Context, error) error {
		return errors.New("fallback")
	})

	assert.Equal(t, errors.New("fallback"), <-err)
}

func BenchmarkNormal(b *testing.B) {
	for i := 0; i < b.N; i++ {
		func() error {
			return nil
		}()
	}
}

func BenchmarkDo(b *testing.B) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	for i := 0; i < b.N; i++ {
		Do(ctx, "test", func(context.Context) error {
			return nil
		}, nil)
	}
}

func BenchmarkGo(b *testing.B) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	for i := 0; i < b.N; i++ {
		<-Go(ctx, "test", func(context.Context) error {
			return nil
		}, nil)
	}
}

func BenchmarkDoFail(b *testing.B) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	for i := 0; i < b.N; i++ {
		Do(ctx, "test", func(context.Context) error {
			return errors.New("fail")
		}, nil)
	}
}

func BenchmarkGoFail(b *testing.B) {
	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)
	for i := 0; i < b.N; i++ {
		<-Go(ctx, "test", func(context.Context) error {
			return errors.New("fail")
		}, nil)
	}
}
<|endoftext|>


<commit_before>package crypto

// xlattice_go/crypto/gocheck.go

import (
	. "launchpad.net/gocheck"
	"testing"
)

func Test(t *testing.T) { TestingT(t) }

type XLSuite struct{}

var _ = Suite(&XLSuite{})

<commit_msg>RegCluster serialization works, tests succeed<commit_after>package crypto

// xlattice_go/crypto/gocheck.go

import (
	. "launchpad.net/gocheck"
	"testing"
)

func Test(t *testing.T) { TestingT(t) }

type XLSuite struct{}

var _ = Suite(&XLSuite{})
<|endoftext|>


<commit_before>/*
  Go Language Raspberry Pi Interface
  (c) Copyright David Thorpe 2016-2020
  All Rights Reserved
  For Licensing and Usage information, please see LICENSE.md
*/

package app

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"path/filepath"

	// Frameworks
	gopi "github.com/djthorpe/gopi/v2"
	base "github.com/djthorpe/gopi/v2/base"
)

////////////////////////////////////////////////////////////////////////////////
// INTERFACES

type debug struct {
	main gopi.MainCommandFunc
	args []string
	base.App
}

////////////////////////////////////////////////////////////////////////////////
// gopi.App implementation for debug tool

func NewDebugTool(main gopi.MainCommandFunc, args []string, units []string) (gopi.App, error) {
	this := new(debug)

	// Name of command
	name := filepath.Base(os.Args[0])

	// Check parameters
	if main == nil {
		return nil, gopi.ErrBadParameter.WithPrefix("main")
	} else if err := this.App.Init(name, units); err != nil {
		return nil, err
	} else {
		this.main = main
		this.args = args
	}

	// Success
	return this, nil
}

func (this *debug) Run() int {
	if returnValue := this.App.Start(this.args); returnValue != 0 {
		return returnValue
	}

	// Defer closing of instances to exit
	defer func() {
		if err := this.App.Close(); err != nil {
			fmt.Fprintln(os.Stderr, this.App.Flags().Name()+":", err)
		}
	}()

	// Run main function
	if err := this.main(this, this.Flags().Args()); errors.Is(err, gopi.ErrHelp) || errors.Is(err, flag.ErrHelp) {
		this.App.Flags().Usage(os.Stderr)
		return 0
	} else if err != nil {
		fmt.Fprintln(os.Stderr, this.App.Flags().Name()+":", err)
		return -1
	}

	// Success
	return 0
}
<commit_msg>Updates<commit_after>/*
  Go Language Raspberry Pi Interface
  (c) Copyright David Thorpe 2016-2020
  All Rights Reserved
  For Licensing and Usage information, please see LICENSE.md
*/

package app

import (
	"fmt"
	"os"
	"testing"

	// Frameworks
	gopi "github.com/djthorpe/gopi/v2"
	base "github.com/djthorpe/gopi/v2/base"
)

////////////////////////////////////////////////////////////////////////////////
// INTERFACES

type debug struct {
	main gopi.MainTestFunc
	t    *testing.T
	args []string
	base.App
}

////////////////////////////////////////////////////////////////////////////////
// gopi.App implementation for debug tool

func NewTestTool(t *testing.T, main gopi.MainTestFunc, args []string, units ...string) (gopi.App, error) {
	this := new(debug)

	// Name of test
	name := t.Name()

	// Check parameters
	if main == nil {
		return nil, gopi.ErrBadParameter.WithPrefix("main")
	} else if err := this.App.Init(name, units); err != nil {
		return nil, err
	} else {
		this.main = main
		this.args = args
		this.t = t
	}

	// Success
	return this, nil
}

func (this *debug) Run() int {
	if returnValue := this.App.Start(this.args); returnValue != 0 {
		return returnValue
	}

	// Defer closing of instances to exit
	defer func() {
		if err := this.App.Close(); err != nil {
			fmt.Fprintln(os.Stderr, this.App.Flags().Name()+":", err)
		}
	}()

	// Run main function - doesn't return any errors since they are
	// handled by the testing package
	this.main(this, this.t)

	// Always return 0
	return 0
}
<|endoftext|>