<commit_before>/*******************************************************************************
The MIT License (MIT)

Copyright (c) 2013-2016 Hajime Nakagami

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/

package firebirdsql

import (
	"bytes"
	"container/list"
	"encoding/binary"
	"errors"
	"math/big"
	"net/url"
	"strconv"
	"strings"
	"time"
)

func str_to_bytes(s string) []byte {
	return []byte(s)
}

func int32_to_bytes(i32 int32) []byte {
	bs := []byte{
		byte(i32 & 0xFF),
		byte(i32 >> 8 & 0xFF),
		byte(i32 >> 16 & 0xFF),
		byte(i32 >> 24 & 0xFF),
	}
	return bs
}

func bint32_to_bytes(i32 int32) []byte {
	bs := []byte{
		byte(i32 >> 24 & 0xFF),
		byte(i32 >> 16 & 0xFF),
		byte(i32 >> 8 & 0xFF),
		byte(i32 & 0xFF),
	}
	return bs
}

func int16_to_bytes(i16 int16) []byte {
	bs := []byte{
		byte(i16 & 0xFF),
		byte(i16 >> 8 & 0xFF),
	}
	return bs
}
func bytes_to_str(b []byte) string {
	return string(b)
}

func bytes_to_bint32(b []byte) int32 {
	return int32(binary.BigEndian.Uint32(b))
}

func bytes_to_int32(b []byte) int32 {
	return int32(binary.LittleEndian.Uint32(b))
}

func bytes_to_bint16(b []byte) int16 {
	return int16(binary.BigEndian.Uint16(b))
}

func bytes_to_int16(b []byte) int16 {
	return int16(binary.LittleEndian.Uint16(b))
}

func bytes_to_bint64(b []byte) int64 {
	return int64(binary.BigEndian.Uint64(b))
}

func bytes_to_int64(b []byte) int64 {
	return int64(binary.LittleEndian.Uint64(b))
}

func bigFromHexString(s string) *big.Int {
	ret := new(big.Int)
	ret.SetString(s, 16)
	return ret
}

func bigFromString(s string) *big.Int {
	ret := new(big.Int)
	ret.SetString(s, 10)
	return ret
}

func bigToBytes(v *big.Int) []byte {
	buf := pad(v)
	for i, _ := range buf {
		if buf[i] != 0 {
			return buf[i:]
		}
	}

	return buf[:1] // 0
}

func bytesToBig(v []byte) (r *big.Int) {
	m := new(big.Int)
	m.SetInt64(256)
	a := new(big.Int)
	r = new(big.Int)
	r.SetInt64(0)
	for _, b := range v {
		r = r.Mul(r, m)
		r = r.Add(r, a.SetInt64(int64(b)))
	}
	return r
}

func flattenBytes(l *list.List) []byte {
	n := 0
	for e := l.Front(); e != nil; e = e.Next() {
		n += len((e.Value).([]byte))
	}

	bs := make([]byte, n)

	n = 0
	for e := l.Front(); e != nil; e = e.Next() {
		for i, b := range (e.Value).([]byte) {
			bs[n+i] = b
		}
		n += len((e.Value).([]byte))
	}

	return bs
}

func xdrBytes(bs []byte) []byte {
	// XDR encoding bytes
	n := len(bs)
	padding := 0
	if n%4 != 0 {
		padding = 4 - n%4
	}
	buf := make([]byte, 4+n+padding)
	buf[0] = byte(n >> 24 & 0xFF)
	buf[1] = byte(n >> 16 & 0xFF)
	buf[2] = byte(n >> 8 & 0xFF)
	buf[3] = byte(n & 0xFF)
	for i, b := range bs {
		buf[4+i] = b
	}
	return buf
}

func xdrString(s string) []byte {
	// XDR encoding string
	bs := bytes.NewBufferString(s).Bytes()
	return xdrBytes(bs)
}

func _int32ToBlr(i32 int32) ([]byte, []byte) {
	v := bytes.Join([][]byte{
		bint32_to_bytes(i32),
	}, nil)
	blr := []byte{8, 0}

	return blr, v
}

func _bytesToBlr(v []byte) ([]byte, []byte) {
	nbytes := len(v)
	pad_length := ((4 - nbytes) & 3)
	padding := make([]byte, pad_length)
	v = bytes.Join([][]byte{
		v,
		padding,
	}, nil)
	blr := []byte{14, byte(nbytes & 255), byte(nbytes >> 8)}
	return blr, v
}

func _convert_date(t time.Time) []byte {
	i := int(t.Month()) + 9
	jy := t.Year() + (i / 12) - 1
	jm := i % 12
	c := jy / 100
	jy -= 100 * c
	j := (146097*c)/4 + (1461*jy)/4 + (153*jm+2)/5 + t.Day() - 678882
	return bint32_to_bytes(int32(j))
}

func _convert_time(t time.Time) []byte {
	v := (t.Hour()*3600+t.Minute()*60+t.Second())*10000 + t.Nanosecond()/100000
	return bint32_to_bytes(int32(v))
}

func _dateToBlr(t time.Time) ([]byte, []byte) {
	v := bytes.Join([][]byte{
		_convert_date(t),
	}, nil)
	blr := []byte{12}
	return blr, v
}

func _timeToBlr(t time.Time) ([]byte, []byte) {
	v := bytes.Join([][]byte{
		_convert_time(t),
	}, nil)
	blr := []byte{13}
	return blr, v
}

func _timestampToBlr(t time.Time) ([]byte, []byte) {
	v := bytes.Join([][]byte{
		_convert_date(t),
		_convert_time(t),
	}, nil)

	blr := []byte{35}
	return blr, v
}

func split1(src string, delm string) (string, string) {
	for i := 0; i < len(src); i++ {
		if src[i:i+1] == delm {
			s1 := src[0:i]
			s2 := src[i+1:]
			return s1, s2
		}
	}
	return src, ""
}

func parseDSN(dsn string) (addr string, dbName string, user string, passwd string, options map[string]string, err error) {
	options = make(map[string]string)
	if !strings.HasPrefix(dsn, "firebird://") {
		dsn = "firebird://" + dsn
	}
	u, err := url.Parse(dsn)
	if err != nil {
		return
	}
	if u.User == nil {
		err = errors.New("User unknown")
		return
	}
	user = u.User.Username()
	passwd, _ = u.User.Password()
	addr = u.Host
	if !strings.ContainsRune(addr, ':') {
		addr += ":3050"
	}
	dbName = u.Path
	if !strings.ContainsRune(dbName[1:], '/') {
		dbName = dbName[1:]
	}

	//Windows Path
	if strings.ContainsRune(dbName[2:], ':') {
		dbName = dbName[1:]
	}

	m, _ := url.ParseQuery(u.RawQuery)

	var default_options = map[string]string{
		"auth_plugin_name":     "Srp",
		"column_name_to_lower": "false",
		"role":                 "",
		"timezone":             "",
		"wire_crypt":           "true",
	}

	for k, v := range default_options {
		values, ok := m[k]
		if ok {
			options[k] = values[0]
		} else {
			options[k] = v
		}
	}

	return
}

func convertToBool(s string, defaultValue bool) bool {
	v, err := strconv.ParseBool(s)
	if err != nil {
		v = defaultValue
	}
	return v
}

func calcBlr(xsqlda []xSQLVAR) []byte {
	// Calculate  BLR from XSQLVAR array.
	ln := len(xsqlda) * 2
	blr := make([]byte, (ln*4)+8)
	blr[0] = 5
	blr[1] = 2
	blr[2] = 4
	blr[3] = 0
	blr[4] = byte(ln & 255)
	blr[5] = byte(ln >> 8)
	n := 6

	for _, x := range xsqlda {
		sqlscale := x.sqlscale
		if sqlscale < 0 {
			sqlscale += 256
		}
		switch x.sqltype {
		case SQL_TYPE_VARYING:
			blr[n] = 37
			blr[n+1] = byte(x.sqllen & 255)
			blr[n+2] = byte(x.sqllen >> 8)
			n += 3
		case SQL_TYPE_TEXT:
			blr[n] = 14
			blr[n+1] = byte(x.sqllen & 255)
			blr[n+2] = byte(x.sqllen >> 8)
			n += 3
		case SQL_TYPE_LONG:
			blr[n] = 8
			blr[n+1] = byte(sqlscale)
			n += 2
		case SQL_TYPE_SHORT:
			blr[n] = 7
			blr[n+1] = byte(sqlscale)
			n += 2
		case SQL_TYPE_INT64:
			blr[n] = 16
			blr[n+1] = byte(sqlscale)
			n += 2
		case SQL_TYPE_QUAD:
			blr[n] = 9
			blr[n+1] = byte(sqlscale)
			n += 2
		case SQL_TYPE_BLOB:
			blr[n] = 9
			blr[n+1] = 0
			n += 2
		case SQL_TYPE_ARRAY:
			blr[n] = 9
			blr[n+1] = 0
			n += 2
		case SQL_TYPE_DOUBLE:
			blr[n] = 27
			n += 1
		case SQL_TYPE_FLOAT:
			blr[n] = 10
			n += 1
		case SQL_TYPE_D_FLOAT:
			blr[n] = 11
			n += 1
		case SQL_TYPE_DATE:
			blr[n] = 12
			n += 1
		case SQL_TYPE_TIME:
			blr[n] = 13
			n += 1
		case SQL_TYPE_TIMESTAMP:
			blr[n] = 35
			n += 1
		case SQL_TYPE_BOOLEAN:
			blr[n] = 23
			n += 1
		}
		// [blr_short, 0]
		blr[n] = 7
		blr[n+1] = 0
		n += 2
	}
	// [blr_end, blr_eoc]
	blr[n] = 255
	blr[n+1] = 76
	n += 2

	return blr[:n]
}
<commit_msg>calcBlr() support timezone and decfloat<commit_after>/*******************************************************************************
The MIT License (MIT)

Copyright (c) 2013-2016 Hajime Nakagami

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/

package firebirdsql

import (
	"bytes"
	"container/list"
	"encoding/binary"
	"errors"
	"math/big"
	"net/url"
	"strconv"
	"strings"
	"time"
)

func str_to_bytes(s string) []byte {
	return []byte(s)
}

func int32_to_bytes(i32 int32) []byte {
	bs := []byte{
		byte(i32 & 0xFF),
		byte(i32 >> 8 & 0xFF),
		byte(i32 >> 16 & 0xFF),
		byte(i32 >> 24 & 0xFF),
	}
	return bs
}

func bint32_to_bytes(i32 int32) []byte {
	bs := []byte{
		byte(i32 >> 24 & 0xFF),
		byte(i32 >> 16 & 0xFF),
		byte(i32 >> 8 & 0xFF),
		byte(i32 & 0xFF),
	}
	return bs
}

func int16_to_bytes(i16 int16) []byte {
	bs := []byte{
		byte(i16 & 0xFF),
		byte(i16 >> 8 & 0xFF),
	}
	return bs
}
func bytes_to_str(b []byte) string {
	return string(b)
}

func bytes_to_bint32(b []byte) int32 {
	return int32(binary.BigEndian.Uint32(b))
}

func bytes_to_int32(b []byte) int32 {
	return int32(binary.LittleEndian.Uint32(b))
}

func bytes_to_bint16(b []byte) int16 {
	return int16(binary.BigEndian.Uint16(b))
}

func bytes_to_int16(b []byte) int16 {
	return int16(binary.LittleEndian.Uint16(b))
}

func bytes_to_bint64(b []byte) int64 {
	return int64(binary.BigEndian.Uint64(b))
}

func bytes_to_int64(b []byte) int64 {
	return int64(binary.LittleEndian.Uint64(b))
}

func bigFromHexString(s string) *big.Int {
	ret := new(big.Int)
	ret.SetString(s, 16)
	return ret
}

func bigFromString(s string) *big.Int {
	ret := new(big.Int)
	ret.SetString(s, 10)
	return ret
}

func bigToBytes(v *big.Int) []byte {
	buf := pad(v)
	for i, _ := range buf {
		if buf[i] != 0 {
			return buf[i:]
		}
	}

	return buf[:1] // 0
}

func bytesToBig(v []byte) (r *big.Int) {
	m := new(big.Int)
	m.SetInt64(256)
	a := new(big.Int)
	r = new(big.Int)
	r.SetInt64(0)
	for _, b := range v {
		r = r.Mul(r, m)
		r = r.Add(r, a.SetInt64(int64(b)))
	}
	return r
}

func flattenBytes(l *list.List) []byte {
	n := 0
	for e := l.Front(); e != nil; e = e.Next() {
		n += len((e.Value).([]byte))
	}

	bs := make([]byte, n)

	n = 0
	for e := l.Front(); e != nil; e = e.Next() {
		for i, b := range (e.Value).([]byte) {
			bs[n+i] = b
		}
		n += len((e.Value).([]byte))
	}

	return bs
}

func xdrBytes(bs []byte) []byte {
	// XDR encoding bytes
	n := len(bs)
	padding := 0
	if n%4 != 0 {
		padding = 4 - n%4
	}
	buf := make([]byte, 4+n+padding)
	buf[0] = byte(n >> 24 & 0xFF)
	buf[1] = byte(n >> 16 & 0xFF)
	buf[2] = byte(n >> 8 & 0xFF)
	buf[3] = byte(n & 0xFF)
	for i, b := range bs {
		buf[4+i] = b
	}
	return buf
}

func xdrString(s string) []byte {
	// XDR encoding string
	bs := bytes.NewBufferString(s).Bytes()
	return xdrBytes(bs)
}

func _int32ToBlr(i32 int32) ([]byte, []byte) {
	v := bytes.Join([][]byte{
		bint32_to_bytes(i32),
	}, nil)
	blr := []byte{8, 0}

	return blr, v
}

func _bytesToBlr(v []byte) ([]byte, []byte) {
	nbytes := len(v)
	pad_length := ((4 - nbytes) & 3)
	padding := make([]byte, pad_length)
	v = bytes.Join([][]byte{
		v,
		padding,
	}, nil)
	blr := []byte{14, byte(nbytes & 255), byte(nbytes >> 8)}
	return blr, v
}

func _convert_date(t time.Time) []byte {
	i := int(t.Month()) + 9
	jy := t.Year() + (i / 12) - 1
	jm := i % 12
	c := jy / 100
	jy -= 100 * c
	j := (146097*c)/4 + (1461*jy)/4 + (153*jm+2)/5 + t.Day() - 678882
	return bint32_to_bytes(int32(j))
}

func _convert_time(t time.Time) []byte {
	v := (t.Hour()*3600+t.Minute()*60+t.Second())*10000 + t.Nanosecond()/100000
	return bint32_to_bytes(int32(v))
}

func _dateToBlr(t time.Time) ([]byte, []byte) {
	v := bytes.Join([][]byte{
		_convert_date(t),
	}, nil)
	blr := []byte{12}
	return blr, v
}

func _timeToBlr(t time.Time) ([]byte, []byte) {
	v := bytes.Join([][]byte{
		_convert_time(t),
	}, nil)
	blr := []byte{13}
	return blr, v
}

func _timestampToBlr(t time.Time) ([]byte, []byte) {
	v := bytes.Join([][]byte{
		_convert_date(t),
		_convert_time(t),
	}, nil)

	blr := []byte{35}
	return blr, v
}

func split1(src string, delm string) (string, string) {
	for i := 0; i < len(src); i++ {
		if src[i:i+1] == delm {
			s1 := src[0:i]
			s2 := src[i+1:]
			return s1, s2
		}
	}
	return src, ""
}

func parseDSN(dsn string) (addr string, dbName string, user string, passwd string, options map[string]string, err error) {
	options = make(map[string]string)
	if !strings.HasPrefix(dsn, "firebird://") {
		dsn = "firebird://" + dsn
	}
	u, err := url.Parse(dsn)
	if err != nil {
		return
	}
	if u.User == nil {
		err = errors.New("User unknown")
		return
	}
	user = u.User.Username()
	passwd, _ = u.User.Password()
	addr = u.Host
	if !strings.ContainsRune(addr, ':') {
		addr += ":3050"
	}
	dbName = u.Path
	if !strings.ContainsRune(dbName[1:], '/') {
		dbName = dbName[1:]
	}

	//Windows Path
	if strings.ContainsRune(dbName[2:], ':') {
		dbName = dbName[1:]
	}

	m, _ := url.ParseQuery(u.RawQuery)

	var default_options = map[string]string{
		"auth_plugin_name":     "Srp",
		"column_name_to_lower": "false",
		"role":                 "",
		"timezone":             "",
		"wire_crypt":           "true",
	}

	for k, v := range default_options {
		values, ok := m[k]
		if ok {
			options[k] = values[0]
		} else {
			options[k] = v
		}
	}

	return
}

func convertToBool(s string, defaultValue bool) bool {
	v, err := strconv.ParseBool(s)
	if err != nil {
		v = defaultValue
	}
	return v
}

func calcBlr(xsqlda []xSQLVAR) []byte {
	// Calculate  BLR from XSQLVAR array.
	ln := len(xsqlda) * 2
	blr := make([]byte, (ln*4)+8)
	blr[0] = 5
	blr[1] = 2
	blr[2] = 4
	blr[3] = 0
	blr[4] = byte(ln & 255)
	blr[5] = byte(ln >> 8)
	n := 6

	for _, x := range xsqlda {
		sqlscale := x.sqlscale
		if sqlscale < 0 {
			sqlscale += 256
		}
		switch x.sqltype {
		case SQL_TYPE_VARYING:
			blr[n] = 37
			blr[n+1] = byte(x.sqllen & 255)
			blr[n+2] = byte(x.sqllen >> 8)
			n += 3
		case SQL_TYPE_TEXT:
			blr[n] = 14
			blr[n+1] = byte(x.sqllen & 255)
			blr[n+2] = byte(x.sqllen >> 8)
			n += 3
		case SQL_TYPE_LONG:
			blr[n] = 8
			blr[n+1] = byte(sqlscale)
			n += 2
		case SQL_TYPE_SHORT:
			blr[n] = 7
			blr[n+1] = byte(sqlscale)
			n += 2
		case SQL_TYPE_INT64:
			blr[n] = 16
			blr[n+1] = byte(sqlscale)
			n += 2
		case SQL_TYPE_QUAD:
			blr[n] = 9
			blr[n+1] = byte(sqlscale)
			n += 2
		case SQL_TYPE_DEC_FIXED:
			blr[n] = 26
			blr[n+1] = byte(sqlscale)
			n += 2
		case SQL_TYPE_DOUBLE:
			blr[n] = 27
			n += 1
		case SQL_TYPE_FLOAT:
			blr[n] = 10
			n += 1
		case SQL_TYPE_D_FLOAT:
			blr[n] = 11
			n += 1
		case SQL_TYPE_DATE:
			blr[n] = 12
			n += 1
		case SQL_TYPE_TIME:
			blr[n] = 13
			n += 1
		case SQL_TYPE_TIMESTAMP:
			blr[n] = 35
			n += 1
		case SQL_TYPE_BLOB:
			blr[n] = 9
			blr[n+1] = 0
			n += 2
		case SQL_TYPE_ARRAY:
			blr[n] = 9
			blr[n+1] = 0
			n += 2
		case SQL_TYPE_BOOLEAN:
			blr[n] = 23
			n += 1
		case SQL_TYPE_DEC64:
			blr[n] = 24
			n += 1
		case SQL_TYPE_DEC128:
			blr[n] = 25
			n += 1
		case SQL_TYPE_TIME_TZ:
			blr[n] = 28
			n += 1
		case SQL_TYPE_TIMESTAMP_TZ:
			blr[n] = 29
			n += 1
		}
		// [blr_short, 0]
		blr[n] = 7
		blr[n+1] = 0
		n += 2
	}
	// [blr_end, blr_eoc]
	blr[n] = 255
	blr[n+1] = 76
	n += 2

	return blr[:n]
}
<|endoftext|>


<commit_before>package httpexpect

import (
	"github.com/yalp/jsonpath"
)

// Value provides methods to inspect attached interface{} object
// (Go representation of arbitrary JSON value) and cast it to
// concrete type.
type Value struct {
	chain chain
	value interface{}
}

// NewValue returns a new Value given a reporter used to report failures
// and value to be inspected.
//
// reporter should not be nil, but value may be nil.
//
// Example:
//  value := NewValue(t, map[string]interface{}{"foo": 123})
//  value.Object()
//
//  value := NewValue(t, []interface{}{"foo", 123})
//  value.Array()
//
//  value := NewValue(t, "foo")
//  value.String()
//
//  value := NewValue(t, 123)
//  value.Number()
//
//  value := NewValue(t, true)
//  value.Boolean()
//
//  value := NewValue(t, nil)
//  value.Null()
func NewValue(reporter Reporter, value interface{}) *Value {
	return &Value{makeChain(reporter), value}
}

// Raw returns underlying value attached to Value.
// This is the value originally passed to NewValue.
//
// Example:
//  value := NewValue(t, "foo")
//  assert.Equal(t, "foo", number.Raw().(string))
func (v *Value) Raw() interface{} {
	return v.value
}

// Object returns a new Object attached to underlying value.
//
// If underlying value is not an object (map[string]interface{}), failure is reported
// and empty (but non-nil) value is returned.
//
// Example:
//  value := NewValue(t, map[string]interface{}{"foo": 123})
//  value.Object().ContainsKey("foo")
func (v *Value) Object() *Object {
	data, ok := canonMap(&v.chain, v.value)
	if !ok {
		v.chain.fail("\nexpected object value (map or struct), but got:\n%s",
			dumpValue(v.value))
	}
	return &Object{v.chain, data}
}

// Array returns a new Array attached to underlying value.
//
// If underlying value is not an array ([]interface{}), failure is reported and empty
// (but non-nil) value is returned.
//
// Example:
//  value := NewValue(t, []interface{}{"foo", 123})
//  value.Array().Elements("foo", 123)
func (v *Value) Array() *Array {
	data, ok := canonArray(&v.chain, v.value)
	if !ok {
		v.chain.fail("\nexpected array value, but got:\n%s",
			dumpValue(v.value))
	}
	return &Array{v.chain, data}
}

// String returns a new String attached to underlying value.
//
// If underlying value is not string, failure is reported and empty (but non-nil)
// value is returned.
//
// Example:
//  value := NewValue(t, "foo")
//  value.String().EqualFold("FOO")
func (v *Value) String() *String {
	data, ok := v.value.(string)
	if !ok {
		v.chain.fail("\nexpected string value, but got:\n%s",
			dumpValue(v.value))
	}
	return &String{v.chain, data}
}

// Number returns a new Number attached to underlying value.
//
// If underlying value is not a number (numeric type convertible to float64), failure
// is reported and empty (but non-nil) value is returned.
//
// Example:
//  value := NewValue(t, 123)
//  value.Number().InRange(100, 200)
func (v *Value) Number() *Number {
	data, ok := canonNumber(&v.chain, v.value)
	if !ok {
		v.chain.fail("\nexpected numeric value, but got:\n%s",
			dumpValue(v.value))
	}
	return &Number{v.chain, data}
}

// Boolean returns a new Boolean attached to underlying value.
//
// If underlying value is not a bool, failure is reported and empty (but non-nil)
// value is returned.
//
// Example:
//  value := NewValue(t, true)
//  value.Boolean().True()
func (v *Value) Boolean() *Boolean {
	data, ok := v.value.(bool)
	if !ok {
		v.chain.fail("\nexpected boolean value, but got:\n%s",
			dumpValue(v.value))
	}
	return &Boolean{v.chain, data}
}

// Null succeedes if value is nil.
//
// Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
// is also treated as null value. Empty (non-nil) slice or map, empty string, and
// zero number are not treated as null value.
//
// Example:
//  value := NewValue(t, nil)
//  value.Null()
//
//  value := NewValue(t, []interface{}(nil))
//  value.Null()
func (v *Value) Null() *Value {
	data, ok := canonValue(&v.chain, v.value)
	if !ok {
		return v
	}
	if data != nil {
		v.chain.fail("\nexpected nil value, but got:\n%s",
			dumpValue(v.value))
	}
	return v
}

// NotNull succeedes if value is not nil.
//
// Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
// is also treated as null value. Empty (non-nil) slice or map, empty string, and
// zero number are not treated as null value.
//
// Example:
//  value := NewValue(t, "")
//  value.NotNull()
//
//  value := NewValue(t, make([]interface{}, 0)
//  value.Null()
func (v *Value) NotNull() *Value {
	data, ok := canonValue(&v.chain, v.value)
	if !ok {
		return v
	}
	if data == nil {
		v.chain.fail("\nexpected non-nil value, but got:\n%s",
			dumpValue(v.value))
	}
	return v
}

// Path returns a new Value object for child object(s) matching given
// JSONPath expression.
//
// JSONPath is a simple XPath-like query language.
// See http://goessner.net/articles/JsonPath/.
//
// We currently use https://github.com/yalp/jsonpath, which implements
// only a subset of JSONPath, yet useful for simple queries. It doesn't
// support expressions and requires double quotes for strings.
//
// Example 1:
//  json := `{"users": [{"name": "john"}, {"name": "bob"}]}`
//  value := NewValue(t, json)
//
//  value.Path("$.users[0].name").String().Equal("john")
//  value.Path("$.users[1].name").String().Equal("bob")
//
// Example 2:
//  json := `{"yfGH2a": {"user": "john"}, "f7GsDd": {"user": "john"}}`
//  value := NewValue(t, json)
//
//  for _, user := range value.Path("$..user").Array().Iter() {
//      user.String().Equal("john")
//  }
func (v *Value) Path(path string) *Value {
	if v.chain.failed() {
		return &Value{v.chain, nil}
	}

	result, err := jsonpath.Read(v.value, path)
	if err != nil {
		v.chain.fail(err.Error())
		return &Value{v.chain, nil}
	}

	return &Value{v.chain, result}
}
<commit_msg>Refactor Value<commit_after>package httpexpect

import (
	"github.com/yalp/jsonpath"
)

// Value provides methods to inspect attached interface{} object
// (Go representation of arbitrary JSON value) and cast it to
// concrete type.
type Value struct {
	chain chain
	value interface{}
}

// NewValue returns a new Value given a reporter used to report failures
// and value to be inspected.
//
// reporter should not be nil, but value may be nil.
//
// Example:
//  value := NewValue(t, map[string]interface{}{"foo": 123})
//  value.Object()
//
//  value := NewValue(t, []interface{}{"foo", 123})
//  value.Array()
//
//  value := NewValue(t, "foo")
//  value.String()
//
//  value := NewValue(t, 123)
//  value.Number()
//
//  value := NewValue(t, true)
//  value.Boolean()
//
//  value := NewValue(t, nil)
//  value.Null()
func NewValue(reporter Reporter, value interface{}) *Value {
	chain := makeChain(reporter)
	if value != nil {
		value, _ = canonValue(&chain, value)
	}
	return &Value{chain, value}
}

// Raw returns underlying value attached to Value.
// This is the value originally passed to NewValue, converted to canonical form.
//
// Example:
//  value := NewValue(t, "foo")
//  assert.Equal(t, "foo", number.Raw().(string))
func (v *Value) Raw() interface{} {
	return v.value
}

// Object returns a new Object attached to underlying value.
//
// If underlying value is not an object (map[string]interface{}), failure is reported
// and empty (but non-nil) value is returned.
//
// Example:
//  value := NewValue(t, map[string]interface{}{"foo": 123})
//  value.Object().ContainsKey("foo")
func (v *Value) Object() *Object {
	data, ok := v.value.(map[string]interface{})
	if !ok {
		v.chain.fail("\nexpected object value (map or struct), but got:\n%s",
			dumpValue(v.value))
	}
	return &Object{v.chain, data}
}

// Array returns a new Array attached to underlying value.
//
// If underlying value is not an array ([]interface{}), failure is reported and empty
// (but non-nil) value is returned.
//
// Example:
//  value := NewValue(t, []interface{}{"foo", 123})
//  value.Array().Elements("foo", 123)
func (v *Value) Array() *Array {
	data, ok := v.value.([]interface{})
	if !ok {
		v.chain.fail("\nexpected array value, but got:\n%s",
			dumpValue(v.value))
	}
	return &Array{v.chain, data}
}

// String returns a new String attached to underlying value.
//
// If underlying value is not string, failure is reported and empty (but non-nil)
// value is returned.
//
// Example:
//  value := NewValue(t, "foo")
//  value.String().EqualFold("FOO")
func (v *Value) String() *String {
	data, ok := v.value.(string)
	if !ok {
		v.chain.fail("\nexpected string value, but got:\n%s",
			dumpValue(v.value))
	}
	return &String{v.chain, data}
}

// Number returns a new Number attached to underlying value.
//
// If underlying value is not a number (numeric type convertible to float64), failure
// is reported and empty (but non-nil) value is returned.
//
// Example:
//  value := NewValue(t, 123)
//  value.Number().InRange(100, 200)
func (v *Value) Number() *Number {
	data, ok := v.value.(float64)
	if !ok {
		v.chain.fail("\nexpected numeric value, but got:\n%s",
			dumpValue(v.value))
	}
	return &Number{v.chain, data}
}

// Boolean returns a new Boolean attached to underlying value.
//
// If underlying value is not a bool, failure is reported and empty (but non-nil)
// value is returned.
//
// Example:
//  value := NewValue(t, true)
//  value.Boolean().True()
func (v *Value) Boolean() *Boolean {
	data, ok := v.value.(bool)
	if !ok {
		v.chain.fail("\nexpected boolean value, but got:\n%s",
			dumpValue(v.value))
	}
	return &Boolean{v.chain, data}
}

// Path returns a new Value object for child object(s) matching given
// JSONPath expression.
//
// JSONPath is a simple XPath-like query language.
// See http://goessner.net/articles/JsonPath/.
//
// We currently use https://github.com/yalp/jsonpath, which implements
// only a subset of JSONPath, yet useful for simple queries. It doesn't
// support expressions and requires double quotes for strings.
//
// Example 1:
//  json := `{"users": [{"name": "john"}, {"name": "bob"}]}`
//  value := NewValue(t, json)
//
//  value.Path("$.users[0].name").String().Equal("john")
//  value.Path("$.users[1].name").String().Equal("bob")
//
// Example 2:
//  json := `{"yfGH2a": {"user": "john"}, "f7GsDd": {"user": "john"}}`
//  value := NewValue(t, json)
//
//  for _, user := range value.Path("$..user").Array().Iter() {
//      user.String().Equal("john")
//  }
func (v *Value) Path(path string) *Value {
	if v.chain.failed() {
		return &Value{v.chain, nil}
	}

	result, err := jsonpath.Read(v.value, path)
	if err != nil {
		v.chain.fail(err.Error())
		return &Value{v.chain, nil}
	}

	return &Value{v.chain, result}
}

// Null succeedes if value is nil.
//
// Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
// is also treated as null value. Empty (non-nil) slice or map, empty string, and
// zero number are not treated as null value.
//
// Example:
//  value := NewValue(t, nil)
//  value.Null()
//
//  value := NewValue(t, []interface{}(nil))
//  value.Null()
func (v *Value) Null() *Value {
	if v.value != nil {
		v.chain.fail("\nexpected nil value, but got:\n%s",
			dumpValue(v.value))
	}
	return v
}

// NotNull succeedes if value is not nil.
//
// Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
// is also treated as null value. Empty (non-nil) slice or map, empty string, and
// zero number are not treated as null value.
//
// Example:
//  value := NewValue(t, "")
//  value.NotNull()
//
//  value := NewValue(t, make([]interface{}, 0)
//  value.Null()
func (v *Value) NotNull() *Value {
	if v.value == nil {
		v.chain.fail("\nexpected non-nil value, but got:\n%s",
			dumpValue(v.value))
	}
	return v
}
<|endoftext|>


<commit_before>package video

import (
	"encoding/hex"
	"fmt"
	"image/color"
	"strings"
)

const (
	Black = iota
	White
	Red
	Cyan
	Purple
	Green
	Blue
	Yellow
	Orange
	Brown
	LightRed
	DarkGrey
	MediumGrey
	LightGreen
	LightBlue
	LightGrey
)

func Palette(name string) []color.Color {
	hexValues, ok := paletteMap[name]
	if !ok {
		panic(fmt.Sprintf("breadbox/video: Invalid palette name %v", name))
	}
	colors := make([]color.Color, 16)
	for i, value := range strings.Split(hexValues, ":") {
		colors[i] = hexColor(value)
	}
	return colors
}

func hexColor(value string) color.Color {
	rgb, err := hex.DecodeString(value)
	if err != nil {
		panic(err)
	}
	return color.RGBA{rgb[0], rgb[1], rgb[2], 255}
}

var paletteMap = map[string]string{
	"pepto":    "000000:ffffff:68372b:70a4b2:6f3d86:588d43:352879:b8c76f:6f4f25:433900:9a6759:444444:6c6c6c:9ad284:6c5eb5:959595",
	"levy":     "040204:fcfefc:cc3634:84f2dc:cc5ac4:5cce34:4436cc:f4ee5c:d47e34:945e34:fc9a94:5c5a5c:8c8e8c:9cfe9c:74a2ec:c4c2c4",
	"vice":     "000000:fdfefc:be1a24:30e6c6:b41ae2:1fd21e:211bae:dff60a:b84104:6a3304:fe4a57:424540:70746f:59fe59:5f53fe:a4a7a2",
	"vice-old": "000000:d5d5d5:72352c:659fa6:733a91:568d35:2e237d:aeb75e:774f1e:4b3c00:9c635a:474747:6b6b6b:8fc271:675db6:8f8f8f"}
<commit_msg>Added comments.<commit_after>// Package video implements constants and functions related to
// the VIC-II video interface chip, such as colors.

package video

import (
	"encoding/hex"
	"fmt"
	"image/color"
	"strings"
)

// Color index names
const (
	Black = iota
	White
	Red
	Cyan
	Purple
	Green
	Blue
	Yellow
	Orange
	Brown
	LightRed
	DarkGrey
	MediumGrey
	LightGreen
	LightBlue
	LightGrey
)

// Palette looks up a color set by name and returns an array of Color
// values corresponding to each 16 colors in the set.
// Valid names are: "pepto", "levy", "vice" and "vice-old"
func Palette(name string) []color.Color {
	hexValues, ok := paletteMap[name]
	if !ok {
		panic(fmt.Sprintf("breadbox/video: Invalid palette name %q", name))
	}
	colors := make([]color.Color, 16)
	for i, value := range strings.Split(hexValues, ":") {
		colors[i] = hexColor(value)
	}
	return colors
}

func hexColor(value string) color.Color {
	rgb, err := hex.DecodeString(value)
	if err != nil {
		panic(err)
	}
	return color.RGBA{rgb[0], rgb[1], rgb[2], 255}
}

var paletteMap = map[string]string{
	"pepto":    "000000:ffffff:68372b:70a4b2:6f3d86:588d43:352879:b8c76f:6f4f25:433900:9a6759:444444:6c6c6c:9ad284:6c5eb5:959595",
	"levy":     "040204:fcfefc:cc3634:84f2dc:cc5ac4:5cce34:4436cc:f4ee5c:d47e34:945e34:fc9a94:5c5a5c:8c8e8c:9cfe9c:74a2ec:c4c2c4",
	"vice":     "000000:fdfefc:be1a24:30e6c6:b41ae2:1fd21e:211bae:dff60a:b84104:6a3304:fe4a57:424540:70746f:59fe59:5f53fe:a4a7a2",
	"vice-old": "000000:d5d5d5:72352c:659fa6:733a91:568d35:2e237d:aeb75e:774f1e:4b3c00:9c635a:474747:6b6b6b:8fc271:675db6:8f8f8f"}
<|endoftext|>


<commit_before>package youtube

import (
	"bufio"
	"errors"
	"html"
	"net/url"
	"regexp"
	"strconv"
	"strings"
)

const (
	videoURL     = "www.youtube.com/watch"
	videoInfoURL = "www.youtube.com/get_video_info"
)

var (
	playerJsReg  = regexp.MustCompile(`"js"\s*:\s*"(.+?)"`)
	urlMapReg    = regexp.MustCompile(`"url_encoded_fmt_stream_map": "(.+?)"`)
	videoDescReg = regexp.MustCompile(`content="(.+?)"`)
)

type Video struct {
	Id          string
	Title       string
	Duration    int
	Description string
	ViewCount   int64
	Rating      float64
	Formats     []*VideoFormat
}

type VideoFormat struct {
	Itag    int
	Type    string
	Quality string
	URL     string
}

func GetVideo(id string) (*Video, error) {
	params := url.Values{"video_id": {id}, "el": {"detailpage"}}.Encode()
	videoURL := url.URL{Host: videoInfoURL, Scheme: "https", RawQuery: params}

	data, err := getURLData(videoURL.String())
	if err != nil {
		return nil, err
	}

	vals, err := url.ParseQuery(string(data))
	if err != nil {
		return nil, err
	}

	title := vals.Get("title")
	if title == "" {
		return nil, errors.New("Could not get video title")
	}

	duration, err := strconv.Atoi(vals.Get("length_seconds"))
	if err != nil {
		return nil, errors.New("Could not get video duration")
	}

	viewCount, err := strconv.ParseInt(vals.Get("view_count"), 10, 64)
	if err != nil {
		return nil, errors.New("Could not get video view count")
	}

	rating, err := strconv.ParseFloat(vals.Get("avg_rating"), 64)
	if err != nil {
		return nil, errors.New("Could not get video rating")
	}

	video := &Video{
		Id:          id,
		Title:       title,
		Duration:    duration,
		Description: "",
		ViewCount:   viewCount,
		Rating:      rating,
	}

	return video, video.ReadFormats()
}

func (v *Video) ReadFormats() error {
	v.Formats = []*VideoFormat{}

	params := url.Values{"v": {v.Id}}.Encode()
	videoURL := url.URL{Host: videoURL, Scheme: "https", RawQuery: params}

	data, err := getURLData(videoURL.String())
	if err != nil {
		return err
	}

	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	for scanner.Scan() {
		line := scanner.Text()

		// Try and read the description of the video if not present
		if v.Description == "" {
			if strings.Contains(line, "<meta name=\"description\"") {
				matches := videoDescReg.FindStringSubmatch(line)
				if matches != nil && len(matches) > 1 {
					v.Description = html.UnescapeString(matches[1])
				}

				continue
			}
		}

		if !strings.Contains(line, "ytplayer.config") {
			continue
		}

		// Get player js url
		matches := playerJsReg.FindStringSubmatch(line)
		if matches == nil || len(matches) <= 1 {
			return errors.New("Could not find the url of the js player")
		}

		jsURL := strings.Replace(matches[1], "\\/", "/", -1)
		jsData, err := getURLData(strings.Replace(jsURL, "//", "https://", 1))
		if err != nil {
			return err
		}

		// Get format stream map
		matches = urlMapReg.FindStringSubmatch(line)
		if matches == nil || len(matches) <= 1 {
			return errors.New("Could not find format stream map")
		}

		fmtStreamMap := strings.Replace(matches[1], "\\u0026", "&", -1)
		v.Formats, err = parseFormats(fmtStreamMap, jsData)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Fix Percent Encoded Host<commit_after>package youtube

import (
	"bufio"
	"errors"
	"html"
	"net/url"
	"regexp"
	"strconv"
	"strings"
)

const (
	hostName     = "www.youtube.com"
	videoURL     = "/watch"
	videoInfoURL = "/get_video_info"
)

var (
	playerJsRe  = regexp.MustCompile(`"js"\s*:\s*"(.+?)"`)
	urlMapRe    = regexp.MustCompile(`encoded_fmt_stream_map"\s*:\s*"(.+?)"`)
	videoDescRe = regexp.MustCompile(`content="(.+?)"`)
)

type Video struct {
	Id          string
	Title       string
	Duration    int
	Description string
	ViewCount   int64
	Rating      float64
	Formats     []*VideoFormat
}

type VideoFormat struct {
	Itag    int
	Type    string
	Quality string
	URL     string
}

func GetVideo(id string) (*Video, error) {
	params := url.Values{"video_id": {id}, "el": {"detailpage"}}.Encode()
	videoURL := url.URL{Host: hostName, Path: videoInfoURL,
		Scheme: "https", RawQuery: params}

	data, err := getURLData(videoURL.String())
	if err != nil {
		return nil, err
	}

	vals, err := url.ParseQuery(string(data))
	if err != nil {
		return nil, err
	}

	title := vals.Get("title")
	if title == "" {
		return nil, errors.New("Could not get video title")
	}

	duration, err := strconv.Atoi(vals.Get("length_seconds"))
	if err != nil {
		return nil, errors.New("Could not get video duration")
	}

	viewCount, err := strconv.ParseInt(vals.Get("view_count"), 10, 64)
	if err != nil {
		return nil, errors.New("Could not get video view count")
	}

	rating, err := strconv.ParseFloat(vals.Get("avg_rating"), 64)
	if err != nil {
		return nil, errors.New("Could not get video rating")
	}

	video := &Video{
		Id:          id,
		Title:       title,
		Duration:    duration,
		Description: "",
		ViewCount:   viewCount,
		Rating:      rating,
	}

	return video, video.ReadFormats()
}

func (v *Video) ReadFormats() error {
	v.Formats = []*VideoFormat{}

	params := url.Values{"v": {v.Id}}.Encode()
	videoURL := url.URL{Host: hostName, Path: videoURL,
		Scheme: "https", RawQuery: params}

	data, err := getURLData(videoURL.String())
	if err != nil {
		return err
	}

	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	for scanner.Scan() {
		line := scanner.Text()

		// Try and read the description of the video if not present
		if v.Description == "" {
			if strings.Contains(line, "<meta name=\"description\"") {
				matches := videoDescRe.FindStringSubmatch(line)
				if matches != nil && len(matches) > 1 {
					v.Description = html.UnescapeString(matches[1])
				}

				continue
			}
		}

		if !strings.Contains(line, "ytplayer.config") {
			continue
		}

		// Get player js url
		matches := playerJsRe.FindStringSubmatch(line)
		if matches == nil || len(matches) <= 1 {
			return errors.New("Could not find the url of the js player")
		}

		jsURL := strings.Replace(matches[1], "\\/", "/", -1)
		jsData, err := getURLData(strings.Replace(jsURL, "//", "https://", 1))
		if err != nil {
			return err
		}

		// Get format stream map
		matches = urlMapRe.FindStringSubmatch(line)
		if matches == nil || len(matches) <= 1 {
			return errors.New("Could not find format stream map")
		}

		fmtStreamMap := strings.Replace(matches[1], "\\u0026", "&", -1)
		v.Formats, err = parseFormats(fmtStreamMap, jsData)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>//https:// Code generated by protoc-gen-go from "examples/echo/echoservice/echoservice.proto"
// DO NOT EDIT!

package echoservice

import proto "code.google.com/p/goprotobuf/proto"
import "math"

import "net"
import "net/rpc"
import "github.com/kylelemons/go-rpcgen/codec"
import "net/url"
import "net/http"
import "github.com/kylelemons/go-rpcgen/webrpc"

// Reference proto and math imports to suppress error if they are not otherwise used.
var _ = proto.GetString
var _ = math.Inf

type Payload struct {
	Message          *string `protobuf:"bytes,1,req,name=message" json:"message,omitempty"`
	XXX_unrecognized []byte  `json:",omitempty"`
}

func (this *Payload) Reset()         { *this = Payload{} }
func (this *Payload) String() string { return proto.CompactTextString(this) }

func init() {
}

// EchoService is an interface satisfied by the generated client and
// which must be implemented by the object wrapped by the server.
type EchoService interface {
	Echo(in *Payload, out *Payload) error
}

// internal wrapper for type-safe RPC calling
type rpcEchoServiceClient struct {
	*rpc.Client
}

func (this rpcEchoServiceClient) Echo(in *Payload, out *Payload) error {
	return this.Call("EchoService.Echo", in, out)
}

// NewEchoServiceClient returns an *rpc.Client wrapper for calling the methods of
// EchoService remotely.
func NewEchoServiceClient(conn net.Conn) EchoService {
	return rpcEchoServiceClient{rpc.NewClientWithCodec(codec.NewClientCodec(conn))}
}

// ServeEchoService serves the given EchoService backend implementation on conn.
func ServeEchoService(conn net.Conn, backend EchoService) error {
	srv := rpc.NewServer()
	if err := srv.RegisterName("EchoService", backend); err != nil {
		return err
	}
	srv.ServeCodec(codec.NewServerCodec(conn))
	return nil
}

// DialEchoService returns a EchoService for calling the EchoService servince at addr (TCP).
func DialEchoService(addr string) (EchoService, error) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}
	return NewEchoServiceClient(conn), nil
}

// ListenAndServeEchoService serves the given EchoService backend implementation
// on all connections accepted as a result of listening on addr (TCP).
func ListenAndServeEchoService(addr string, backend EchoService) error {
	clients, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	srv := rpc.NewServer()
	if err := srv.RegisterName("EchoService", backend); err != nil {
		return err
	}
	for {
		conn, err := clients.Accept()
		if err != nil {
			return err
		}
		go srv.ServeCodec(codec.NewServerCodec(conn))
	}
	panic("unreachable")
}

// EchoServiceWeb is the web-based RPC version of the interface which
// must be implemented by the object wrapped by the webrpc server.
type EchoServiceWeb interface {
	Echo(r *http.Request, in *Payload, out *Payload) error
}

// internal wrapper for type-safe webrpc calling
type rpcEchoServiceWebClient struct {
	remote   *url.URL
	protocol webrpc.Protocol
}

func (this rpcEchoServiceWebClient) Echo(in *Payload, out *Payload) error {
	return webrpc.Post(this.protocol, this.remote, "/EchoService/Echo", in, out)
}

// Register a EchoServiceWeb implementation with the given webrpc ServeMux.
// If mux is nil, the default webrpc.ServeMux is used.
func RegisterEchoServiceWeb(this EchoServiceWeb, mux webrpc.ServeMux) error {
	if mux == nil {
		mux = webrpc.DefaultServeMux
	}
	if err := mux.Handle("/EchoService/Echo", func(c *webrpc.Call) error {
		in, out := new(Payload), new(Payload)
		if err := c.ReadRequest(in); err != nil {
			return err
		}
		if err := this.Echo(c.Request, in, out); err != nil {
			return err
		}
		return c.WriteResponse(out)
	}); err != nil {
		return err
	}
	return nil
}

// NewEchoServiceWebClient returns a webrpc wrapper for calling the methods of EchoService
// remotely via the web.  The remote URL is the base URL of the webrpc server.
func NewEchoServiceWebClient(pro webrpc.Protocol, remote *url.URL) EchoService {
	return rpcEchoServiceWebClient{remote, pro}
}
<commit_msg>regenerate<commit_after>// Code generated by protoc-gen-go from "examples/echo/echoservice/echoservice.proto"
// DO NOT EDIT!

package echoservice

import proto "code.google.com/p/goprotobuf/proto"
import "math"

import "net"
import "net/rpc"
import "github.com/kylelemons/go-rpcgen/codec"
import "net/url"
import "net/http"
import "github.com/kylelemons/go-rpcgen/webrpc"

// Reference proto and math imports to suppress error if they are not otherwise used.
var _ = proto.GetString
var _ = math.Inf

type Payload struct {
	Message          *string `protobuf:"bytes,1,req,name=message" json:"message,omitempty"`
	XXX_unrecognized []byte  `json:",omitempty"`
}

func (this *Payload) Reset()         { *this = Payload{} }
func (this *Payload) String() string { return proto.CompactTextString(this) }

func init() {
}

// EchoService is an interface satisfied by the generated client and
// which must be implemented by the object wrapped by the server.
type EchoService interface {
	Echo(in *Payload, out *Payload) error
}

// internal wrapper for type-safe RPC calling
type rpcEchoServiceClient struct {
	*rpc.Client
}

func (this rpcEchoServiceClient) Echo(in *Payload, out *Payload) error {
	return this.Call("EchoService.Echo", in, out)
}

// NewEchoServiceClient returns an *rpc.Client wrapper for calling the methods of
// EchoService remotely.
func NewEchoServiceClient(conn net.Conn) EchoService {
	return rpcEchoServiceClient{rpc.NewClientWithCodec(codec.NewClientCodec(conn))}
}

// ServeEchoService serves the given EchoService backend implementation on conn.
func ServeEchoService(conn net.Conn, backend EchoService) error {
	srv := rpc.NewServer()
	if err := srv.RegisterName("EchoService", backend); err != nil {
		return err
	}
	srv.ServeCodec(codec.NewServerCodec(conn))
	return nil
}

// DialEchoService returns a EchoService for calling the EchoService servince at addr (TCP).
func DialEchoService(addr string) (EchoService, error) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}
	return NewEchoServiceClient(conn), nil
}

// ListenAndServeEchoService serves the given EchoService backend implementation
// on all connections accepted as a result of listening on addr (TCP).
func ListenAndServeEchoService(addr string, backend EchoService) error {
	clients, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	srv := rpc.NewServer()
	if err := srv.RegisterName("EchoService", backend); err != nil {
		return err
	}
	for {
		conn, err := clients.Accept()
		if err != nil {
			return err
		}
		go srv.ServeCodec(codec.NewServerCodec(conn))
	}
	panic("unreachable")
}

// EchoServiceWeb is the web-based RPC version of the interface which
// must be implemented by the object wrapped by the webrpc server.
type EchoServiceWeb interface {
	Echo(r *http.Request, in *Payload, out *Payload) error
}

// internal wrapper for type-safe webrpc calling
type rpcEchoServiceWebClient struct {
	remote   *url.URL
	protocol webrpc.Protocol
}

func (this rpcEchoServiceWebClient) Echo(in *Payload, out *Payload) error {
	return webrpc.Post(this.protocol, this.remote, "/EchoService/Echo", in, out)
}

// Register a EchoServiceWeb implementation with the given webrpc ServeMux.
// If mux is nil, the default webrpc.ServeMux is used.
func RegisterEchoServiceWeb(this EchoServiceWeb, mux webrpc.ServeMux) error {
	if mux == nil {
		mux = webrpc.DefaultServeMux
	}
	if err := mux.Handle("/EchoService/Echo", func(c *webrpc.Call) error {
		in, out := new(Payload), new(Payload)
		if err := c.ReadRequest(in); err != nil {
			return err
		}
		if err := this.Echo(c.Request, in, out); err != nil {
			return err
		}
		return c.WriteResponse(out)
	}); err != nil {
		return err
	}
	return nil
}

// NewEchoServiceWebClient returns a webrpc wrapper for calling the methods of EchoService
// remotely via the web.  The remote URL is the base URL of the webrpc server.
func NewEchoServiceWebClient(pro webrpc.Protocol, remote *url.URL) EchoService {
	return rpcEchoServiceWebClient{remote, pro}
}
<|endoftext|>


<commit_before>package datatype

/*
#cgo pkg-config: libqrencode
#include <stdlib.h>
#include <qrencode.h>
*/
import "C"

import "unsafe"

var qrcodeList *C.QRcode_List

// CreateQRCodes creates multiple QR Codes using structured append
func CreateQRCodes(data []byte) {
	qrcodeList = C.QRcode_encodeDataStructured(C.int(len(data)), (*C.uchar)(unsafe.Pointer(&data[0])), C.int(40), C.QR_ECLEVEL_L)
}

// Next increments QRcode_List pointer to the next element
func Next() {
	qrcodeList = (*C.QRcode_List)(qrcodeList.next)
}

// Code returns a QRcode struct of the QR Code
func Code() *QRcode {
	return CreateQRCode(qrcodeList.code)
}

// Free frees the QR Code List
func Free() {
	C.QRcode_List_free(qrcodeList)
}
<commit_msg>Lazy load QRCode<commit_after>package datatype

/*
#cgo pkg-config: libqrencode
#include <stdlib.h>
#include <qrencode.h>
*/
import "C"

import "unsafe"

var qrcodeList *C.QRcode_List
var qrcode *QRcode

// CreateQRCodes creates multiple QR Codes using structured append
func CreateQRCodes(data []byte) {
	qrcodeList = C.QRcode_encodeDataStructured(C.int(len(data)), (*C.uchar)(unsafe.Pointer(&data[0])), C.int(40), C.QR_ECLEVEL_L)
}

// Next increments QRcode_List pointer to the next element
func Next() {
	qrcodeList = (*C.QRcode_List)(qrcodeList.next)
	qrcode = nil
}

// Code returns a QRcode struct of the QR Code
func Code() *QRcode {
	if qrcodeList == nil {
		return nil
	}

	if qrcode == nil {
		qrcode = CreateQRCode(qrcodeList.code)
	}

	return qrcode
}

// Size returns the size of the QR Code List
func Size() int {
	return int(C.QRcode_List_size(qrcodeList))
}

// Free frees the QR Code List
func Free() {
	C.QRcode_List_free(qrcodeList)
}
<|endoftext|>


<commit_before>package common

import (
	"crypto/ecdsa"
	"errors"
	"sync"
	"time"

	jwt "github.com/dgrijalva/jwt-go"
)

// JWTManager interface to manage APNS JWT
type JWTManager interface {
	// GenerateToken returns a token used for APNS connection
	// Returns error if fails to serialize or sign the token
	GenerateToken() (string, error)
}

var (
	jwtManagers = make(map[string]JWTManager)
	mutex       sync.Mutex
)

// SetJWTManager replaces instance of JWTManager for a certain key ID with the one specified
func SetJWTManager(keyID string, jwtManager JWTManager) {
	mutex.Lock()
	defer mutex.Unlock()

	jwtManagers[keyID] = jwtManager
}

type jwtManagerImpl struct {
	privateKey *ecdsa.PrivateKey
	kid        string
	iss        string
	token      *t
}

type t struct {
	content string
	expiry  time.Time
	mutex   sync.RWMutex
}

// GetJWTManager returns a JWTManager to handle APNS authentication token
// Accepts keyFile as path to p8 key file, the key id, and issuer team id
// Every unique key ID has its own JWTManager instance
// Returns error if fails to read key from the provided path
func GetJWTManager(keyFile, keyID, teamID string) (JWTManager, error) {
	if _, ok := jwtManagers[keyID]; !ok {
		mutex.Lock()
		defer mutex.Unlock()
		if _, ok := jwtManagers[keyID]; !ok {
			jm, err := newJWTManager(keyFile, keyID, teamID)
			if err != nil {
				return nil, err
			}
			jwtManagers[keyID] = jm
		}
	}

	return jwtManagers[keyID], nil
}

func newJWTManager(keyFile, keyID, teamID string) (JWTManager, error) {
	key, err := LoadPKCS8Key(keyFile)
	if err != nil {
		return nil, err
	}
	switch key := key.(type) {
	case *ecdsa.PrivateKey:
		return &jwtManagerImpl{
			privateKey: key,
			kid:        keyID,
			iss:        teamID,
			token:      new(t),
		}, nil
	default:
		return nil, errors.New("Unsupported key algorithm")
	}
}

func (jm *jwtManagerImpl) GenerateToken() (string, error) {
	if !jm.token.isValid() {
		jm.token.mutex.Lock()
		defer jm.token.mutex.Unlock()
		if !jm.token.isValid() {
			jwt, expiry, err := jm.newToken()
			if err != nil {
				return "", err
			}
			jm.token.content = jwt
			jm.token.expiry = expiry
		}
	}
	return jm.token.content, nil
}

func (jm *jwtManagerImpl) newToken() (string, time.Time, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodES256, jwt.MapClaims{
		"iss": jm.iss,
		"iat": time.Now().Unix(),
	})
	token.Header["kid"] = jm.kid

	result, err := token.SignedString(jm.privateKey)
	if err != nil {
		return "", time.Time{}, err
	}
	return result, time.Now().Add(1 * time.Hour), nil
}

func (token *t) isValid() bool {
	return token.content != "" && token.expiry.After(time.Now())
}
<commit_msg>Use issued at value to determine token expiration<commit_after>package common

import (
	"crypto/ecdsa"
	"errors"
	"sync"
	"time"

	jwt "github.com/dgrijalva/jwt-go"
)

// JWTManager interface to manage APNS JWT
type JWTManager interface {
	// GenerateToken returns a token used for APNS connection
	// Returns error if fails to serialize or sign the token
	GenerateToken() (string, error)
}

var (
	jwtManagers = make(map[string]JWTManager)
	mutex       sync.Mutex
)

// SetJWTManager replaces instance of JWTManager for a certain key ID with the one specified
func SetJWTManager(keyID string, jwtManager JWTManager) {
	mutex.Lock()
	defer mutex.Unlock()

	jwtManagers[keyID] = jwtManager
}

type jwtManagerImpl struct {
	privateKey *ecdsa.PrivateKey
	kid        string
	iss        string
	token      *t
}

type t struct {
	content string
	expiry  time.Time
	mutex   sync.Mutex
}

// GetJWTManager returns a JWTManager to handle APNS authentication token
// Accepts keyFile as path to p8 key file, the key id, and issuer team id
// Every unique key ID has its own JWTManager instance
// Returns error if fails to read key from the provided path
func GetJWTManager(keyFile, keyID, teamID string) (JWTManager, error) {
	if _, ok := jwtManagers[keyID]; !ok {
		mutex.Lock()
		defer mutex.Unlock()
		if _, ok := jwtManagers[keyID]; !ok {
			jm, err := newJWTManager(keyFile, keyID, teamID)
			if err != nil {
				return nil, err
			}
			jwtManagers[keyID] = jm
		}
	}

	return jwtManagers[keyID], nil
}

func newJWTManager(keyFile, keyID, teamID string) (JWTManager, error) {
	key, err := LoadPKCS8Key(keyFile)
	if err != nil {
		return nil, err
	}
	switch key := key.(type) {
	case *ecdsa.PrivateKey:
		return &jwtManagerImpl{
			privateKey: key,
			kid:        keyID,
			iss:        teamID,
			token:      new(t),
		}, nil
	default:
		return nil, errors.New("Unsupported key algorithm")
	}
}

func (jm *jwtManagerImpl) GenerateToken() (string, error) {
	if !jm.token.isValid() {
		jm.token.mutex.Lock()
		defer jm.token.mutex.Unlock()
		if !jm.token.isValid() {
			jwt, expiry, err := jm.newToken()
			if err != nil {
				return "", err
			}
			jm.token.content = jwt
			jm.token.expiry = expiry
		}
	}
	return jm.token.content, nil
}

func (jm *jwtManagerImpl) newToken() (string, time.Time, error) {
	issuedAt := time.Now()

	token := jwt.NewWithClaims(jwt.SigningMethodES256, jwt.MapClaims{
		"iss": jm.iss,
		"iat": issuedAt.Unix(),
	})
	token.Header["kid"] = jm.kid

	result, err := token.SignedString(jm.privateKey)
	if err != nil {
		return "", time.Time{}, err
	}
	return result, issuedAt.Add(1 * time.Hour), nil
}

func (token *t) isValid() bool {
	return token.content != "" && time.Now().Before(token.expiry)
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 trivago GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package format

import (
	"encoding/json"
	"github.com/mssola/user_agent"
	"github.com/trivago/gollum/core"
	"github.com/trivago/gollum/core/log"
	"github.com/trivago/gollum/shared"
	"strconv"
	"strings"
	"time"
)

// ProcessJSON formatter plugin
// ProcessJSON is a formatter that allows modifications to fields of a given
// JSON message. The message is modified and returned again as JSON.
// Configuration example
//
//  - "stream.Broadcast":
//    Formatter: "format.ProcessJSON"
//    ProcessJSONDataFormatter: "format.Forward"
//    ProcessJSONDirectives:
//      - "host:split: :host:@timestamp"
//      - "@timestamp:time:20060102150405:2006-01-02 15\\:04\\:05"
//      - "error:replace:°:\n"
//      - "text:trim: \t"
//      - "foo:rename:bar"
//		- "foobar:remove"
//      - "user_agent:agent:browser:os:version"
//    ProcessJSONTrimValues: true
//
// ProcessJSONDataFormatter formatter that will be applied before
// ProcessJSONDirectives are processed.
//
// ProcessJSONDirectives defines the action to be applied to the json payload.
// Directives are processed in order of appearance.
// The directives have to be given in the form of key:operation:parameters, where
// operation can be one of the following.
//  * split:<string>:{<key>:<key>:...} Split the value by a string and set the
//    resulting array elements to the given fields in order of appearance.
//  * replace:<old>:<new> replace a given string in the value with a new one
//  * trim:<characters> remove the given characters (not string!) from the start
//    and end of the value
//  * rename:<old>:<new> rename a given field
//  * remove remove a given field
//  * time:<read>:<write> read a timestamp and transform it into another
//    format
//  * unixtimestamp:<read>:<write> read a unix timestamp and transform it into another
//    format. valid read formats are s, ms, and ns.
//  * agent:{<user_agent_field>:<user_agent_field>:...} Parse the value as a user
//    agent string and extract the given fields into <key>_<user_agent_field>
//    ("ua:agent:browser:os" would create the new fields "ua_browser" and "ua_os")
//  * flatten:{<delimiter>} create new fields from the values in field, with new
//    fields named field + delimiter + subfield. Delimiter defaults to ".".
//    Removes the original field.
//
// ProcessJSONTrimValues will trim whitspaces from all values if enabled.
// Enabled by default.
type ProcessJSON struct {
	base       core.Formatter
	directives []transformDirective
	trimValues bool
}

type transformDirective struct {
	key        string
	operation  string
	parameters []string
}

func init() {
	shared.TypeRegistry.Register(ProcessJSON{})
}

// Configure initializes this formatter with values from a plugin config.
func (format *ProcessJSON) Configure(conf core.PluginConfig) error {
	plugin, err := core.NewPluginWithType(conf.GetString("ProcessJSONDataFormatter", "format.Forward"), conf)
	if err != nil {
		return err
	}
	directives := conf.GetStringArray("ProcessJSONDirectives", []string{})

	format.base = plugin.(core.Formatter)
	format.directives = make([]transformDirective, 0, len(directives))
	format.trimValues = conf.GetBool("ProcessJSONTrimValues", true)

	for _, directive := range directives {
		directive := strings.Replace(directive, "\\:", "\r", -1)
		parts := strings.Split(directive, ":")
		for i, value := range parts {
			parts[i] = strings.Replace(value, "\r", ":", -1)
		}

		if len(parts) >= 2 {
			newDirective := transformDirective{
				key:       parts[0],
				operation: strings.ToLower(parts[1]),
			}

			for i := 2; i < len(parts); i++ {
				newDirective.parameters = append(newDirective.parameters, shared.Unescape(parts[i]))
			}

			format.directives = append(format.directives, newDirective)
		}
	}

	return nil
}

func processDirective(directive transformDirective, values *shared.MarshalMap) {
	if value, keyExists := (*values)[directive.key]; keyExists {

		numParameters := len(directive.parameters)
		switch directive.operation {
		case "rename":
			if numParameters == 1 {
				(*values)[shared.Unescape(directive.parameters[0])] = value
				delete(*values, directive.key)
			}

		case "time":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			if numParameters == 2 {

				if timestamp, err := time.Parse(directive.parameters[0], stringValue[:len(directive.parameters[0])]); err != nil {
					Log.Warning.Print("ProcessJSON failed to parse a timestamp: ", err)
				} else {
					(*values)[directive.key] = timestamp.Format(directive.parameters[1])
				}
			}

		case "unixtimestamp":
			floatValue, err := values.Float64(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			intValue := int64(floatValue)
			if numParameters == 2 {
				s, ns := int64(0), int64(0)
				switch directive.parameters[0] {
				case "s":
					s = intValue
				case "ms":
					ns = intValue * int64(time.Millisecond)
				case "ns":
					ns = intValue
				default:
					return
				}
				(*values)[directive.key] = time.Unix(s, ns).Format(directive.parameters[1])
			}

		case "split":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			if numParameters > 1 {
				token := shared.Unescape(directive.parameters[0])
				if strings.Contains(stringValue, token) {
					elements := strings.Split(stringValue, token)
					mapping := directive.parameters[1:]
					maxItems := shared.MinI(len(elements), len(mapping))

					for i := 0; i < maxItems; i++ {
						(*values)[mapping[i]] = elements[i]
					}
				}
			}

		case "remove":
			if numParameters == 0 {
				delete(*values, directive.key)
			}

		case "replace":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			if numParameters == 2 {
				(*values)[directive.key] = strings.Replace(stringValue, shared.Unescape(directive.parameters[0]), shared.Unescape(directive.parameters[1]), -1)
			}

		case "trim":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			switch {
			case numParameters == 0:
				(*values)[directive.key] = strings.Trim(stringValue, " \t")
			case numParameters == 1:
				(*values)[directive.key] = strings.Trim(stringValue, shared.Unescape(directive.parameters[0]))
			}

		case "agent":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			fields := []string{
				"mozilla",
				"platform",
				"os",
				"localization",
				"engine",
				"engine_version",
				"browser",
				"version",
			}
			if numParameters > 0 {
				fields = directive.parameters
			}
			ua := user_agent.New(stringValue)
			for _, field := range fields {
				switch field {
				case "mozilla":
					(*values)[directive.key+"_mozilla"] = ua.Mozilla()
				case "platform":
					(*values)[directive.key+"_platform"] = ua.Platform()
				case "os":
					(*values)[directive.key+"_os"] = ua.OS()
				case "localization":
					(*values)[directive.key+"_localization"] = ua.Localization()
				case "engine":
					(*values)[directive.key+"_engine"], _ = ua.Engine()
				case "engine_version":
					_, (*values)[directive.key+"_engine_version"] = ua.Engine()
				case "browser":
					(*values)[directive.key+"_browser"], _ = ua.Browser()
				case "version":
					_, (*values)[directive.key+"_version"] = ua.Browser()
				}
			}

		case "flatten":
			delimiter := "."
			if numParameters == 1 {
				delimiter = directive.parameters[0]
			}
			keyPrefix := directive.key + delimiter
			if mapValue, err := values.Map(directive.key); err == nil {
				for key, val := range mapValue {
					(*values)[keyPrefix + key.(string)] = val
				}
			} else if arrayValue, err := values.Array(directive.key); err == nil {
				for index, val := range arrayValue {
					(*values)[keyPrefix + strconv.Itoa(index)] = val
				}
			} else {
				Log.Warning.Print("key was not a JSON array or object: " + directive.key)
				return
			}
			delete(*values, directive.key)
		}
	}
}

// Format modifies the JSON payload of this message
func (format *ProcessJSON) Format(msg core.Message) ([]byte, core.MessageStreamID) {
	data, streamID := format.base.Format(msg)
	if len(format.directives) == 0 {
		return data, streamID // ### return, no directives ###
	}

	values := make(shared.MarshalMap)
	err := json.Unmarshal(data, &values)
	if err != nil {
		Log.Warning.Print("ProcessJSON failed to unmarshal a message: ", err)
		return data, streamID // ### return, malformed data ###
	}

	for _, directive := range format.directives {
		processDirective(directive, &values)
	}

	if format.trimValues {
		for key := range values {
			stringValue, err := values.String(key)
			if err == nil {
				values[key] = strings.Trim(stringValue, " ")
			}
		}
	}

	if jsonData, err := json.Marshal(values); err == nil {
		return jsonData, streamID // ### return, ok ###
	}

	Log.Warning.Print("ProcessJSON failed to marshal a message: ", err)
	return data, streamID
}
<commit_msg>Fix format.ProcessJSONs flatten directive<commit_after>// Copyright 2015-2016 trivago GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package format

import (
	"encoding/json"
	"github.com/mssola/user_agent"
	"github.com/trivago/gollum/core"
	"github.com/trivago/gollum/core/log"
	"github.com/trivago/gollum/shared"
	"strconv"
	"strings"
	"time"
)

// ProcessJSON formatter plugin
// ProcessJSON is a formatter that allows modifications to fields of a given
// JSON message. The message is modified and returned again as JSON.
// Configuration example
//
//  - "stream.Broadcast":
//    Formatter: "format.ProcessJSON"
//    ProcessJSONDataFormatter: "format.Forward"
//    ProcessJSONDirectives:
//      - "host:split: :host:@timestamp"
//      - "@timestamp:time:20060102150405:2006-01-02 15\\:04\\:05"
//      - "error:replace:°:\n"
//      - "text:trim: \t"
//      - "foo:rename:bar"
//		- "foobar:remove"
//      - "user_agent:agent:browser:os:version"
//    ProcessJSONTrimValues: true
//
// ProcessJSONDataFormatter formatter that will be applied before
// ProcessJSONDirectives are processed.
//
// ProcessJSONDirectives defines the action to be applied to the json payload.
// Directives are processed in order of appearance.
// The directives have to be given in the form of key:operation:parameters, where
// operation can be one of the following.
//  * split:<string>:{<key>:<key>:...} Split the value by a string and set the
//    resulting array elements to the given fields in order of appearance.
//  * replace:<old>:<new> replace a given string in the value with a new one
//  * trim:<characters> remove the given characters (not string!) from the start
//    and end of the value
//  * rename:<old>:<new> rename a given field
//  * remove remove a given field
//  * time:<read>:<write> read a timestamp and transform it into another
//    format
//  * unixtimestamp:<read>:<write> read a unix timestamp and transform it into another
//    format. valid read formats are s, ms, and ns.
//  * agent:{<user_agent_field>:<user_agent_field>:...} Parse the value as a user
//    agent string and extract the given fields into <key>_<user_agent_field>
//    ("ua:agent:browser:os" would create the new fields "ua_browser" and "ua_os")
//  * flatten:{<delimiter>} create new fields from the values in field, with new
//    fields named field + delimiter + subfield. Delimiter defaults to ".".
//    Removes the original field.
//
// ProcessJSONTrimValues will trim whitspaces from all values if enabled.
// Enabled by default.
type ProcessJSON struct {
	base       core.Formatter
	directives []transformDirective
	trimValues bool
}

type transformDirective struct {
	key        string
	operation  string
	parameters []string
}

func init() {
	shared.TypeRegistry.Register(ProcessJSON{})
}

// Configure initializes this formatter with values from a plugin config.
func (format *ProcessJSON) Configure(conf core.PluginConfig) error {
	plugin, err := core.NewPluginWithType(conf.GetString("ProcessJSONDataFormatter", "format.Forward"), conf)
	if err != nil {
		return err
	}
	directives := conf.GetStringArray("ProcessJSONDirectives", []string{})

	format.base = plugin.(core.Formatter)
	format.directives = make([]transformDirective, 0, len(directives))
	format.trimValues = conf.GetBool("ProcessJSONTrimValues", true)

	for _, directive := range directives {
		directive := strings.Replace(directive, "\\:", "\r", -1)
		parts := strings.Split(directive, ":")
		for i, value := range parts {
			parts[i] = strings.Replace(value, "\r", ":", -1)
		}

		if len(parts) >= 2 {
			newDirective := transformDirective{
				key:       parts[0],
				operation: strings.ToLower(parts[1]),
			}

			for i := 2; i < len(parts); i++ {
				newDirective.parameters = append(newDirective.parameters, shared.Unescape(parts[i]))
			}

			format.directives = append(format.directives, newDirective)
		}
	}

	return nil
}

func processDirective(directive transformDirective, values *shared.MarshalMap) {
	if value, keyExists := (*values)[directive.key]; keyExists {

		numParameters := len(directive.parameters)
		switch directive.operation {
		case "rename":
			if numParameters == 1 {
				(*values)[shared.Unescape(directive.parameters[0])] = value
				delete(*values, directive.key)
			}

		case "time":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			if numParameters == 2 {

				if timestamp, err := time.Parse(directive.parameters[0], stringValue[:len(directive.parameters[0])]); err != nil {
					Log.Warning.Print("ProcessJSON failed to parse a timestamp: ", err)
				} else {
					(*values)[directive.key] = timestamp.Format(directive.parameters[1])
				}
			}

		case "unixtimestamp":
			floatValue, err := values.Float64(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			intValue := int64(floatValue)
			if numParameters == 2 {
				s, ns := int64(0), int64(0)
				switch directive.parameters[0] {
				case "s":
					s = intValue
				case "ms":
					ns = intValue * int64(time.Millisecond)
				case "ns":
					ns = intValue
				default:
					return
				}
				(*values)[directive.key] = time.Unix(s, ns).Format(directive.parameters[1])
			}

		case "split":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			if numParameters > 1 {
				token := shared.Unescape(directive.parameters[0])
				if strings.Contains(stringValue, token) {
					elements := strings.Split(stringValue, token)
					mapping := directive.parameters[1:]
					maxItems := shared.MinI(len(elements), len(mapping))

					for i := 0; i < maxItems; i++ {
						(*values)[mapping[i]] = elements[i]
					}
				}
			}

		case "remove":
			if numParameters == 0 {
				delete(*values, directive.key)
			}

		case "replace":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			if numParameters == 2 {
				(*values)[directive.key] = strings.Replace(stringValue, shared.Unescape(directive.parameters[0]), shared.Unescape(directive.parameters[1]), -1)
			}

		case "trim":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			switch {
			case numParameters == 0:
				(*values)[directive.key] = strings.Trim(stringValue, " \t")
			case numParameters == 1:
				(*values)[directive.key] = strings.Trim(stringValue, shared.Unescape(directive.parameters[0]))
			}

		case "agent":
			stringValue, err := values.String(directive.key)
			if err != nil {
				Log.Warning.Print(err.Error())
				return
			}
			fields := []string{
				"mozilla",
				"platform",
				"os",
				"localization",
				"engine",
				"engine_version",
				"browser",
				"version",
			}
			if numParameters > 0 {
				fields = directive.parameters
			}
			ua := user_agent.New(stringValue)
			for _, field := range fields {
				switch field {
				case "mozilla":
					(*values)[directive.key+"_mozilla"] = ua.Mozilla()
				case "platform":
					(*values)[directive.key+"_platform"] = ua.Platform()
				case "os":
					(*values)[directive.key+"_os"] = ua.OS()
				case "localization":
					(*values)[directive.key+"_localization"] = ua.Localization()
				case "engine":
					(*values)[directive.key+"_engine"], _ = ua.Engine()
				case "engine_version":
					_, (*values)[directive.key+"_engine_version"] = ua.Engine()
				case "browser":
					(*values)[directive.key+"_browser"], _ = ua.Browser()
				case "version":
					_, (*values)[directive.key+"_version"] = ua.Browser()
				}
			}

		case "flatten":
			delimiter := "."
			if numParameters == 1 {
				delimiter = directive.parameters[0]
			}
			keyPrefix := directive.key + delimiter
			if mapValue, err := values.MarshalMap(directive.key); err == nil {
				for key, val := range mapValue {
					(*values)[keyPrefix + key] = val
				}
			} else if arrayValue, err := values.Array(directive.key); err == nil {
				for index, val := range arrayValue {
					(*values)[keyPrefix + strconv.Itoa(index)] = val
				}
			} else {
				Log.Warning.Print("key was not a JSON array or object: " + directive.key)
				return
			}
			delete(*values, directive.key)
		}
	}
}

// Format modifies the JSON payload of this message
func (format *ProcessJSON) Format(msg core.Message) ([]byte, core.MessageStreamID) {
	data, streamID := format.base.Format(msg)
	if len(format.directives) == 0 {
		return data, streamID // ### return, no directives ###
	}

	values := make(shared.MarshalMap)
	err := json.Unmarshal(data, &values)
	if err != nil {
		Log.Warning.Print("ProcessJSON failed to unmarshal a message: ", err)
		return data, streamID // ### return, malformed data ###
	}

	for _, directive := range format.directives {
		processDirective(directive, &values)
	}

	if format.trimValues {
		for key := range values {
			stringValue, err := values.String(key)
			if err == nil {
				values[key] = strings.Trim(stringValue, " ")
			}
		}
	}

	if jsonData, err := json.Marshal(values); err == nil {
		return jsonData, streamID // ### return, ok ###
	}

	Log.Warning.Print("ProcessJSON failed to marshal a message: ", err)
	return data, streamID
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	c "github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-check"
	"github.com/flynn/flynn/cli/config"
	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/discoverd/client"
	"github.com/flynn/flynn/pkg/cluster"
)

type Helper struct {
	config     *config.Cluster
	cluster    *cluster.Client
	controller *controller.Client
	disc       *discoverd.Client
	hosts      map[string]cluster.Host
	ssh        *sshData
}

func (h *Helper) clusterConf(t *c.C) *config.Cluster {
	if h.config == nil {
		conf, err := config.ReadFile(flynnrc)
		t.Assert(err, c.IsNil)
		t.Assert(conf.Clusters, c.HasLen, 1)
		h.config = conf.Clusters[0]
	}
	return h.config
}

func (h *Helper) clusterClient(t *c.C) *cluster.Client {
	if h.cluster == nil {
		var err error
		h.cluster, err = cluster.NewClientWithDial(nil, h.discoverdClient(t).NewServiceSet)
		t.Assert(err, c.IsNil)
	}
	return h.cluster
}

func (h *Helper) controllerClient(t *c.C) *controller.Client {
	if h.controller == nil {
		conf := h.clusterConf(t)
		pin, err := base64.StdEncoding.DecodeString(conf.TLSPin)
		t.Assert(err, c.IsNil)
		h.controller, err = controller.NewClientWithPin(conf.URL, conf.Key, pin)
		t.Assert(err, c.IsNil)
	}
	return h.controller
}

func (h *Helper) discoverdClient(t *c.C) *discoverd.Client {
	if h.disc == nil {
		var err error
		h.disc, err = discoverd.NewClientWithAddr(routerIP + ":1111")
		t.Assert(err, c.IsNil)
	}
	return h.disc
}

func (h *Helper) hostClient(t *c.C, hostID string) cluster.Host {
	if h.hosts == nil {
		h.hosts = make(map[string]cluster.Host)
	}
	if client, ok := h.hosts[hostID]; ok {
		return client
	}
	client, err := h.clusterClient(t).DialHost(hostID)
	t.Assert(err, c.IsNil)
	h.hosts[hostID] = client
	return client
}

func (h *Helper) sshKeys(t *c.C) *sshData {
	if h.ssh == nil {
		var err error
		h.ssh, err = genSSHKey()
		t.Assert(err, c.IsNil)
	}
	return h.ssh
}

func (h *Helper) createApp(t *c.C) (*ct.App, *ct.Release) {
	client := h.controllerClient(t)

	app := &ct.App{}
	t.Assert(client.CreateApp(app), c.IsNil)
	debugf(t, "created app %s (%s)", app.Name, app.ID)

	artifact := &ct.Artifact{Type: "docker", URI: testImageURI}
	t.Assert(client.CreateArtifact(artifact), c.IsNil)

	release := &ct.Release{
		ArtifactID: artifact.ID,
		Processes: map[string]ct.ProcessType{
			"echoer": {
				Cmd:   []string{"/bin/echoer"},
				Ports: []ct.Port{{Proto: "tcp"}},
			},
			"printer": {
				Cmd: []string{"sh", "-c", "while true; do echo I like to print; sleep 1; done"},
			},
			"crasher": {
				Cmd: []string{"sh", "-c", "trap 'exit 1' SIGTERM; while true; do echo I like to crash; sleep 1; done"},
			},
			"omni": {
				Cmd:  []string{"sh", "-c", "while true; do echo I am everywhere; sleep 1; done"},
				Omni: true,
			},
		},
	}
	t.Assert(client.CreateRelease(release), c.IsNil)
	t.Assert(client.SetAppRelease(app.ID, release.ID), c.IsNil)
	return app, release
}

func (h *Helper) stopJob(t *c.C, id string) {
	debugf(t, "stopping job %s", id)
	hostID, jobID, _ := cluster.ParseJobID(id)
	hc := h.hostClient(t, hostID)
	t.Assert(hc.StopJob(jobID), c.IsNil)
}

type gitRepo struct {
	dir string
	ssh *sshData
	t   *c.C
}

func (h *Helper) newGitRepo(t *c.C, nameOrURL string) *gitRepo {
	dir := filepath.Join(t.MkDir(), "repo")
	r := &gitRepo{dir, h.sshKeys(t), t}

	if strings.HasPrefix(nameOrURL, "https://") {
		t.Assert(run(t, exec.Command("git", "clone", nameOrURL, dir)), Succeeds)
		return r
	}

	t.Assert(run(t, exec.Command("cp", "-r", filepath.Join("apps", nameOrURL), dir)), Succeeds)
	t.Assert(r.git("init"), Succeeds)
	t.Assert(r.git("add", "."), Succeeds)
	t.Assert(r.git("commit", "-am", "init"), Succeeds)
	return r
}

func (r *gitRepo) flynn(args ...string) *CmdResult {
	return flynn(r.t, r.dir, args...)
}

func (r *gitRepo) git(args ...string) *CmdResult {
	cmd := exec.Command("git", args...)
	cmd.Env = append(os.Environ(), r.ssh.Env...)
	cmd.Dir = r.dir
	return run(r.t, cmd)
}

func (h *Helper) cleanup() {
	if h.disc != nil {
		h.disc.Close()
	}
	if h.cluster != nil {
		h.cluster.Close()
	}
	if h.controller != nil {
		h.controller.Close()
	}
	for _, host := range h.hosts {
		host.Close()
	}
	if h.ssh != nil {
		h.ssh.Cleanup()
	}
}
<commit_msg>test: Make Helper methods thread safe<commit_after>package main

import (
	"encoding/base64"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"

	c "github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-check"
	"github.com/flynn/flynn/cli/config"
	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/discoverd/client"
	"github.com/flynn/flynn/pkg/cluster"
)

type Helper struct {
	config     *config.Cluster
	cluster    *cluster.Client
	controller *controller.Client
	disc       *discoverd.Client
	hosts      map[string]cluster.Host
	ssh        *sshData
	mtx        sync.Mutex
}

func (h *Helper) clusterConf(t *c.C) *config.Cluster {
	h.mtx.Lock()
	defer h.mtx.Unlock()
	if h.config == nil {
		conf, err := config.ReadFile(flynnrc)
		t.Assert(err, c.IsNil)
		t.Assert(conf.Clusters, c.HasLen, 1)
		h.config = conf.Clusters[0]
	}
	return h.config
}

func (h *Helper) clusterClient(t *c.C) *cluster.Client {
	h.mtx.Lock()
	defer h.mtx.Unlock()
	if h.cluster == nil {
		h.mtx.Unlock()
		client, err := cluster.NewClientWithDial(nil, h.discoverdClient(t).NewServiceSet)
		t.Assert(err, c.IsNil)
		h.mtx.Lock()
		if h.cluster != nil {
			client.Close()
		} else {
			h.cluster = client
		}
	}
	return h.cluster
}

func (h *Helper) controllerClient(t *c.C) *controller.Client {
	h.mtx.Lock()
	defer h.mtx.Unlock()
	if h.controller == nil {
		h.mtx.Unlock()
		conf := h.clusterConf(t)
		pin, err := base64.StdEncoding.DecodeString(conf.TLSPin)
		t.Assert(err, c.IsNil)
		client, err := controller.NewClientWithPin(conf.URL, conf.Key, pin)
		t.Assert(err, c.IsNil)
		h.mtx.Lock()
		if h.controller != nil {
			client.Close()
		} else {
			h.controller = client
		}
	}
	return h.controller
}

func (h *Helper) discoverdClient(t *c.C) *discoverd.Client {
	h.mtx.Lock()
	defer h.mtx.Unlock()
	if h.disc == nil {
		var err error
		h.disc, err = discoverd.NewClientWithAddr(routerIP + ":1111")
		t.Assert(err, c.IsNil)
	}
	return h.disc
}

func (h *Helper) hostClient(t *c.C, hostID string) cluster.Host {
	h.mtx.Lock()
	defer h.mtx.Unlock()
	if h.hosts == nil {
		h.hosts = make(map[string]cluster.Host)
	}
	if client, ok := h.hosts[hostID]; ok {
		return client
	}
	h.mtx.Unlock()
	client, err := h.clusterClient(t).DialHost(hostID)
	t.Assert(err, c.IsNil)
	h.mtx.Lock()
	if prevClient, ok := h.hosts[hostID]; ok {
		client.Close()
		return prevClient
	} else {
		h.hosts[hostID] = client
		return client
	}
}

func (h *Helper) sshKeys(t *c.C) *sshData {
	h.mtx.Lock()
	defer h.mtx.Unlock()
	if h.ssh == nil {
		var err error
		h.ssh, err = genSSHKey()
		t.Assert(err, c.IsNil)
	}
	return h.ssh
}

func (h *Helper) createApp(t *c.C) (*ct.App, *ct.Release) {
	client := h.controllerClient(t)

	app := &ct.App{}
	t.Assert(client.CreateApp(app), c.IsNil)
	debugf(t, "created app %s (%s)", app.Name, app.ID)

	artifact := &ct.Artifact{Type: "docker", URI: testImageURI}
	t.Assert(client.CreateArtifact(artifact), c.IsNil)

	release := &ct.Release{
		ArtifactID: artifact.ID,
		Processes: map[string]ct.ProcessType{
			"echoer": {
				Cmd:   []string{"/bin/echoer"},
				Ports: []ct.Port{{Proto: "tcp"}},
			},
			"printer": {
				Cmd: []string{"sh", "-c", "while true; do echo I like to print; sleep 1; done"},
			},
			"crasher": {
				Cmd: []string{"sh", "-c", "trap 'exit 1' SIGTERM; while true; do echo I like to crash; sleep 1; done"},
			},
			"omni": {
				Cmd:  []string{"sh", "-c", "while true; do echo I am everywhere; sleep 1; done"},
				Omni: true,
			},
		},
	}
	t.Assert(client.CreateRelease(release), c.IsNil)
	t.Assert(client.SetAppRelease(app.ID, release.ID), c.IsNil)
	return app, release
}

func (h *Helper) stopJob(t *c.C, id string) {
	debugf(t, "stopping job %s", id)
	hostID, jobID, _ := cluster.ParseJobID(id)
	hc := h.hostClient(t, hostID)
	t.Assert(hc.StopJob(jobID), c.IsNil)
}

type gitRepo struct {
	dir string
	ssh *sshData
	t   *c.C
}

func (h *Helper) newGitRepo(t *c.C, nameOrURL string) *gitRepo {
	dir := filepath.Join(t.MkDir(), "repo")
	r := &gitRepo{dir, h.sshKeys(t), t}

	if strings.HasPrefix(nameOrURL, "https://") {
		t.Assert(run(t, exec.Command("git", "clone", nameOrURL, dir)), Succeeds)
		return r
	}

	t.Assert(run(t, exec.Command("cp", "-r", filepath.Join("apps", nameOrURL), dir)), Succeeds)
	t.Assert(r.git("init"), Succeeds)
	t.Assert(r.git("add", "."), Succeeds)
	t.Assert(r.git("commit", "-am", "init"), Succeeds)
	return r
}

func (r *gitRepo) flynn(args ...string) *CmdResult {
	return flynn(r.t, r.dir, args...)
}

func (r *gitRepo) git(args ...string) *CmdResult {
	cmd := exec.Command("git", args...)
	cmd.Env = append(os.Environ(), r.ssh.Env...)
	cmd.Dir = r.dir
	return run(r.t, cmd)
}

func (h *Helper) cleanup() {
	h.mtx.Lock()
	defer h.mtx.Unlock()
	if h.disc != nil {
		h.disc.Close()
	}
	if h.cluster != nil {
		h.cluster.Close()
	}
	if h.controller != nil {
		h.controller.Close()
	}
	for _, host := range h.hosts {
		host.Close()
	}
	if h.ssh != nil {
		h.ssh.Cleanup()
	}
}
<|endoftext|>


<commit_before>package metric

import (
	"strings"
	"time"
)

// The different types of metrics that are supported
const (
	Gauge             = "gauge"
	Counter           = "counter"
	CumulativeCounter = "cumcounter"
)

// Metric type holds all the information for a single metric data
// point. Metrics are generated in collectors and passed to handlers.
type Metric struct {
	Name       string            `json:"name"`
	MetricType string            `json:"type"`
	Value      float64           `json:"value"`
	Dimensions map[string]string `json:"dimensions"`
	MetricTime time.Time         `json:"time"`
}

// New returns a new metric with name. Default metric type is "gauge"
// and timestamp is set to now. Value is initialized to 0.0.
func New(name string) Metric {
	return Metric{
		Name:       sanitizeString(name),
		MetricType: "gauge",
		Value:      0.0,
		Dimensions: make(map[string]string),
		MetricTime: time.Now(),
	}
}

// WithValue returns metric with value of type Gauge
func WithValue(name string, value float64) Metric {
	metric := New(name)
	metric.Value = value
	return metric
}

// SetTime to metric
func (m *Metric) SetTime(mtime time.Time) {
	m.MetricTime = mtime
}

// AddDimension adds a new dimension to the Metric.
func (m *Metric) AddDimension(name, value string) {
	m.Dimensions[sanitizeString(name)] = sanitizeString(value)
}

// RemoveDimension removes a dimension from the Metric.
func (m *Metric) RemoveDimension(name string) {
	delete(m.Dimensions, name)
}

// AddDimensions adds multiple new dimensions to the Metric.
func (m *Metric) AddDimensions(dimensions map[string]string) {
	for k, v := range dimensions {
		m.AddDimension(k, v)
	}
}

// GetDimensions returns the dimensions of a metric merged with defaults. Defaults win.
func (m *Metric) GetDimensions(defaults map[string]string) (dimensions map[string]string) {
	dimensions = make(map[string]string)
	for name, value := range m.Dimensions {
		dimensions[name] = value
	}
	for name, value := range defaults {
		dimensions[name] = value
	}
	return dimensions
}

// GetDimensionValue returns the value of a dimension if it's set.
func (m *Metric) GetDimensionValue(dimension string) (value string, ok bool) {
	dimension = sanitizeString(dimension)
	value, ok = m.Dimensions[dimension]
	return
}

// ZeroValue is metric zero value
func (m *Metric) ZeroValue() bool {
	return (len(m.Name) == 0) &&
		(len(m.MetricType) == 0) &&
		(m.Value == 0.0) &&
		(len(m.Dimensions) == 0)
}

// AddToAll adds a map of dimensions to a list of metrics
func AddToAll(metrics *[]Metric, dims map[string]string) {
	for _, m := range *metrics {
		for key, value := range dims {
			m.AddDimension(key, value)
		}
	}
}

func sanitizeString(s string) string {
	s = strings.Replace(s, "=", "-", -1)
	s = strings.Replace(s, ":", "-", -1)
	return s
}
<commit_msg>Use time of metric-creation instead of push-time for graphite<commit_after>package metric

import (
	"strings"

	"fmt"
	"time"
)

// The different types of metrics that are supported
const (
	Gauge             = "gauge"
	Counter           = "counter"
	CumulativeCounter = "cumcounter"
)

// Metric type holds all the information for a single metric data
// point. Metrics are generated in collectors and passed to handlers.
type Metric struct {
	Name       string            `json:"name"`
	MetricType string            `json:"type"`
	Value      float64           `json:"value"`
	MetricTime string            `json:"time"`
	Dimensions map[string]string `json:"dimensions"`
	MetricTime time.Time         `json:"time"`
}

// New returns a new metric with name. Default metric type is "gauge"
// and timestamp is set to now. Value is initialized to 0.0.
func New(name string) Metric {
	return Metric{
		Name:       sanitizeString(name),
		MetricType: "gauge",
		Value:      0.0,
		MetricTime: fmt.Sprintf("%d", time.Now().Unix()),
		Dimensions: make(map[string]string),
		MetricTime: time.Now(),
	}
}

// WithValue returns metric with value of type Gauge
func WithValue(name string, value float64) Metric {
	metric := New(name)
	metric.Value = value
	return metric
}

// SetTime to metric
func (m *Metric) SetTime(mtime time.Time) {
	m.MetricTime = mtime
}

// AddDimension adds a new dimension to the Metric.
func (m *Metric) AddDimension(name, value string) {
	m.Dimensions[sanitizeString(name)] = sanitizeString(value)
}

// RemoveDimension removes a dimension from the Metric.
func (m *Metric) RemoveDimension(name string) {
	delete(m.Dimensions, name)
}

// AddDimensions adds multiple new dimensions to the Metric.
func (m *Metric) AddDimensions(dimensions map[string]string) {
	for k, v := range dimensions {
		m.AddDimension(k, v)
	}
}

// GetDimensions returns the dimensions of a metric merged with defaults. Defaults win.
func (m *Metric) GetDimensions(defaults map[string]string) (dimensions map[string]string) {
	dimensions = make(map[string]string)
	for name, value := range m.Dimensions {
		dimensions[name] = value
	}
	for name, value := range defaults {
		dimensions[name] = value
	}
	return dimensions
}

// GetDimensionValue returns the value of a dimension if it's set.
func (m *Metric) GetDimensionValue(dimension string) (value string, ok bool) {
	dimension = sanitizeString(dimension)
	value, ok = m.Dimensions[dimension]
	return
}

// ZeroValue is metric zero value
func (m *Metric) ZeroValue() bool {
	return (len(m.Name) == 0) &&
		(len(m.MetricType) == 0) &&
		(m.Value == 0.0) &&
		(len(m.Dimensions) == 0)
}

// AddToAll adds a map of dimensions to a list of metrics
func AddToAll(metrics *[]Metric, dims map[string]string) {
	for _, m := range *metrics {
		for key, value := range dims {
			m.AddDimension(key, value)
		}
	}
}

func sanitizeString(s string) string {
	s = strings.Replace(s, "=", "-", -1)
	s = strings.Replace(s, ":", "-", -1)
	return s
}
<|endoftext|>