<commit_before>package speed

import (
	"errors"
	"os"
	"path"
	"strings"
	"sync"
	"time"

	"github.com/performancecopilot/speed/bytebuffer"
)

// byte lengths of different components in an mmv file
const (
	HeaderLength         = 40
	TocLength            = 16
	MetricLength         = 104
	ValueLength          = 32
	InstanceLength       = 80
	InstanceDomainLength = 32
	StringBlockLength    = 256
)

// MaxMetricNameLength is the maximum length for a metric name
const MaxMetricNameLength = 63

// MaxDataValueSize is the maximum byte length for a stored metric value, unless it is a string
const MaxDataValueSize = 16

// Writer defines the interface of a MMV file writer's properties
type Writer interface {
	// a writer must contain a registry of metrics and instance domains
	Registry() Registry

	// writes an mmv file
	Start() error

	// stops writing and cleans up
	Stop() error

	// adds a metric to be written
	Register(Metric) error

	// adds an instance domain to be written
	RegisterIndom(InstanceDomain) error

	// adds metric and instance domain from a string
	RegisterString(s string) error

	// update a metric
	Update(Metric, interface{}) error
}

func mmvFileLocation(name string) (string, error) {
	if strings.ContainsRune(name, os.PathSeparator) {
		return "", errors.New("name cannot have path separator")
	}

	tdir, present := config["PCP_TMP_DIR"]
	var loc string
	if present {
		loc = path.Join(rootPath, tdir)
	} else {
		loc = os.TempDir()
	}

	return path.Join(loc, "mmv", name), nil
}

// PCPClusterIDBitLength is the bit length of the cluster id
// for a set of PCP metrics
const PCPClusterIDBitLength = 12

// MMVFlag represents an enumerated type to represent mmv flag values
type MMVFlag int

// values for MMVFlag
const (
	NoPrefixFlag MMVFlag = 1 << iota
	ProcessFlag
	SentinelFlag
)

//go:generate stringer -type=MMVFlag

// PCPWriter implements a writer that can write PCP compatible MMV files
type PCPWriter struct {
	sync.Mutex
	loc       string       // absolute location of the mmv file
	clusterID uint32       // cluster identifier for the writer
	flag      MMVFlag      // write flag
	r         *PCPRegistry // current registry
}

// NewPCPWriter initializes a new PCPWriter object
func NewPCPWriter(name string, flag MMVFlag) (*PCPWriter, error) {
	fileLocation, err := mmvFileLocation(name)
	if err != nil {
		return nil, err
	}

	return &PCPWriter{
		loc:       fileLocation,
		r:         NewPCPRegistry(),
		clusterID: getHash(name, PCPClusterIDBitLength),
		flag:      flag,
	}, nil
}

// Registry returns a writer's registry
func (w *PCPWriter) Registry() Registry {
	return w.r
}

func (w *PCPWriter) tocCount() int {
	ans := 2

	if w.Registry().InstanceCount() > 0 {
		ans += 2
	}

	if w.Registry().StringCount() > 0 {
		ans++
	}

	return ans
}

// Length returns the byte length of data in the mmv file written by the current writer
func (w *PCPWriter) Length() int {
	return HeaderLength +
		(w.tocCount() * TocLength) +
		(w.Registry().InstanceCount() * InstanceLength) +
		(w.Registry().InstanceDomainCount() * InstanceDomainLength) +
		(w.Registry().MetricCount() * (MetricLength + ValueLength)) +
		(w.Registry().StringCount() * StringBlockLength)
}

func (w *PCPWriter) initializeOffsets() {
	indomoffset := HeaderLength + TocLength*w.tocCount()
	instanceoffset := indomoffset + InstanceDomainLength*w.r.InstanceDomainCount()
	metricsoffset := instanceoffset + InstanceLength*w.r.InstanceCount()
	valuesoffset := metricsoffset + MetricLength*w.r.MetricCount()
	stringsoffset := valuesoffset + ValueLength*w.r.MetricCount()

	w.r.indomoffset = indomoffset
	w.r.instanceoffset = instanceoffset
	w.r.metricsoffset = metricsoffset
	w.r.valuesoffset = valuesoffset
	w.r.stringsoffset = stringsoffset

	for _, indom := range w.r.instanceDomains {
		indom.offset = indomoffset
		indom.instanceOffset = instanceoffset
		indomoffset += InstanceDomainLength

		for _, i := range indom.instances {
			i.offset = instanceoffset
			instanceoffset += InstanceLength
		}

		if indom.shortHelpText.val != "" {
			indom.shortHelpText.offset = stringsoffset
			stringsoffset += StringBlockLength
		}

		if indom.longHelpText.val != "" {
			indom.longHelpText.offset = stringsoffset
			stringsoffset += StringBlockLength
		}
	}

	for _, metric := range w.r.metrics {
		metric.desc.offset = metricsoffset
		metricsoffset += MetricLength
		metric.offset = valuesoffset
		valuesoffset += ValueLength

		if metric.desc.shortDescription.val != "" {
			metric.desc.shortDescription.offset = stringsoffset
			stringsoffset += StringBlockLength
		}

		if metric.desc.longDescription.val != "" {
			metric.desc.longDescription.offset = stringsoffset
			stringsoffset += StringBlockLength
		}
	}
}

func (w *PCPWriter) writeHeaderBlock(buffer bytebuffer.Buffer) (generation2offset int, generation int64) {
	// tag
	buffer.WriteString("MMV")
	buffer.SetPos(buffer.Pos() + 1) // extra null byte is needed and \0 isn't a valid escape character in go

	// version
	buffer.WriteUint32(1)

	// generation
	generation = time.Now().Unix()
	buffer.WriteInt64(generation)

	generation2offset = buffer.Pos()

	buffer.WriteInt64(0)

	// tocCount
	buffer.WriteInt32(int32(w.tocCount()))

	// flag mask
	buffer.WriteInt32(int32(w.flag))

	// process identifier
	buffer.WriteInt32(int32(os.Getpid()))

	// cluster identifier
	buffer.WriteUint32(w.clusterID)

	return
}

func (w *PCPWriter) writeSingleToc(pos, identifier, count, offset int, buffer bytebuffer.Buffer) {
	buffer.SetPos(pos)
	buffer.WriteInt32(int32(identifier))
	buffer.WriteInt32(int32(count))
	buffer.WriteUint64(uint64(offset))
}

func (w *PCPWriter) writeTocBlock(buffer bytebuffer.Buffer) {
	tocpos := HeaderLength

	// instance domains toc
	if w.Registry().InstanceDomainCount() > 0 {
		// 1 is the identifier for instance domains
		w.writeSingleToc(tocpos, 1, w.r.InstanceDomainCount(), w.r.indomoffset, buffer)
		tocpos += TocLength
	}

	// instances toc
	if w.Registry().InstanceCount() > 0 {
		// 2 is the identifier for instances
		w.writeSingleToc(tocpos, 2, w.r.InstanceCount(), w.r.instanceoffset, buffer)
		tocpos += TocLength
	}

	// metrics and values toc
	metricsoffset, valuesoffset := w.r.metricsoffset, w.r.valuesoffset
	if w.Registry().MetricCount() == 0 {
		metricsoffset, valuesoffset = 0, 0
	}

	// 3 is the identifier for metrics
	w.writeSingleToc(tocpos, 3, w.r.MetricCount(), metricsoffset, buffer)
	tocpos += TocLength

	// 4 is the identifier for values
	w.writeSingleToc(tocpos, 4, w.r.MetricCount(), valuesoffset, buffer)
	tocpos += TocLength

	// strings toc
	if w.Registry().StringCount() > 0 {
		// 5 is the identifier for strings
		w.writeSingleToc(tocpos, 5, w.r.StringCount(), w.r.stringsoffset, buffer)
	}
}

func (w *PCPWriter) writeInstanceAndInstanceDomainBlock(buffer bytebuffer.Buffer) {
	for _, indom := range w.r.instanceDomains {
		buffer.SetPos(indom.offset)
		buffer.WriteUint32(indom.ID())
		buffer.WriteInt32(int32(indom.InstanceCount()))
		buffer.WriteInt64(int64(indom.instanceOffset))

		so, lo := indom.shortHelpText.offset, indom.longHelpText.offset
		buffer.WriteInt64(int64(so))
		buffer.WriteInt64(int64(lo))

		if so != 0 {
			buffer.SetPos(so)
			buffer.WriteString(indom.shortHelpText.val)
		}

		if lo != 0 {
			buffer.SetPos(lo)
			buffer.WriteString(indom.longHelpText.val)
		}

		for _, i := range indom.instances {
			buffer.SetPos(i.offset)
			buffer.WriteInt64(int64(indom.offset))
			buffer.WriteInt32(0)
			buffer.WriteUint32(i.id)
			buffer.WriteString(i.name)
		}
	}
}

func (w *PCPWriter) writeMetricDesc(desc *pcpMetricDesc, buffer bytebuffer.Buffer) {
	pos := desc.offset
	buffer.SetPos(pos)

	buffer.WriteString(desc.name)
	buffer.Write([]byte{0})
	buffer.SetPos(pos + MaxMetricNameLength + 1)
	buffer.WriteUint32(desc.id)
	buffer.WriteInt32(int32(desc.t))
	buffer.WriteInt32(int32(desc.sem))
	buffer.WriteUint32(desc.u.PMAPI())
	if desc.indom != nil {
		buffer.WriteUint32(desc.indom.ID())
	} else {
		buffer.WriteInt32(-1)
	}
	buffer.WriteInt32(0)

	so, lo := desc.shortDescription.offset, desc.longDescription.offset
	buffer.WriteInt64(int64(so))
	buffer.WriteInt64(int64(lo))

	if so != 0 {
		buffer.SetPos(so)
		buffer.WriteString(desc.shortDescription.val)
	}

	if lo != 0 {
		buffer.SetPos(lo)
		buffer.WriteString(desc.longDescription.val)
	}
}

func (w *PCPWriter) writeMetricVal(m *PCPMetric, buffer bytebuffer.Buffer) {
	pos := m.offset
	buffer.SetPos(pos)

	m.desc.t.WriteVal(m.val, buffer)

	buffer.SetPos(pos + MaxDataValueSize)
	buffer.WriteInt64(int64(m.desc.offset))
	if m.desc.indom != nil {
		buffer.WriteInt64(int64(m.desc.indom.(*PCPInstanceDomain).instanceOffset))
	} else {
		buffer.WriteInt64(0)
	}
}

func (w *PCPWriter) writeMetricsAndValuesBlock(buffer bytebuffer.Buffer) {
	for _, metric := range w.r.metrics {
		w.writeMetricDesc(metric.desc, buffer)
		w.writeMetricVal(metric, buffer)
	}
}

// fillData will fill the Buffer with the mmv file
// data as long as something doesn't go wrong
func (w *PCPWriter) fillData(buffer bytebuffer.Buffer) error {
	generation2offset, generation := w.writeHeaderBlock(buffer)
	w.writeTocBlock(buffer)
	w.writeInstanceAndInstanceDomainBlock(buffer)
	w.writeMetricsAndValuesBlock(buffer)

	buffer.SetPos(generation2offset)
	buffer.WriteUint64(uint64(generation))

	return nil
}

// Start dumps existing registry data
func (w *PCPWriter) Start() error {
	w.Lock()
	defer w.Unlock()

	l := w.Length()

	w.initializeOffsets()

	buffer, err := bytebuffer.NewMemoryMappedBuffer(w.loc, l)
	if err != nil {
		return err
	}

	w.fillData(buffer)

	w.r.mapped = true

	return nil
}

// Stop removes existing mapping and cleans up
func (w *PCPWriter) Stop() error {
	w.Lock()
	defer w.Unlock()

	w.r.mapped = false

	return nil
}

// Register is simply a shorthand for Registry().AddMetric
func (w *PCPWriter) Register(m Metric) error { return w.Registry().AddMetric(m) }

// RegisterIndom is simply a shorthand for Registry().AddInstanceDomain
func (w *PCPWriter) RegisterIndom(indom InstanceDomain) error {
	return w.Registry().AddInstanceDomain(indom)
}

// RegisterString is simply a shorthand for Registry().AddMetricByString
func (w *PCPWriter) RegisterString(str string, val interface{}, s MetricSemantics, t MetricType, u MetricUnit) error {
	_, err := w.Registry().AddMetricByString(str, val, s, t, u)
	return err
}

// Update is simply a shorthand for Registry().UpdateMetric
func (w *PCPWriter) Update(m Metric, val interface{}) error { return w.Registry().UpdateMetric(m, val) }
<commit_msg>writer: cache Buffer inside the PCPWriter type<commit_after>package speed

import (
	"errors"
	"os"
	"path"
	"strings"
	"sync"
	"time"

	"github.com/performancecopilot/speed/bytebuffer"
)

// byte lengths of different components in an mmv file
const (
	HeaderLength         = 40
	TocLength            = 16
	MetricLength         = 104
	ValueLength          = 32
	InstanceLength       = 80
	InstanceDomainLength = 32
	StringBlockLength    = 256
)

// MaxMetricNameLength is the maximum length for a metric name
const MaxMetricNameLength = 63

// MaxDataValueSize is the maximum byte length for a stored metric value, unless it is a string
const MaxDataValueSize = 16

// Writer defines the interface of a MMV file writer's properties
type Writer interface {
	// a writer must contain a registry of metrics and instance domains
	Registry() Registry

	// writes an mmv file
	Start() error

	// stops writing and cleans up
	Stop() error

	// adds a metric to be written
	Register(Metric) error

	// adds an instance domain to be written
	RegisterIndom(InstanceDomain) error

	// adds metric and instance domain from a string
	RegisterString(string, interface{}, MetricSemantics, MetricType, MetricUnit) error

	// update a metric
	Update(Metric, interface{}) error
}

func mmvFileLocation(name string) (string, error) {
	if strings.ContainsRune(name, os.PathSeparator) {
		return "", errors.New("name cannot have path separator")
	}

	tdir, present := config["PCP_TMP_DIR"]
	var loc string
	if present {
		loc = path.Join(rootPath, tdir)
	} else {
		loc = os.TempDir()
	}

	return path.Join(loc, "mmv", name), nil
}

// PCPClusterIDBitLength is the bit length of the cluster id
// for a set of PCP metrics
const PCPClusterIDBitLength = 12

// MMVFlag represents an enumerated type to represent mmv flag values
type MMVFlag int

// values for MMVFlag
const (
	NoPrefixFlag MMVFlag = 1 << iota
	ProcessFlag
	SentinelFlag
)

//go:generate stringer -type=MMVFlag

// PCPWriter implements a writer that can write PCP compatible MMV files
type PCPWriter struct {
	sync.Mutex
	loc       string            // absolute location of the mmv file
	clusterID uint32            // cluster identifier for the writer
	flag      MMVFlag           // write flag
	r         *PCPRegistry      // current registry
	buffer    bytebuffer.Buffer // current Buffer
}

// NewPCPWriter initializes a new PCPWriter object
func NewPCPWriter(name string, flag MMVFlag) (*PCPWriter, error) {
	fileLocation, err := mmvFileLocation(name)
	if err != nil {
		return nil, err
	}

	return &PCPWriter{
		loc:       fileLocation,
		r:         NewPCPRegistry(),
		clusterID: getHash(name, PCPClusterIDBitLength),
		flag:      flag,
		buffer:    nil,
	}, nil
}

// Registry returns a writer's registry
func (w *PCPWriter) Registry() Registry {
	return w.r
}

func (w *PCPWriter) tocCount() int {
	ans := 2

	if w.Registry().InstanceCount() > 0 {
		ans += 2
	}

	if w.Registry().StringCount() > 0 {
		ans++
	}

	return ans
}

// Length returns the byte length of data in the mmv file written by the current writer
func (w *PCPWriter) Length() int {
	return HeaderLength +
		(w.tocCount() * TocLength) +
		(w.Registry().InstanceCount() * InstanceLength) +
		(w.Registry().InstanceDomainCount() * InstanceDomainLength) +
		(w.Registry().MetricCount() * (MetricLength + ValueLength)) +
		(w.Registry().StringCount() * StringBlockLength)
}

func (w *PCPWriter) initializeOffsets() {
	indomoffset := HeaderLength + TocLength*w.tocCount()
	instanceoffset := indomoffset + InstanceDomainLength*w.r.InstanceDomainCount()
	metricsoffset := instanceoffset + InstanceLength*w.r.InstanceCount()
	valuesoffset := metricsoffset + MetricLength*w.r.MetricCount()
	stringsoffset := valuesoffset + ValueLength*w.r.MetricCount()

	w.r.indomoffset = indomoffset
	w.r.instanceoffset = instanceoffset
	w.r.metricsoffset = metricsoffset
	w.r.valuesoffset = valuesoffset
	w.r.stringsoffset = stringsoffset

	for _, indom := range w.r.instanceDomains {
		indom.offset = indomoffset
		indom.instanceOffset = instanceoffset
		indomoffset += InstanceDomainLength

		for _, i := range indom.instances {
			i.offset = instanceoffset
			instanceoffset += InstanceLength
		}

		if indom.shortHelpText.val != "" {
			indom.shortHelpText.offset = stringsoffset
			stringsoffset += StringBlockLength
		}

		if indom.longHelpText.val != "" {
			indom.longHelpText.offset = stringsoffset
			stringsoffset += StringBlockLength
		}
	}

	for _, metric := range w.r.metrics {
		metric.desc.offset = metricsoffset
		metricsoffset += MetricLength
		metric.offset = valuesoffset
		valuesoffset += ValueLength

		if metric.desc.shortDescription.val != "" {
			metric.desc.shortDescription.offset = stringsoffset
			stringsoffset += StringBlockLength
		}

		if metric.desc.longDescription.val != "" {
			metric.desc.longDescription.offset = stringsoffset
			stringsoffset += StringBlockLength
		}
	}
}

func (w *PCPWriter) writeHeaderBlock() (generation2offset int, generation int64) {
	// tag
	w.buffer.WriteString("MMV")
	w.buffer.SetPos(w.buffer.Pos() + 1) // extra null byte is needed and \0 isn't a valid escape character in go

	// version
	w.buffer.WriteUint32(1)

	// generation
	generation = time.Now().Unix()
	w.buffer.WriteInt64(generation)

	generation2offset = w.buffer.Pos()

	w.buffer.WriteInt64(0)

	// tocCount
	w.buffer.WriteInt32(int32(w.tocCount()))

	// flag mask
	w.buffer.WriteInt32(int32(w.flag))

	// process identifier
	w.buffer.WriteInt32(int32(os.Getpid()))

	// cluster identifier
	w.buffer.WriteUint32(w.clusterID)

	return
}

func (w *PCPWriter) writeSingleToc(pos, identifier, count, offset int) {
	w.buffer.SetPos(pos)
	w.buffer.WriteInt32(int32(identifier))
	w.buffer.WriteInt32(int32(count))
	w.buffer.WriteUint64(uint64(offset))
}

func (w *PCPWriter) writeTocBlock() {
	tocpos := HeaderLength

	// instance domains toc
	if w.Registry().InstanceDomainCount() > 0 {
		// 1 is the identifier for instance domains
		w.writeSingleToc(tocpos, 1, w.r.InstanceDomainCount(), w.r.indomoffset)
		tocpos += TocLength
	}

	// instances toc
	if w.Registry().InstanceCount() > 0 {
		// 2 is the identifier for instances
		w.writeSingleToc(tocpos, 2, w.r.InstanceCount(), w.r.instanceoffset)
		tocpos += TocLength
	}

	// metrics and values toc
	metricsoffset, valuesoffset := w.r.metricsoffset, w.r.valuesoffset
	if w.Registry().MetricCount() == 0 {
		metricsoffset, valuesoffset = 0, 0
	}

	// 3 is the identifier for metrics
	w.writeSingleToc(tocpos, 3, w.r.MetricCount(), metricsoffset)
	tocpos += TocLength

	// 4 is the identifier for values
	w.writeSingleToc(tocpos, 4, w.r.MetricCount(), valuesoffset)
	tocpos += TocLength

	// strings toc
	if w.Registry().StringCount() > 0 {
		// 5 is the identifier for strings
		w.writeSingleToc(tocpos, 5, w.r.StringCount(), w.r.stringsoffset)
	}
}

func (w *PCPWriter) writeInstanceAndInstanceDomainBlock() {
	for _, indom := range w.r.instanceDomains {
		w.buffer.SetPos(indom.offset)
		w.buffer.WriteUint32(indom.ID())
		w.buffer.WriteInt32(int32(indom.InstanceCount()))
		w.buffer.WriteInt64(int64(indom.instanceOffset))

		so, lo := indom.shortHelpText.offset, indom.longHelpText.offset
		w.buffer.WriteInt64(int64(so))
		w.buffer.WriteInt64(int64(lo))

		if so != 0 {
			w.buffer.SetPos(so)
			w.buffer.WriteString(indom.shortHelpText.val)
		}

		if lo != 0 {
			w.buffer.SetPos(lo)
			w.buffer.WriteString(indom.longHelpText.val)
		}

		for _, i := range indom.instances {
			w.buffer.SetPos(i.offset)
			w.buffer.WriteInt64(int64(indom.offset))
			w.buffer.WriteInt32(0)
			w.buffer.WriteUint32(i.id)
			w.buffer.WriteString(i.name)
		}
	}
}

func (w *PCPWriter) writeMetricDesc(desc *pcpMetricDesc) {
	pos := desc.offset
	w.buffer.SetPos(pos)

	w.buffer.WriteString(desc.name)
	w.buffer.Write([]byte{0})
	w.buffer.SetPos(pos + MaxMetricNameLength + 1)
	w.buffer.WriteUint32(desc.id)
	w.buffer.WriteInt32(int32(desc.t))
	w.buffer.WriteInt32(int32(desc.sem))
	w.buffer.WriteUint32(desc.u.PMAPI())
	if desc.indom != nil {
		w.buffer.WriteUint32(desc.indom.ID())
	} else {
		w.buffer.WriteInt32(-1)
	}
	w.buffer.WriteInt32(0)

	so, lo := desc.shortDescription.offset, desc.longDescription.offset
	w.buffer.WriteInt64(int64(so))
	w.buffer.WriteInt64(int64(lo))

	if so != 0 {
		w.buffer.SetPos(so)
		w.buffer.WriteString(desc.shortDescription.val)
	}

	if lo != 0 {
		w.buffer.SetPos(lo)
		w.buffer.WriteString(desc.longDescription.val)
	}
}

func (w *PCPWriter) writeMetricVal(m *PCPMetric) {
	pos := m.offset
	w.buffer.SetPos(pos)

	m.desc.t.WriteVal(m.val, w.buffer)

	w.buffer.SetPos(pos + MaxDataValueSize)
	w.buffer.WriteInt64(int64(m.desc.offset))
	if m.desc.indom != nil {
		w.buffer.WriteInt64(int64(m.desc.indom.(*PCPInstanceDomain).instanceOffset))
	} else {
		w.buffer.WriteInt64(0)
	}
}

func (w *PCPWriter) writeMetricsAndValuesBlock() {
	for _, metric := range w.r.metrics {
		w.writeMetricDesc(metric.desc)
		w.writeMetricVal(metric)
	}
}

// fillData will fill the Buffer with the mmv file
// data as long as something doesn't go wrong
func (w *PCPWriter) fillData() error {
	generation2offset, generation := w.writeHeaderBlock()
	w.writeTocBlock()
	w.writeInstanceAndInstanceDomainBlock()
	w.writeMetricsAndValuesBlock()

	w.buffer.SetPos(generation2offset)
	w.buffer.WriteUint64(uint64(generation))

	return nil
}

// Start dumps existing registry data
func (w *PCPWriter) Start() error {
	w.Lock()
	defer w.Unlock()

	l := w.Length()

	w.initializeOffsets()

	buffer, err := bytebuffer.NewMemoryMappedBuffer(w.loc, l)
	if err != nil {
		return err
	}
	w.buffer = buffer

	w.fillData()

	w.r.mapped = true

	return nil
}

// Stop removes existing mapping and cleans up
func (w *PCPWriter) Stop() error {
	w.Lock()
	defer w.Unlock()

	w.r.mapped = false

	return nil
}

// Register is simply a shorthand for Registry().AddMetric
func (w *PCPWriter) Register(m Metric) error { return w.Registry().AddMetric(m) }

// RegisterIndom is simply a shorthand for Registry().AddInstanceDomain
func (w *PCPWriter) RegisterIndom(indom InstanceDomain) error {
	return w.Registry().AddInstanceDomain(indom)
}

// RegisterString is simply a shorthand for Registry().AddMetricByString
func (w *PCPWriter) RegisterString(str string, val interface{}, s MetricSemantics, t MetricType, u MetricUnit) error {
	_, err := w.Registry().AddMetricByString(str, val, s, t, u)
	return err
}

// Update is simply a shorthand for Registry().UpdateMetric
func (w *PCPWriter) Update(m Metric, val interface{}) error { return w.Registry().UpdateMetric(m, val) }
<|endoftext|>


<commit_before><commit_msg>Fix broken test - TestClient_Do_Backoff on macos_latest<commit_after><|endoftext|>


<commit_before>package main

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

	"github.com/golang-bristol/beer-model"
	"github.com/julienschmidt/httprouter"
)

// GetBeers returns the cellar
func GetBeers(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(Cellar)
}

// GetBeer returns a beer from the cellar
func GetBeer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")

	ID, err := strconv.Atoi(ps.ByName("id"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(fmt.Sprintf("%s is not a valid Beer ID, it must be a number.", ps.ByName("id")))
		return
	}

	for _, v := range Cellar {
		if v.ID == ID {
			json.NewEncoder(w).Encode(v)
			return
		}
	}

	w.WriteHeader(http.StatusNotFound)
	json.NewEncoder(w).Encode("The beer you requested does not exist.")
}

// GetBeerReviews returns all reviews for a beer
func GetBeerReviews(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	// TODO
}

// AddBeer adds a new beer to the cellar
func AddBeer(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")

	decoder := json.NewDecoder(r.Body)

	var newBeer model.Beer
	err := decoder.Decode(&newBeer)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(http.StatusBadRequest)
		fmt.Println("Bad beer - this will be a HTTP status code soon!")
	} else {
		json.NewEncoder(w).Encode("New beer added.")
	}
}

// AddBeerReview adds a new review for a beer
func AddBeerReview(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	// TODO
}
<commit_msg>Implement AddBeerReview() function<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/golang-bristol/beer-model"
	"github.com/julienschmidt/httprouter"
)

// GetBeers returns the cellar
func GetBeers(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(Cellar)
}

// GetBeer returns a beer from the cellar
func GetBeer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")

	ID, err := strconv.Atoi(ps.ByName("id"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(fmt.Sprintf("%s is not a valid Beer ID, it must be a number.", ps.ByName("id")))
		return
	}

	for _, v := range Cellar {
		if v.ID == ID {
			json.NewEncoder(w).Encode(v)
			return
		}
	}

	w.WriteHeader(http.StatusNotFound)
	json.NewEncoder(w).Encode("The beer you requested does not exist.")
}

// GetBeerReviews returns all reviews for a beer
func GetBeerReviews(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	// TODO
}

// AddBeer adds a new beer to the cellar
func AddBeer(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")

	decoder := json.NewDecoder(r.Body)

	var newBeer model.Beer
	err := decoder.Decode(&newBeer)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(http.StatusBadRequest)
		fmt.Println("Bad beer - this will be a HTTP status code soon!")
	} else {
		json.NewEncoder(w).Encode("New beer added.")
	}
}

// AddBeerReview adds a new review for a beer
func AddBeerReview(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")

	ID, err := strconv.Atoi(ps.ByName("id"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(fmt.Sprintf("%s is not a valid Beer ID, it must be a number.", ps.ByName("id")))
		return
	}

	for _, v := range Cellar {
		if v.ID == ID {
			decoder := json.NewDecoder(r.Body)

			var newReview model.Review
			err := decoder.Decode(&newReview)

			newReview.BeerID = ID

			if err != nil {
				w.WriteHeader(http.StatusBadRequest)
				json.NewEncoder(w).Encode(http.StatusBadRequest)
				fmt.Println("Bad beer - this will be a HTTP status code soon!")
			} else {
				Reviews = append(Reviews, newReview)
				json.NewEncoder(w).Encode("New beer review added.")
			}
			return
		}
	}

	w.WriteHeader(http.StatusNotFound)
	json.NewEncoder(w).Encode("The beer selected for the review does not exist.")
}
<|endoftext|>


<commit_before>package gnosis

// package file will contain MarkdownHandler and RawHandler to handle incoming requests
// Whole thing needs to be written

import (
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"

	"github.com/JackKnifed/blackfriday"
)

var fileFilter = regexp.MustCompile("^(/([a-zA-Z0-9_ /]+/)?)([a-zA-Z0-9_ ]+)?(\\.)?([a-zA-Z0-9_ ]+)?")

func RawHandler(responsePipe http.ResponseWriter, request *http.Request) {
	var err error

	filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)
	config := GetConfig()

	if filteredRequest == nil {
		log.Printf("null request improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	}

	if filteredRequest[1] != config.Mainserver.Prefix {
		log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, err.Error(), 500)
	}

	contents, err := ioutil.ReadFile(config.Mainserver.Prefix + filteredRequest[2] + ".md")
	if err != nil {
		log.Printf("request %s points to an bad file target sent to server %s", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, err.Error(), 403)
	}

	_, err = responsePipe.Write([]byte(contents))
	if err != nil {
		http.Error(responsePipe, err.Error(), 500)
	}
}

const (
	bodyHtmlFlags = 0 |
		blackfriday.HTML_USE_XHTML |
		blackfriday.HTML_USE_SMARTYPANTS |
		blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES

	bodyExtensions = 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_AUTO_HEADER_IDS |
		blackfriday.EXTENSION_TITLEBLOCK

	tocHtmlFlags = 0 |
		blackfriday.HTML_USE_XHTML |
		blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES |
		blackfriday.HTML_TOC |
		blackfriday.HTML_OMIT_CONTENTS

	tocExtensions = 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_AUTO_HEADER_IDS |
		blackfriday.EXTENSION_TITLEBLOCK
)

type WikiPage struct {
	Title string
	ToC   template.HTML
	Body  template.HTML
}

var templates = template.Must(template.ParseFiles("wiki.html"))

var wikiFilter = regexp.MustCompile("^(/([a-zA-Z0-9_ /]+/)?)([a-zA-Z0-9_ ]+)$")

func bodyParseMarkdown(input []byte) []byte {
	// set up the HTML renderer
	renderer := blackfriday.HtmlRenderer(bodyHtmlFlags, "", "")
	return blackfriday.Markdown(input, renderer, bodyExtensions)
}

func tocParseMarkdown(input []byte) []byte {
	// set up the HTML renderer
	renderer := blackfriday.HtmlRenderer(tocHtmlFlags, "", "")
	return blackfriday.Markdown(input, renderer, tocExtensions)
}

func MarkdownHandler(responsePipe http.ResponseWriter, request *http.Request) {
	var err error

	filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)

	config := GetConfig()
	if filteredRequest == nil {
		log.Printf("null request [ %s ] improperly routed to wiki handler [ %s ]", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	} else {
		if filteredRequest[1] != config.Mainserver.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(config.Mainserver.Path + filteredRequest[3] + ".md")
		if err != nil {
			log.Printf("request [ %s ] points to an bad file target [ %s ]sent to server %s", request.URL.Path, filteredRequest[3], config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 403)
		}
		// parse any markdown in the input
		body := template.HTML(bodyParseMarkdown(contents))

		toc := template.HTML(tocParseMarkdown(contents))

		response := WikiPage{Title: filteredRequest[3], ToC: toc, Body: body}
		err = templates.ExecuteTemplate(responsePipe, "wiki.html", response)
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}

// Generate a Markdown Handler Function
func ConfiguredMarkdownHandler(responsePipe http.ResponseWriter, request *http.Request, serverConfig ServerSection) http.HandlerFunc {

	return func(resposePipe http.ResponseWriter, request *http.Request) {

		var err error

		// break up the request parameters - for reference, regex is listed below
		filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)

		// if there are no matches, the regex ovbiously didn't match up
		if filteredRequest == nil {
			log.Printf("null request [ %s ] improperly routed to wiki handler [ %s ]", request.URL.Path, serverConfig.Prefix)
			http.Error(responsePipe, "Request not allowed", 403)
		} else {
			if filteredRequest[1] != serverConfig.Prefix {
				log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, serverConfig.Prefix)
				http.Error(responsePipe, err.Error(), 500)
			}

			contents, err := ioutil.ReadFile(serverConfig.Path + filteredRequest[3] + ".md")
			if err != nil {
				log.Printf("request [ %s ] points to an bad file target [ %s ]sent to server %s", request.URL.Path, filteredRequest[3], serverConfig.Prefix)
				http.Error(responsePipe, err.Error(), 404)
			}
			// parse any markdown in the input
			body := template.HTML(bodyParseMarkdown(contents))

			toc := template.HTML(tocParseMarkdown(contents))

			response := WikiPage{Title: filteredRequest[3], ToC: toc, Body: body}
			err = templates.ExecuteTemplate(responsePipe, serverConfig.Template, response)
			if err != nil {
				http.Error(responsePipe, err.Error(), 500)
			}
		}
	}
}

func MakeHandler(handlerConfig ServerSection) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		switch handlerConfig.ServerType {
		case "markdown":
			ConfiguredMarkdownHandler(w, r, handlerConfig)
			//		case "raw":
			//			ConfiguredRawHandler(w, r, handlerConfig)
		default:
			log.Printf("Bad server type [%s]", handlerConfig.ServerType)
		}
	}
}

/*
func GenerateRawHandler(responsePipe http.ResponseWriter, request *http.Request, serverConfig ServerSection) {
	return func(responsePipe http.responseWriter, request *http.Request) {
		var err error

		filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)

		if filteredRequest == nil {
			log.Printf("null request improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, "Request not allowed", 403)
		}

		if filteredRequest[1] != config.Mainserver.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(config.Mainserver.Prefix + filteredRequest[2] + ".md")
		if err != nil {
			log.Printf("request %s points to an bad file target sent to server %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 403)
		}

		_, err = responsePipe.Write([]byte(contents))
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}
*/
<commit_msg>i am dumb. originally wrote one function to return another function to return a function, when i only had to do that twice, idk derp<commit_after>package gnosis

// package file will contain MarkdownHandler and RawHandler to handle incoming requests
// Whole thing needs to be written

import (
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"

	"github.com/JackKnifed/blackfriday"
)

var fileFilter = regexp.MustCompile("^(/([a-zA-Z0-9_ /]+/)?)([a-zA-Z0-9_ ]+)?(\\.)?([a-zA-Z0-9_ ]+)?")

func RawHandler(responsePipe http.ResponseWriter, request *http.Request) {
	var err error

	filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)
	config := GetConfig()

	if filteredRequest == nil {
		log.Printf("null request improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	}

	if filteredRequest[1] != config.Mainserver.Prefix {
		log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, err.Error(), 500)
	}

	contents, err := ioutil.ReadFile(config.Mainserver.Prefix + filteredRequest[2] + ".md")
	if err != nil {
		log.Printf("request %s points to an bad file target sent to server %s", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, err.Error(), 403)
	}

	_, err = responsePipe.Write([]byte(contents))
	if err != nil {
		http.Error(responsePipe, err.Error(), 500)
	}
}

const (
	bodyHtmlFlags = 0 |
		blackfriday.HTML_USE_XHTML |
		blackfriday.HTML_USE_SMARTYPANTS |
		blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES

	bodyExtensions = 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_AUTO_HEADER_IDS |
		blackfriday.EXTENSION_TITLEBLOCK

	tocHtmlFlags = 0 |
		blackfriday.HTML_USE_XHTML |
		blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES |
		blackfriday.HTML_TOC |
		blackfriday.HTML_OMIT_CONTENTS

	tocExtensions = 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_AUTO_HEADER_IDS |
		blackfriday.EXTENSION_TITLEBLOCK
)

type WikiPage struct {
	Title string
	ToC   template.HTML
	Body  template.HTML
}

var templates = template.Must(template.ParseFiles("wiki.html"))

var wikiFilter = regexp.MustCompile("^(/([a-zA-Z0-9_ /]+/)?)([a-zA-Z0-9_ ]+)$")

func bodyParseMarkdown(input []byte) []byte {
	// set up the HTML renderer
	renderer := blackfriday.HtmlRenderer(bodyHtmlFlags, "", "")
	return blackfriday.Markdown(input, renderer, bodyExtensions)
}

func tocParseMarkdown(input []byte) []byte {
	// set up the HTML renderer
	renderer := blackfriday.HtmlRenderer(tocHtmlFlags, "", "")
	return blackfriday.Markdown(input, renderer, tocExtensions)
}

func MarkdownHandler(responsePipe http.ResponseWriter, request *http.Request) {
	var err error

	filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)

	config := GetConfig()
	if filteredRequest == nil {
		log.Printf("null request [ %s ] improperly routed to wiki handler [ %s ]", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	} else {
		if filteredRequest[1] != config.Mainserver.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(config.Mainserver.Path + filteredRequest[3] + ".md")
		if err != nil {
			log.Printf("request [ %s ] points to an bad file target [ %s ]sent to server %s", request.URL.Path, filteredRequest[3], config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 403)
		}
		// parse any markdown in the input
		body := template.HTML(bodyParseMarkdown(contents))

		toc := template.HTML(tocParseMarkdown(contents))

		response := WikiPage{Title: filteredRequest[3], ToC: toc, Body: body}
		err = templates.ExecuteTemplate(responsePipe, "wiki.html", response)
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}

// Generate a Markdown Handler Function
func ConfiguredMarkdownHandler(responsePipe http.ResponseWriter, request *http.Request, serverConfig ServerSection) {

	var err error

	// break up the request parameters - for reference, regex is listed below
	filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)

	// if there are no matches, the regex ovbiously didn't match up
	if filteredRequest == nil {
		log.Printf("null request [ %s ] improperly routed to wiki handler [ %s ]", request.URL.Path, serverConfig.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	} else {
		if filteredRequest[1] != serverConfig.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(serverConfig.Path + filteredRequest[3] + ".md")
		if err != nil {
			log.Printf("request [ %s ] points to an bad file target [ %s ]sent to server %s", request.URL.Path, filteredRequest[3], serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 404)
		}
		// parse any markdown in the input
		body := template.HTML(bodyParseMarkdown(contents))

		toc := template.HTML(tocParseMarkdown(contents))

		response := WikiPage{Title: filteredRequest[3], ToC: toc, Body: body}
		err = templates.ExecuteTemplate(responsePipe, serverConfig.Template, response)
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}

func MakeHandler(handlerConfig ServerSection) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		switch handlerConfig.ServerType {
		case "markdown":
			ConfiguredMarkdownHandler(w, r, handlerConfig)
			//		case "raw":
			//			ConfiguredRawHandler(w, r, handlerConfig)
		default:
			log.Printf("Bad server type [%s]", handlerConfig.ServerType)
		}
	}
}

/*
func GenerateRawHandler(responsePipe http.ResponseWriter, request *http.Request, serverConfig ServerSection) {
	return func(responsePipe http.responseWriter, request *http.Request) {
		var err error

		filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)

		if filteredRequest == nil {
			log.Printf("null request improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, "Request not allowed", 403)
		}

		if filteredRequest[1] != config.Mainserver.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(config.Mainserver.Prefix + filteredRequest[2] + ".md")
		if err != nil {
			log.Printf("request %s points to an bad file target sent to server %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 403)
		}

		_, err = responsePipe.Write([]byte(contents))
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}
*/
<|endoftext|>


<commit_before>//
// Copyright (c) 2016 Dennis Chen
//
// This file is part of Clashr.
//
// Clashr is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// Clashr is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
// more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Clashr.  If not, see <http://www.gnu.org/licenses/>.

// Package cgroup provides a large amount of functionality for properly
// implementing cgroups in the judging and tracking of programs in Clashr.
// Most of this work is inspired by the DOMJudge implementation runguard.c and
// attempts to mimic a majoritiy of it's behavior
//
package cgroup

// #cgo pkg-config: libcgroup
// #include <libcgroup.h>
import "C"

import (
	"errors"
	"fmt"
	"syscall"
	"unsafe"
)

// A uniform interface for the cgroup actions.
type Cgroup struct {
	name string
	cpus string
	mems int64
}

// OutputStats returns the memory used (in bytes) by a process controlled by a
// cgroup.
func (g *Cgroup) OutputStats() (int64, error) {
	var param *C.char

	param = C.CString(g.name)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		return 0, errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	if ret := C.cgroup_get_cgroup(cg); ret != 0 {
		err := fmt.Errorf("Get cgroup information: %s(d)",
			C.cgroup_strerror(ret), ret)
		return 0, err
	}
	param = C.CString("memory")
	cgController := C.cgroup_get_controller(cg, param)

	var maxUsage C.int64_t
	param = C.CString("memory.memsw.max_usage_in_bytes")
	if ret := C.cgroup_get_value_int64(cgController, param, &maxUsage); ret != 0 {
		err := fmt.Errorf("Get cgroup value: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return 0, err
	}

	return int64(maxUsage), nil
}

// Create makes a new instance of the cgroup interface. It sets the memory
// limit of the cgroup to memsize, and the set of CPUs to use to cpuset. If
// memory does not need to be limited, set memsize to syscall.RLIMIT_INFINITY.
// Similarly, set cpuset to the empty string if CPUs do not need to be set.
func Create(cgroupname, cpuset string, memsize int64) (Cgroup, error) {
	var param *C.char

	param = C.CString(cgroupname)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		return Cgroup{}, errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	// Set memory restrictions. We limit both ram and ram+swap to the same
	// amount to prevent swapping.
	param = C.CString("memory")
	cgController := C.cgroup_add_controller(cg, param)

	mem := C.int64_t(memsize)
	param = C.CString("memory.limit_in_bytes")
	C.cgroup_add_value_int64(cgController, param, mem)
	param = C.CString("memory.memsw.limit_in_bytes")
	C.cgroup_add_value_int64(cgController, param, mem)

	// Setup CPU restrictions. The task is pinned to a specific set of CPUs
	// if a non-empty string is passed.
	if len(cpuset) > 0 {
		param = C.CString("cpuset")
		cgController = C.cgroup_add_controller(cg, param)

		var arg *C.char
		param = C.CString("cpuset.mems")
		arg = C.CString("0")
		C.cgroup_add_value_string(cgController, param, arg)
		param = C.CString("cpuset.cpus")
		arg = C.CString(cpuset)
		C.cgroup_add_value_string(cgController, param, arg)
	}

	// Perform the creation of the cgroup.
	if ret := C.cgroup_create_cgroup(cg, 1); ret != 0 {
		err := fmt.Errorf("Creating cgroup: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return Cgroup{}, err
	}
	return Cgroup{cgroupname, cpuset, memsize}, nil
}

// Attach attaches a task with PID p to the cgroup.
func (g *Cgroup) Attach(p int) error {
	var param *C.char

	param = C.CString(g.name)
	cg := C.cgroup_new_cgroup(param)
	if cg != nil {
		return errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	if ret := C.cgroup_get_cgroup(cg); ret != 0 {
		err := fmt.Errorf("Get cgroup information: %s(d)",
			C.cgroup_strerror(ret), ret)
		return err
	}

	// Attach task to the cgroup
	if ret := C.cgroup_attach_task_pid(cg, C.pid_t(p)); ret != 0 {
		err := fmt.Errorf("Attach task to cgroup: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return err
	}

	return nil
}

// Kill sends SIGKILL(9) to all PIDs associated with the given cgroup.
func (g *Cgroup) Kill() error {
	cgName := C.CString(g.name)
	cgCtrl := C.CString("memory")

	var pid C.pid_t
	var handle unsafe.Pointer

	for {
		ret := C.cgroup_get_task_begin(cgName, cgCtrl, &handle, &pid)
		C.cgroup_get_task_end(&handle)
		if ret == C.ECGEOF {
			break
		}
		if err := syscall.Kill(int(pid), syscall.SIGKILL); err != nil {
			return err
		}
	}
	return nil
}

// Delete removes the cgroup from the kernel.
func (g *Cgroup) Delete() error {
	var param *C.char

	param = C.CString(g.name)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		err := fmt.Errorf("cgroup_new_cgroup")
		return err
	}

	if ret := C.cgroup_get_cgroup(cg); ret != 0 {
		err := fmt.Errorf("Get cgroup information: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return err
	}

	// Clean up the cgroup
	if ret := C.cgroup_delete_cgroup(cg, 1); ret != 0 {
		err := fmt.Errorf("Deleteing cgroup: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return err
	}
	return nil
}
<commit_msg>cgroup: allow initialization of the cgroups library.<commit_after>//
// Copyright (c) 2016 Dennis Chen
//
// This file is part of Clashr.
//
// Clashr is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// Clashr is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
// more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Clashr.  If not, see <http://www.gnu.org/licenses/>.

// Package cgroup provides a large amount of functionality for properly
// implementing cgroups in the judging and tracking of programs in Clashr.
// Most of this work is inspired by the DOMJudge implementation runguard.c and
// attempts to mimic a majoritiy of it's behavior
//
package cgroup

// #cgo pkg-config: libcgroup
// #include <libcgroup.h>
import "C"

import (
	"errors"
	"fmt"
	"syscall"
	"unsafe"
)

// A uniform interface for the cgroup actions.
type Cgroup struct {
	name string
	cpus string
	mems int64
}

// Init must be called for the cgroup library to be avaliable.
func Init() error {
	if res := C.cgroup_init(); res != 0 {
		err := fmt.Errorf("Could not cgroup_init %s(%d)",
			C.cgroup_strerror(res), res)
		return err
	}
	return nil
}

// OutputStats returns the memory used (in bytes) by a process controlled by a
// cgroup.
func (g *Cgroup) OutputStats() (int64, error) {
	var param *C.char

	param = C.CString(g.name)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		return 0, errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	if ret := C.cgroup_get_cgroup(cg); ret != 0 {
		err := fmt.Errorf("Get cgroup information: %s(d)",
			C.cgroup_strerror(ret), ret)
		return 0, err
	}
	param = C.CString("memory")
	cgController := C.cgroup_get_controller(cg, param)

	var maxUsage C.int64_t
	param = C.CString("memory.memsw.max_usage_in_bytes")
	if ret := C.cgroup_get_value_int64(cgController, param, &maxUsage); ret != 0 {
		err := fmt.Errorf("Get cgroup value: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return 0, err
	}

	return int64(maxUsage), nil
}

// Create makes a new instance of the cgroup interface. It sets the memory
// limit of the cgroup to memsize, and the set of CPUs to use to cpuset. If
// memory does not need to be limited, set memsize to syscall.RLIMIT_INFINITY.
// Similarly, set cpuset to the empty string if CPUs do not need to be set.
func Create(cgroupname, cpuset string, memsize int64) (Cgroup, error) {
	var param *C.char

	param = C.CString(cgroupname)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		return Cgroup{}, errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	// Set memory restrictions. We limit both ram and ram+swap to the same
	// amount to prevent swapping.
	param = C.CString("memory")
	cgController := C.cgroup_add_controller(cg, param)

	mem := C.int64_t(memsize)
	param = C.CString("memory.limit_in_bytes")
	C.cgroup_add_value_int64(cgController, param, mem)
	param = C.CString("memory.memsw.limit_in_bytes")
	C.cgroup_add_value_int64(cgController, param, mem)

	// Setup CPU restrictions. The task is pinned to a specific set of CPUs
	// if a non-empty string is passed.
	if len(cpuset) > 0 {
		param = C.CString("cpuset")
		cgController = C.cgroup_add_controller(cg, param)

		var arg *C.char
		param = C.CString("cpuset.mems")
		arg = C.CString("0")
		C.cgroup_add_value_string(cgController, param, arg)
		param = C.CString("cpuset.cpus")
		arg = C.CString(cpuset)
		C.cgroup_add_value_string(cgController, param, arg)
	}

	// Perform the creation of the cgroup.
	if ret := C.cgroup_create_cgroup(cg, 1); ret != 0 {
		err := fmt.Errorf("Creating cgroup: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return Cgroup{}, err
	}
	return Cgroup{cgroupname, cpuset, memsize}, nil
}

// Attach attaches a task with PID p to the cgroup.
func (g *Cgroup) Attach(p int) error {
	var param *C.char

	param = C.CString(g.name)
	cg := C.cgroup_new_cgroup(param)
	if cg != nil {
		return errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	if ret := C.cgroup_get_cgroup(cg); ret != 0 {
		err := fmt.Errorf("Get cgroup information: %s(d)",
			C.cgroup_strerror(ret), ret)
		return err
	}

	// Attach task to the cgroup
	if ret := C.cgroup_attach_task_pid(cg, C.pid_t(p)); ret != 0 {
		err := fmt.Errorf("Attach task to cgroup: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return err
	}

	return nil
}

// Kill sends SIGKILL(9) to all PIDs associated with the given cgroup.
func (g *Cgroup) Kill() error {
	cgName := C.CString(g.name)
	cgCtrl := C.CString("memory")

	var pid C.pid_t
	var handle unsafe.Pointer

	for {
		ret := C.cgroup_get_task_begin(cgName, cgCtrl, &handle, &pid)
		C.cgroup_get_task_end(&handle)
		if ret == C.ECGEOF {
			break
		}
		if err := syscall.Kill(int(pid), syscall.SIGKILL); err != nil {
			return err
		}
	}
	return nil
}

// Delete removes the cgroup from the kernel.
func (g *Cgroup) Delete() error {
	var param *C.char

	param = C.CString(g.name)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		err := fmt.Errorf("cgroup_new_cgroup")
		return err
	}

	if ret := C.cgroup_get_cgroup(cg); ret != 0 {
		err := fmt.Errorf("Get cgroup information: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return err
	}

	// Clean up the cgroup
	if ret := C.cgroup_delete_cgroup(cg, 1); ret != 0 {
		err := fmt.Errorf("Deleteing cgroup: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package channels

import (
	"math/rand"
	"testing"
	"time"
)

func testChannel(t *testing.T, name string, ch Channel) {
	go func() {
		for i := 0; i < 1000; i++ {
			ch.In() <- i
		}
		ch.Close()
	}()
	for i := 0; i < 1000; i++ {
		val := <-ch.Out()
		if i != val.(int) {
			t.Fatal(name, "expected", i, "but got", val.(int))
		}
	}
}

func testChannelPair(t *testing.T, name string, in InChannel, out OutChannel) {
	go func() {
		for i := 0; i < 1000; i++ {
			in.In() <- i
		}
		in.Close()
	}()
	for i := 0; i < 1000; i++ {
		val := <-out.Out()
		if i != val.(int) {
			t.Fatal("pair", name, "expected", i, "but got", val.(int))
		}
	}
}

func TestPipe(t *testing.T) {
	a := NewNativeChannel(None)
	b := NewNativeChannel(None)

	Pipe(a, b)

	testChannelPair(t, "pipe", a, b)
}

func TestWeakPipe(t *testing.T) {
	a := NewNativeChannel(None)
	b := NewNativeChannel(None)

	WeakPipe(a, b)

	testChannelPair(t, "pipe", a, b)
}

func testMultiplex(t *testing.T, multi func (output SimpleInChannel, inputs ...SimpleOutChannel)) {
	a := NewNativeChannel(None)
	b := NewNativeChannel(None)

	multi(b, a)

	testChannelPair(t, "simple multiplex", a, b)

	a = NewNativeChannel(None)
	inputs := []Channel{
		NewNativeChannel(None),
		NewNativeChannel(None),
		NewNativeChannel(None),
		NewNativeChannel(None),
	}

	multi(a, inputs[0], inputs[1], inputs[2], inputs[3])

	go func() {
		rand.Seed(time.Now().Unix())
		for i := 0; i < 1000; i++ {
			inputs[rand.Intn(len(inputs))].In() <- i
		}
		for i := range inputs {
			inputs[i].Close()
		}
	}()
	for i := 0; i < 1000; i++ {
		val := <-a.Out()
		if i != val.(int) {
			t.Fatal("multiplexing expected", i, "but got", val.(int))
		}
	}
}

func TestMultiplex(t *testing.T) {
	testMultiplex(t, Multiplex)
}

func TestWeakMultiplex(t *testing.T) {
	testMultiplex(t, WeakMultiplex)
}

func testTee(t *testing.T, tee func (input SimpleOutChannel, outputs ...SimpleInChannel)) {
	a := NewNativeChannel(None)
	b := NewNativeChannel(None)

	tee(a, b)

	testChannelPair(t, "simple tee", a, b)

	a = NewNativeChannel(None)
	outputs := []Channel{
		NewNativeChannel(None),
		NewNativeChannel(None),
		NewNativeChannel(None),
		NewNativeChannel(None),
	}

	tee(a, outputs[0], outputs[1], outputs[2], outputs[3])

	go func() {
		for i := 0; i < 1000; i++ {
			a.In() <- i
		}
		a.Close()
	}()
	for i := 0; i < 1000; i++ {
		for _, output := range outputs {
			val := <-output.Out()
			if i != val.(int) {
				t.Fatal("teeing expected", i, "but got", val.(int))
			}
		}
	}
}

func TestTee(t *testing.T) {
	testTee(t, Tee)
}

func TestWeakTee(t *testing.T) {
	testTee(t, WeakTee)
}
<commit_msg>go fmt<commit_after>package channels

import (
	"math/rand"
	"testing"
	"time"
)

func testChannel(t *testing.T, name string, ch Channel) {
	go func() {
		for i := 0; i < 1000; i++ {
			ch.In() <- i
		}
		ch.Close()
	}()
	for i := 0; i < 1000; i++ {
		val := <-ch.Out()
		if i != val.(int) {
			t.Fatal(name, "expected", i, "but got", val.(int))
		}
	}
}

func testChannelPair(t *testing.T, name string, in InChannel, out OutChannel) {
	go func() {
		for i := 0; i < 1000; i++ {
			in.In() <- i
		}
		in.Close()
	}()
	for i := 0; i < 1000; i++ {
		val := <-out.Out()
		if i != val.(int) {
			t.Fatal("pair", name, "expected", i, "but got", val.(int))
		}
	}
}

func TestPipe(t *testing.T) {
	a := NewNativeChannel(None)
	b := NewNativeChannel(None)

	Pipe(a, b)

	testChannelPair(t, "pipe", a, b)
}

func TestWeakPipe(t *testing.T) {
	a := NewNativeChannel(None)
	b := NewNativeChannel(None)

	WeakPipe(a, b)

	testChannelPair(t, "pipe", a, b)
}

func testMultiplex(t *testing.T, multi func(output SimpleInChannel, inputs ...SimpleOutChannel)) {
	a := NewNativeChannel(None)
	b := NewNativeChannel(None)

	multi(b, a)

	testChannelPair(t, "simple multiplex", a, b)

	a = NewNativeChannel(None)
	inputs := []Channel{
		NewNativeChannel(None),
		NewNativeChannel(None),
		NewNativeChannel(None),
		NewNativeChannel(None),
	}

	multi(a, inputs[0], inputs[1], inputs[2], inputs[3])

	go func() {
		rand.Seed(time.Now().Unix())
		for i := 0; i < 1000; i++ {
			inputs[rand.Intn(len(inputs))].In() <- i
		}
		for i := range inputs {
			inputs[i].Close()
		}
	}()
	for i := 0; i < 1000; i++ {
		val := <-a.Out()
		if i != val.(int) {
			t.Fatal("multiplexing expected", i, "but got", val.(int))
		}
	}
}

func TestMultiplex(t *testing.T) {
	testMultiplex(t, Multiplex)
}

func TestWeakMultiplex(t *testing.T) {
	testMultiplex(t, WeakMultiplex)
}

func testTee(t *testing.T, tee func(input SimpleOutChannel, outputs ...SimpleInChannel)) {
	a := NewNativeChannel(None)
	b := NewNativeChannel(None)

	tee(a, b)

	testChannelPair(t, "simple tee", a, b)

	a = NewNativeChannel(None)
	outputs := []Channel{
		NewNativeChannel(None),
		NewNativeChannel(None),
		NewNativeChannel(None),
		NewNativeChannel(None),
	}

	tee(a, outputs[0], outputs[1], outputs[2], outputs[3])

	go func() {
		for i := 0; i < 1000; i++ {
			a.In() <- i
		}
		a.Close()
	}()
	for i := 0; i < 1000; i++ {
		for _, output := range outputs {
			val := <-output.Out()
			if i != val.(int) {
				t.Fatal("teeing expected", i, "but got", val.(int))
			}
		}
	}
}

func TestTee(t *testing.T) {
	testTee(t, Tee)
}

func TestWeakTee(t *testing.T) {
	testTee(t, WeakTee)
}
<|endoftext|>


<commit_before>// Package charge provides the /charges APIs
package charge

import (
	"errors"
	"fmt"
	"net/url"
	"strconv"

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

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

// New POSTs new charges.
// For more details see https://stripe.com/docs/api#create_charge.
func New(params *stripe.ChargeParams) (*stripe.Charge, error) {
	return getC().New(params)
}

func (c Client) New(params *stripe.ChargeParams) (*stripe.Charge, error) {
	body := &url.Values{
		"amount":   {strconv.FormatUint(params.Amount, 10)},
		"currency": {string(params.Currency)},
	}

	if len(params.Token) > 0 {
		body.Add("card", params.Token)
	} else if len(params.Customer) > 0 {
		body.Add("customer", params.Customer)
		if params.Card != nil {
			if len(params.Card.Token) > 0 {
				body.Add("card", params.Card.Token)
			} else {
				params.Card.AppendDetails(body, true)
			}
		}
	} else {
		err := errors.New("Invalid charge params: either customer, card Tok or card need to be set")
		return nil, err
	}

	if len(params.Desc) > 0 {
		body.Add("description", params.Desc)
	}

	if len(params.Statement) > 0 {
		body.Add("statement_description", params.Statement)
	}

	if len(params.Email) > 0 {
		body.Add("receipt_email", params.Email)
	}

	body.Add("capture", strconv.FormatBool(!params.NoCapture))

	token := c.Key
	if params.Fee > 0 {
		body.Add("application_fee", strconv.FormatUint(params.Fee, 10))
	}

	params.AppendTo(body)

	charge := &stripe.Charge{}
	err := c.B.Call("POST", "/charges", token, body, charge)

	return charge, err
}

// Get returns the details of a charge.
// For more details see https://stripe.com/docs/api#retrieve_charge.
func Get(id string, params *stripe.ChargeParams) (*stripe.Charge, error) {
	return getC().Get(id, params)
}

func (c Client) Get(id string, params *stripe.ChargeParams) (*stripe.Charge, error) {
	var body *url.Values

	if params != nil {
		body = &url.Values{}
		params.AppendTo(body)
	}

	charge := &stripe.Charge{}
	err := c.B.Call("GET", "/charges/"+id, c.Key, body, charge)

	return charge, err
}

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

func (c Client) Update(id string, params *stripe.ChargeParams) (*stripe.Charge, error) {
	var body *url.Values

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

		if len(params.Desc) > 0 {
			body.Add("description", params.Desc)
		}

		params.AppendTo(body)
	}

	charge := &stripe.Charge{}
	err := c.B.Call("POST", "/charges/"+id, c.Key, body, charge)

	return charge, err
}

// Capture captures a previously created charge with NoCapture set to true.
// For more details see https://stripe.com/docs/api#charge_capture.
func Capture(id string, params *stripe.CaptureParams) (*stripe.Charge, error) {
	return getC().Capture(id, params)
}

func (c Client) Capture(id string, params *stripe.CaptureParams) (*stripe.Charge, error) {
	var body *url.Values
	token := c.Key

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

		if params.Amount > 0 {
			body.Add("amount", strconv.FormatUint(params.Amount, 10))
		}

		if len(params.Email) > 0 {
			body.Add("receipt_email", params.Email)
		}

		if params.Fee > 0 {
			body.Add("application_fee", strconv.FormatUint(params.Fee, 10))
		}

		params.AppendTo(body)
	}

	charge := &stripe.Charge{}
	err := c.B.Call("POST", fmt.Sprintf("/charges/%v/capture", id), token, body, charge)

	return charge, err
}

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

func (c Client) List(params *stripe.ChargeListParams) *Iter {
	type chargeList struct {
		stripe.ListMeta
		Values []*stripe.Charge `json:"data"`
	}

	var body *url.Values
	var lp *stripe.ListParams

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

		if params.Created > 0 {
			body.Add("created", strconv.FormatInt(params.Created, 10))
		}

		if len(params.Customer) > 0 {
			body.Add("customer", params.Customer)
		}

		params.AppendTo(body)
		lp = &params.ListParams
	}

	return &Iter{stripe.GetIter(lp, body, func(b url.Values) ([]interface{}, stripe.ListMeta, error) {
		list := &chargeList{}
		err := c.B.Call("GET", "/charges", c.Key, &b, list)

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

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

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

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

func getC() Client {
	return Client{stripe.GetBackend(), stripe.Key}
}
<commit_msg>code reshuffled, commented<commit_after>// Package charge provides the /charges APIs
package charge

import (
	"errors"
	"fmt"
	"net/url"
	"strconv"

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

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

// New POSTs new charges.
// For more details see https://stripe.com/docs/api#create_charge.
func New(params *stripe.ChargeParams) (*stripe.Charge, error) {
	return getC().New(params)
}

func (c Client) New(params *stripe.ChargeParams) (*stripe.Charge, error) {
	body := &url.Values{
		"amount":   {strconv.FormatUint(params.Amount, 10)},
		"currency": {string(params.Currency)},
	}

	if len(params.Token) > 0 { // If card is token
		body.Add("card", params.Token)
	} else if len(params.Customer) > 0 { // If customer is present
		body.Add("customer", params.Customer)
		if params.Card != nil {
			if len(params.Card.Token) > 0 {
				body.Add("card", params.Card.Token) // If card.Token is card ID
			}
		}
	} else if params.Card != nil {
		params.Card.AppendDetails(body, true) // If neither token nor customer present, card is credit card details
	} else {
		err := errors.New("Invalid charge params: either customer, card Tok or card need to be set")
		return nil, err
	}

	if len(params.Desc) > 0 {
		body.Add("description", params.Desc)
	}

	if len(params.Statement) > 0 {
		body.Add("statement_description", params.Statement)
	}

	if len(params.Email) > 0 {
		body.Add("receipt_email", params.Email)
	}

	body.Add("capture", strconv.FormatBool(!params.NoCapture))

	token := c.Key
	if params.Fee > 0 {
		body.Add("application_fee", strconv.FormatUint(params.Fee, 10))
	}

	params.AppendTo(body)

	charge := &stripe.Charge{}
	err := c.B.Call("POST", "/charges", token, body, charge)

	return charge, err
}

// Get returns the details of a charge.
// For more details see https://stripe.com/docs/api#retrieve_charge.
func Get(id string, params *stripe.ChargeParams) (*stripe.Charge, error) {
	return getC().Get(id, params)
}

func (c Client) Get(id string, params *stripe.ChargeParams) (*stripe.Charge, error) {
	var body *url.Values

	if params != nil {
		body = &url.Values{}
		params.AppendTo(body)
	}

	charge := &stripe.Charge{}
	err := c.B.Call("GET", "/charges/"+id, c.Key, body, charge)

	return charge, err
}

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

func (c Client) Update(id string, params *stripe.ChargeParams) (*stripe.Charge, error) {
	var body *url.Values

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

		if len(params.Desc) > 0 {
			body.Add("description", params.Desc)
		}

		params.AppendTo(body)
	}

	charge := &stripe.Charge{}
	err := c.B.Call("POST", "/charges/"+id, c.Key, body, charge)

	return charge, err
}

// Capture captures a previously created charge with NoCapture set to true.
// For more details see https://stripe.com/docs/api#charge_capture.
func Capture(id string, params *stripe.CaptureParams) (*stripe.Charge, error) {
	return getC().Capture(id, params)
}

func (c Client) Capture(id string, params *stripe.CaptureParams) (*stripe.Charge, error) {
	var body *url.Values
	token := c.Key

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

		if params.Amount > 0 {
			body.Add("amount", strconv.FormatUint(params.Amount, 10))
		}

		if len(params.Email) > 0 {
			body.Add("receipt_email", params.Email)
		}

		if params.Fee > 0 {
			body.Add("application_fee", strconv.FormatUint(params.Fee, 10))
		}

		params.AppendTo(body)
	}

	charge := &stripe.Charge{}
	err := c.B.Call("POST", fmt.Sprintf("/charges/%v/capture", id), token, body, charge)

	return charge, err
}

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

func (c Client) List(params *stripe.ChargeListParams) *Iter {
	type chargeList struct {
		stripe.ListMeta
		Values []*stripe.Charge `json:"data"`
	}

	var body *url.Values
	var lp *stripe.ListParams

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

		if params.Created > 0 {
			body.Add("created", strconv.FormatInt(params.Created, 10))
		}

		if len(params.Customer) > 0 {
			body.Add("customer", params.Customer)
		}

		params.AppendTo(body)
		lp = &params.ListParams
	}

	return &Iter{stripe.GetIter(lp, body, func(b url.Values) ([]interface{}, stripe.ListMeta, error) {
		list := &chargeList{}
		err := c.B.Call("GET", "/charges", c.Key, &b, list)

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

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

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

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

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


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/pschlump/MiscLib"

	// JsonXScanner "www.2c-why.com/JsonX"
	"www.2c-why.com/JsonX"
)

//
//JxCli:
//	-i <fn> 	input
//	-j <fn>  	Dump output using JSON
/// -o <fn>      Output from the JxonX processor
//	-s			Setter for each field
//	-l			Line number where field set
//	-e 			Errors/Warnings
//

var Input = flag.String("input", "", "Input JsonX file")      // 1
var Json = flag.String("json", "", "Output as JSON")          // 2
var Output = flag.String("output", "", "Output as JsonX")     // 3
var OutMeta = flag.String("meta", "", "Output 'meta' data")   // 4
var OutGo = flag.String("go", "", "Output Go format")         // 8
var Debug = flag.String("debug", "", "Debug flags")           // 3
var InCfg = flag.String("cfg", "", "Input JsonX config file") // 9		// new config file [ meta/validate for interface{} ]

var ShowSetter = flag.Bool("setter", false, "Show who set a vairable") // 4
var ShowLineNo = flag.Bool("lineno", false, "Show line numbers")       // 5
var ShowErrors = flag.Bool("errors", false, "Show errors/warnings")    // 6
var ValidateData = flag.Bool("validate", false, "Validate Data")       // 7

func init() {
	flag.StringVar(Input, "i", "", "Input JsonX file")        // 1
	flag.StringVar(Json, "j", "", "Output as JSON")           // 2
	flag.StringVar(Output, "o", "", "Output as JsonX")        // 3
	flag.StringVar(OutMeta, "m", "", "Output 'meta' data")    // 4
	flag.StringVar(OutGo, "g", "", "Output in Go format")     // 8
	flag.StringVar(Debug, "D", "", "Debug flags")             // 5
	flag.StringVar(InCfg, "K", "", "Input JsonX config file") // 9

	flag.BoolVar(ShowSetter, "s", false, "Show who set a vairable") // 4
	flag.BoolVar(ShowLineNo, "l", false, "Show line numbers")       // 5
	flag.BoolVar(ShowErrors, "e", false, "Show errors/warnings")    // 6
	flag.BoolVar(ValidateData, "v", false, "Validate Data")         // 7
}

// ===============================================================================================================================================
func main() {

	flag.Parse()
	fns := flag.Args()
	if len(fns) != 0 {
		fmt.Fprintf(os.Stderr, "Usage: ./JxCli -i fn [ -K cfgFile.jsonx ] [ -j out ] [ -m metaout ] [ -D 'db,flags' ]\n")
		os.Exit(1)
	}

	JsonX.SetDebugFlags(*Debug)

	var Out interface{}

	In, err := ioutil.ReadFile(*Input)
	if err != nil {
		fmt.Printf("JxCli: Error returned from ReadFile: %s\n", err)
		os.Exit(1)
	}

	fn := *Input
	if JsonX.Db["dump-read-in"] {
		if JsonX.Db["no-color"] {
			fmt.Printf("File: %s Read in ->%s<-\n", fn, In)
		} else {
			fmt.Printf("%sFile: %s Read in ->%s<-%s\n", MiscLib.ColorCyan, fn, In, MiscLib.ColorReset)
		}
	}

	meta, err := JsonX.Unmarshal(fn, In, &Out)
	if err != nil {
		fmt.Printf("JxCli: Error returned from Unmarshal: %s\n", err)
		os.Exit(1)
	}

	// -o - not implemented yet.

	var fmeta, fjson *os.File

	if OutMeta != nil && *OutMeta == "-" {
		fmt.Fprintf(os.Stdout, "%s\n", JsonX.SVarI(meta)) // -m
	} else if OutMeta != nil && *OutMeta != "" {
		fmeta, err = Fopen(*OutMeta, "w")
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to open %s for JSON output, %s\n", *OutMeta, err)
			os.Exit(1)
		}
		defer fmeta.Close()
		fmt.Fprintf(fmeta, "%s\n", JsonX.SVarI(meta)) // -m
	}

	if Json != nil && *Json == "-" {
		fmt.Fprintf(os.Stdout, "%s\n", JsonX.SVarI(Out)) // -j
	} else if Json != nil && *Json != "" {
		fjson, err = Fopen(*Json, "w")
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to open %s for JSON output, %s\n", *Json, err)
			os.Exit(1)
		}
		defer fjson.Close()
		fmt.Fprintf(fjson, "%s\n", JsonX.SVarI(Out)) // -j
	}

	// -s -- who set
	// -l -- line numbers
	// -e -- error messages

	if *ValidateData {

		err = JsonX.ValidateValues(&Out, meta, "", "", "")
		if err != nil {
			// xyzzy
		}

		//if !CalledPostFuncJsonXScannerS1 {
		//	t.Errorf("Error: Expected A call to post-func for JsonX.S1, did not happen\n")
		//}

		// Test ValidateRequired - both success and fail, nested, in arrays
		errReq := JsonX.ValidateRequired(&Out, meta)
		if errReq == nil {
			// xyzzy
		}

		fmt.Printf("err=%s meta=%s\n", err, JsonX.SVarI(meta))
		msg, err := JsonX.ErrorSummary("text", &Out, meta)
		if err != nil {
			fmt.Printf("%s\n", msg)
		}

	}

}
<commit_msg>Making this MIT licensed<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/pschlump/MiscLib"

	JsonX "github.com/pschlump/JSONx"
)

//
//JxCli:
//	-i <fn> 	input
//	-j <fn>  	Dump output using JSON
/// -o <fn>      Output from the JxonX processor
//	-s			Setter for each field
//	-l			Line number where field set
//	-e 			Errors/Warnings
//

var Input = flag.String("input", "", "Input JsonX file")      // 1
var Json = flag.String("json", "", "Output as JSON")          // 2
var Output = flag.String("output", "", "Output as JsonX")     // 3
var OutMeta = flag.String("meta", "", "Output 'meta' data")   // 4
var OutGo = flag.String("go", "", "Output Go format")         // 8
var Debug = flag.String("debug", "", "Debug flags")           // 3
var InCfg = flag.String("cfg", "", "Input JsonX config file") // 9		// new config file [ meta/validate for interface{} ]

var ShowSetter = flag.Bool("setter", false, "Show who set a vairable") // 4
var ShowLineNo = flag.Bool("lineno", false, "Show line numbers")       // 5
var ShowErrors = flag.Bool("errors", false, "Show errors/warnings")    // 6
var ValidateData = flag.Bool("validate", false, "Validate Data")       // 7

func init() {
	flag.StringVar(Input, "i", "", "Input JsonX file")        // 1
	flag.StringVar(Json, "j", "", "Output as JSON")           // 2
	flag.StringVar(Output, "o", "", "Output as JsonX")        // 3
	flag.StringVar(OutMeta, "m", "", "Output 'meta' data")    // 4
	flag.StringVar(OutGo, "g", "", "Output in Go format")     // 8
	flag.StringVar(Debug, "D", "", "Debug flags")             // 5
	flag.StringVar(InCfg, "K", "", "Input JsonX config file") // 9

	flag.BoolVar(ShowSetter, "s", false, "Show who set a vairable") // 4
	flag.BoolVar(ShowLineNo, "l", false, "Show line numbers")       // 5
	flag.BoolVar(ShowErrors, "e", false, "Show errors/warnings")    // 6
	flag.BoolVar(ValidateData, "v", false, "Validate Data")         // 7
}

// ===============================================================================================================================================
func main() {

	flag.Parse()
	fns := flag.Args()
	if len(fns) != 0 {
		fmt.Fprintf(os.Stderr, "Usage: ./JxCli -i fn [ -K cfgFile.jsonx ] [ -j out ] [ -m metaout ] [ -D 'db,flags' ]\n")
		os.Exit(1)
	}

	JsonX.SetDebugFlags(*Debug)

	var Out interface{}

	In, err := ioutil.ReadFile(*Input)
	if err != nil {
		fmt.Printf("JxCli: Error returned from ReadFile: %s\n", err)
		os.Exit(1)
	}

	fn := *Input
	if JsonX.Db["dump-read-in"] {
		if JsonX.Db["no-color"] {
			fmt.Printf("File: %s Read in ->%s<-\n", fn, In)
		} else {
			fmt.Printf("%sFile: %s Read in ->%s<-%s\n", MiscLib.ColorCyan, fn, In, MiscLib.ColorReset)
		}
	}

	meta, err := JsonX.Unmarshal(fn, In, &Out)
	if err != nil {
		fmt.Printf("JxCli: Error returned from Unmarshal: %s\n", err)
		os.Exit(1)
	}

	// -o - not implemented yet.

	var fmeta, fjson *os.File

	if OutMeta != nil && *OutMeta == "-" {
		fmt.Fprintf(os.Stdout, "%s\n", JsonX.SVarI(meta)) // -m
	} else if OutMeta != nil && *OutMeta != "" {
		fmeta, err = Fopen(*OutMeta, "w")
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to open %s for JSON output, %s\n", *OutMeta, err)
			os.Exit(1)
		}
		defer fmeta.Close()
		fmt.Fprintf(fmeta, "%s\n", JsonX.SVarI(meta)) // -m
	}

	if Json != nil && *Json == "-" {
		fmt.Fprintf(os.Stdout, "%s\n", JsonX.SVarI(Out)) // -j
	} else if Json != nil && *Json != "" {
		fjson, err = Fopen(*Json, "w")
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to open %s for JSON output, %s\n", *Json, err)
			os.Exit(1)
		}
		defer fjson.Close()
		fmt.Fprintf(fjson, "%s\n", JsonX.SVarI(Out)) // -j
	}

	// -s -- who set
	// -l -- line numbers
	// -e -- error messages

	if *ValidateData {

		err = JsonX.ValidateValues(&Out, meta, "", "", "")
		if err != nil {
			// xyzzy
		}

		//if !CalledPostFuncJsonXScannerS1 {
		//	t.Errorf("Error: Expected A call to post-func for JsonX.S1, did not happen\n")
		//}

		// Test ValidateRequired - both success and fail, nested, in arrays
		errReq := JsonX.ValidateRequired(&Out, meta)
		if errReq == nil {
			// xyzzy
		}

		fmt.Printf("err=%s meta=%s\n", err, JsonX.SVarI(meta))
		msg, err := JsonX.ErrorSummary("text", &Out, meta)
		if err != nil {
			fmt.Printf("%s\n", msg)
		}

	}

}
<|endoftext|>


<commit_before>package compile

import (
	"github.com/tisp-lang/tisp/src/lib/core"
	"github.com/tisp-lang/tisp/src/lib/scalar"
	"github.com/tisp-lang/tisp/src/lib/std"
)

var goBuiltins = func() environment {
	e := newEnvironment(scalar.Convert)

	for _, nv := range []struct {
		name  string
		value *core.Thunk
	}{
		{"if", core.If},

		{"partial", core.Partial},

		{"first", core.First},
		{"rest", core.Rest},
		{"prepend", core.Prepend},

		{"typeOf", core.TypeOf},
		{"isOrdered", core.IsOrdered},

		{"+", core.Add},
		{"-", core.Sub},
		{"*", core.Mul},
		{"/", core.Div},
		{"//", core.FloorDiv},
		{"mod", core.Mod},
		{"**", core.Pow},

		{"=", std.Equal},
		{"<", std.Less},
		{"<=", std.LessEq},
		{">", std.Greater},
		{">=", std.GreaterEq},

		{"toStr", core.ToString},
		{"dump", core.Dump},

		{"delete", core.Delete},
		{"include", core.Include},
		{"insert", core.Insert},
		{"merge", core.Merge},
		{"size", core.Size},
		{"toList", core.ToList},

		{"dict", std.Dictionary},
		{"error", core.Error},

		{"y", std.Y},
		{"ys", std.Ys},

		{"par", std.Par},
		{"seq", std.Seq},
		{"rally", std.Rally},

		{"read", std.Read},
		{"write", std.Write},

		{"matchError", core.NewError("MatchError", "A value didn't match with any pattern.")},
		{"catch", core.Catch},

		{"pure", core.Pure},
	} {
		e.set(nv.name, nv.value)
		e.set("$"+nv.name, nv.value)
	}

	return e
}()

func builtins() environment {
	e := goBuiltins.copy()

	for n, t := range subModule(goBuiltins.copy(), "<builtins>", `
		(def (list ..xs) xs)

		(def (indexOf list elem . (index 0))
			(match list
				[] (error "ElementNotFoundError" "Could not find an element in a list")
				[first ..rest] (if (= first elem) index (indexOf rest elem . index (+ index 1)))))

		(def (map f l)
			(if (= l (list)) (list) (prepend (f (first l)) (map f (rest l)))))
	`) {
		e.set(n, t)
		e.set("$"+n, t)
	}

	return e
}
<commit_msg>Make list expressions available in builtin script<commit_after>package compile

import (
	"github.com/tisp-lang/tisp/src/lib/core"
	"github.com/tisp-lang/tisp/src/lib/scalar"
	"github.com/tisp-lang/tisp/src/lib/std"
)

var goBuiltins = func() environment {
	e := newEnvironment(scalar.Convert)

	for _, nv := range []struct {
		name  string
		value *core.Thunk
	}{
		{"if", core.If},

		{"partial", core.Partial},

		{"first", core.First},
		{"rest", core.Rest},
		{"prepend", core.Prepend},

		{"typeOf", core.TypeOf},
		{"isOrdered", core.IsOrdered},

		{"+", core.Add},
		{"-", core.Sub},
		{"*", core.Mul},
		{"/", core.Div},
		{"//", core.FloorDiv},
		{"mod", core.Mod},
		{"**", core.Pow},

		{"=", std.Equal},
		{"<", std.Less},
		{"<=", std.LessEq},
		{">", std.Greater},
		{">=", std.GreaterEq},

		{"toStr", core.ToString},
		{"dump", core.Dump},

		{"delete", core.Delete},
		{"include", core.Include},
		{"insert", core.Insert},
		{"merge", core.Merge},
		{"size", core.Size},
		{"toList", core.ToList},

		{"dict", std.Dictionary},
		{"error", core.Error},

		{"y", std.Y},
		{"ys", std.Ys},

		{"par", std.Par},
		{"seq", std.Seq},
		{"rally", std.Rally},

		{"read", std.Read},
		{"write", std.Write},

		{"matchError", core.NewError("MatchError", "A value didn't match with any pattern.")},
		{"catch", core.Catch},

		{"pure", core.Pure},
	} {
		e.set(nv.name, nv.value)
		e.set("$"+nv.name, nv.value)
	}

	return e
}()

func builtins() environment {
	e := goBuiltins.copy()

	for _, s := range []string{
		`
			(def (list ..xs) xs)
		`,
		`
			(def (indexOf list elem . (index 0))
				(match list
					[] (error "ElementNotFoundError" "Could not find an element in a list")
					[first ..rest] (if (= first elem) index (indexOf rest elem . index (+ index 1)))))

			(def (map f l)
				(if (= l []) [] (prepend (f (first l)) (map f (rest l)))))
		`,
	} {
		for n, t := range subModule(e.copy(), "<builtins>", s) {
			e.set(n, t)
			e.set("$"+n, t)
		}
	}

	return e
}
<|endoftext|>