<commit_before>package dbus

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

var (
	byteType        = reflect.TypeOf(byte(0))
	boolType        = reflect.TypeOf(false)
	uint8Type       = reflect.TypeOf(uint8(0))
	int16Type       = reflect.TypeOf(int16(0))
	uint16Type      = reflect.TypeOf(uint16(0))
	intType         = reflect.TypeOf(int(0))
	uintType        = reflect.TypeOf(uint(0))
	int32Type       = reflect.TypeOf(int32(0))
	uint32Type      = reflect.TypeOf(uint32(0))
	int64Type       = reflect.TypeOf(int64(0))
	uint64Type      = reflect.TypeOf(uint64(0))
	float64Type     = reflect.TypeOf(float64(0))
	stringType      = reflect.TypeOf("")
	signatureType   = reflect.TypeOf(Signature{""})
	objectPathType  = reflect.TypeOf(ObjectPath(""))
	variantType     = reflect.TypeOf(Variant{Signature{""}, nil})
	interfacesType  = reflect.TypeOf([]interface{}{})
	interfaceType   = reflect.TypeOf((*interface{})(nil)).Elem()
	unixFDType      = reflect.TypeOf(UnixFD(0))
	unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
)

// An InvalidTypeError signals that a value which cannot be represented in the
// D-Bus wire format was passed to a function.
type InvalidTypeError struct {
	Type reflect.Type
}

func (e InvalidTypeError) Error() string {
	return "dbus: invalid type " + e.Type.String()
}

// Store copies the values contained in src to dest, which must be a slice of
// pointers. It converts slices of interfaces from src to corresponding structs
// in dest. An error is returned if the lengths of src and dest or the types of
// their elements don't match.
func Store(src []interface{}, dest ...interface{}) error {
	if len(src) != len(dest) {
		return errors.New("dbus.Store: length mismatch")
	}

	for i := range src {
		if err := storeInterfaces(src[i], dest[i]); err != nil {
			return err
		}
	}
	return nil
}

func storeInterfaces(src, dest interface{}) error {
	return store(reflect.ValueOf(dest), reflect.ValueOf(src))
}

func store(dest, src reflect.Value) error {
	if dest.Kind() == reflect.Ptr {
		return store(dest.Elem(), src)
	}
	switch src.Kind() {
	case reflect.Slice:
		return storeSlice(dest, src)
	case reflect.Map:
		return storeMap(dest, src)
	default:
		return storeBase(dest, src)
	}
}

func storeBase(dest, src reflect.Value) error {
	return setDest(dest, src)
}

func setDest(dest, src reflect.Value) error {
	if !isVariant(src.Type()) && isVariant(dest.Type()) {
		//special conversion for dbus.Variant
		dest.Set(reflect.ValueOf(MakeVariant(src.Interface())))
		return nil
	}
	if isVariant(src.Type()) && !isVariant(dest.Type()) {
		src = getVariantValue(src)
		return store(dest, src)
	}
	if !src.Type().ConvertibleTo(dest.Type()) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: cannot convert %s to %s",
			src.Type(), dest.Type())
	}
	dest.Set(src.Convert(dest.Type()))
	return nil
}

func kindsAreCompatible(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	default:
		return dest.Kind() == src.Kind()
	}
}

func isConvertibleTo(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	case dest.Kind() == reflect.Slice:
		return src.Kind() == reflect.Slice &&
			isConvertibleTo(dest.Elem(), src.Elem())
	case dest.Kind() == reflect.Struct:
		return src == interfacesType
	default:
		return src.ConvertibleTo(dest)
	}
}

func storeMap(dest, src reflect.Value) error {
	switch {
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeMapIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeMapIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Key(), src.Type().Key()) &&
		isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeMapIntoMap(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeMapIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeMap(src.Type())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeMap(
			reflect.MapOf(src.Type().Key(), interfaceType))
	} else {
		dv = reflect.MakeMap(src.Type())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoMap(dest, src reflect.Value) error {
	if dest.IsNil() {
		dest.Set(reflect.MakeMap(dest.Type()))
	}
	keys := src.MapKeys()
	for _, key := range keys {
		dkey := key.Convert(dest.Type().Key())
		dval := reflect.New(dest.Type().Elem()).Elem()
		err := store(dval, getVariantValue(src.MapIndex(key)))
		if err != nil {
			return err
		}
		dest.SetMapIndex(dkey, dval)
	}
	return nil
}

func storeSlice(dest, src reflect.Value) error {
	switch {
	case src.Type() == interfacesType && dest.Kind() == reflect.Struct:
		//The decoder always decodes structs as slices of interface{}
		return storeStruct(dest, src)
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeSliceIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeSliceIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeSliceIntoSlice(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeStruct(dest, src reflect.Value) error {
	if isVariant(dest.Type()) {
		return storeBase(dest, src)
	}
	dval := make([]interface{}, 0, dest.NumField())
	dtype := dest.Type()
	for i := 0; i < dest.NumField(); i++ {
		field := dest.Field(i)
		ftype := dtype.Field(i)
		if ftype.PkgPath != "" {
			continue
		}
		if ftype.Tag.Get("dbus") == "-" {
			continue
		}
		dval = append(dval, field.Addr().Interface())
	}
	if src.Len() != len(dval) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"destination struct does not have "+
				"enough fields need: %d have: %d",
			src.Len(), len(dval))
	}
	return Store(src.Interface().([]interface{}), dval...)
}

func storeSliceIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeSlice(reflect.SliceOf(interfaceType),
			src.Len(), src.Cap())
	} else {
		dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoSlice(dest, src reflect.Value) error {
	if dest.IsNil() || dest.Len() < src.Len() {
		dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap()))
	}
	if dest.Len() != src.Len() {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slices are different lengths "+
				"need: %d have: %d",
			src.Len(), dest.Len())
	}
	for i := 0; i < src.Len(); i++ {
		err := store(dest.Index(i), getVariantValue(src.Index(i)))
		if err != nil {
			return err
		}
	}
	return nil
}

func getVariantValue(in reflect.Value) reflect.Value {
	if isVariant(in.Type()) {
		return reflect.ValueOf(in.Interface().(Variant).Value())
	}
	return in
}

func isVariant(t reflect.Type) bool {
	return t == variantType
}

// An ObjectPath is an object path as defined by the D-Bus spec.
type ObjectPath string

// IsValid returns whether the object path is valid.
func (o ObjectPath) IsValid() bool {
	s := string(o)
	if len(s) == 0 {
		return false
	}
	if s[0] != '/' {
		return false
	}
	if s[len(s)-1] == '/' && len(s) != 1 {
		return false
	}
	// probably not used, but technically possible
	if s == "/" {
		return true
	}
	split := strings.Split(s[1:], "/")
	for _, v := range split {
		if len(v) == 0 {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// A UnixFD is a Unix file descriptor sent over the wire. See the package-level
// documentation for more information about Unix file descriptor passsing.
type UnixFD int32

// A UnixFDIndex is the representation of a Unix file descriptor in a message.
type UnixFDIndex uint32

// alignment returns the alignment of values of type t.
func alignment(t reflect.Type) int {
	switch t {
	case variantType:
		return 1
	case objectPathType:
		return 4
	case signatureType:
		return 1
	case interfacesType:
		return 4
	}
	switch t.Kind() {
	case reflect.Uint8:
		return 1
	case reflect.Uint16, reflect.Int16:
		return 2
	case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
		return 4
	case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
		return 8
	case reflect.Ptr:
		return alignment(t.Elem())
	}
	return 1
}

// isKeyType returns whether t is a valid type for a D-Bus dict.
func isKeyType(t reflect.Type) bool {
	switch t.Kind() {
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
		reflect.String, reflect.Uint, reflect.Int:

		return true
	}
	return false
}

// isValidInterface returns whether s is a valid name for an interface.
func isValidInterface(s string) bool {
	if len(s) == 0 || len(s) > 255 || s[0] == '.' {
		return false
	}
	elem := strings.Split(s, ".")
	if len(elem) < 2 {
		return false
	}
	for _, v := range elem {
		if len(v) == 0 {
			return false
		}
		if v[0] >= '0' && v[0] <= '9' {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// isValidMember returns whether s is a valid name for a member.
func isValidMember(s string) bool {
	if len(s) == 0 || len(s) > 255 {
		return false
	}
	i := strings.Index(s, ".")
	if i != -1 {
		return false
	}
	if s[0] >= '0' && s[0] <= '9' {
		return false
	}
	for _, c := range s {
		if !isMemberChar(c) {
			return false
		}
	}
	return true
}

func isMemberChar(c rune) bool {
	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
		(c >= 'a' && c <= 'z') || c == '_'
}
<commit_msg>Fix panic on call to method with pointer arguments<commit_after>package dbus

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

var (
	byteType        = reflect.TypeOf(byte(0))
	boolType        = reflect.TypeOf(false)
	uint8Type       = reflect.TypeOf(uint8(0))
	int16Type       = reflect.TypeOf(int16(0))
	uint16Type      = reflect.TypeOf(uint16(0))
	intType         = reflect.TypeOf(int(0))
	uintType        = reflect.TypeOf(uint(0))
	int32Type       = reflect.TypeOf(int32(0))
	uint32Type      = reflect.TypeOf(uint32(0))
	int64Type       = reflect.TypeOf(int64(0))
	uint64Type      = reflect.TypeOf(uint64(0))
	float64Type     = reflect.TypeOf(float64(0))
	stringType      = reflect.TypeOf("")
	signatureType   = reflect.TypeOf(Signature{""})
	objectPathType  = reflect.TypeOf(ObjectPath(""))
	variantType     = reflect.TypeOf(Variant{Signature{""}, nil})
	interfacesType  = reflect.TypeOf([]interface{}{})
	interfaceType   = reflect.TypeOf((*interface{})(nil)).Elem()
	unixFDType      = reflect.TypeOf(UnixFD(0))
	unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
)

// An InvalidTypeError signals that a value which cannot be represented in the
// D-Bus wire format was passed to a function.
type InvalidTypeError struct {
	Type reflect.Type
}

func (e InvalidTypeError) Error() string {
	return "dbus: invalid type " + e.Type.String()
}

// Store copies the values contained in src to dest, which must be a slice of
// pointers. It converts slices of interfaces from src to corresponding structs
// in dest. An error is returned if the lengths of src and dest or the types of
// their elements don't match.
func Store(src []interface{}, dest ...interface{}) error {
	if len(src) != len(dest) {
		return errors.New("dbus.Store: length mismatch")
	}

	for i := range src {
		if err := storeInterfaces(src[i], dest[i]); err != nil {
			return err
		}
	}
	return nil
}

func storeInterfaces(src, dest interface{}) error {
	return store(reflect.ValueOf(dest), reflect.ValueOf(src))
}

func store(dest, src reflect.Value) error {
	if dest.Kind() == reflect.Ptr {
		if dest.IsNil() {
			dest.Set(reflect.New(dest.Type().Elem()))
		}
		return store(dest.Elem(), src)
	}
	switch src.Kind() {
	case reflect.Slice:
		return storeSlice(dest, src)
	case reflect.Map:
		return storeMap(dest, src)
	default:
		return storeBase(dest, src)
	}
}

func storeBase(dest, src reflect.Value) error {
	return setDest(dest, src)
}

func setDest(dest, src reflect.Value) error {
	if !isVariant(src.Type()) && isVariant(dest.Type()) {
		//special conversion for dbus.Variant
		dest.Set(reflect.ValueOf(MakeVariant(src.Interface())))
		return nil
	}
	if isVariant(src.Type()) && !isVariant(dest.Type()) {
		src = getVariantValue(src)
		return store(dest, src)
	}
	if !src.Type().ConvertibleTo(dest.Type()) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: cannot convert %s to %s",
			src.Type(), dest.Type())
	}
	dest.Set(src.Convert(dest.Type()))
	return nil
}

func kindsAreCompatible(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	default:
		return dest.Kind() == src.Kind()
	}
}

func isConvertibleTo(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	case dest.Kind() == reflect.Slice:
		return src.Kind() == reflect.Slice &&
			isConvertibleTo(dest.Elem(), src.Elem())
	case dest.Kind() == reflect.Struct:
		return src == interfacesType
	default:
		return src.ConvertibleTo(dest)
	}
}

func storeMap(dest, src reflect.Value) error {
	switch {
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeMapIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeMapIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Key(), src.Type().Key()) &&
		isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeMapIntoMap(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeMapIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeMap(src.Type())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeMap(
			reflect.MapOf(src.Type().Key(), interfaceType))
	} else {
		dv = reflect.MakeMap(src.Type())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoMap(dest, src reflect.Value) error {
	if dest.IsNil() {
		dest.Set(reflect.MakeMap(dest.Type()))
	}
	keys := src.MapKeys()
	for _, key := range keys {
		dkey := key.Convert(dest.Type().Key())
		dval := reflect.New(dest.Type().Elem()).Elem()
		err := store(dval, getVariantValue(src.MapIndex(key)))
		if err != nil {
			return err
		}
		dest.SetMapIndex(dkey, dval)
	}
	return nil
}

func storeSlice(dest, src reflect.Value) error {
	switch {
	case src.Type() == interfacesType && dest.Kind() == reflect.Struct:
		//The decoder always decodes structs as slices of interface{}
		return storeStruct(dest, src)
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeSliceIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeSliceIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeSliceIntoSlice(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeStruct(dest, src reflect.Value) error {
	if isVariant(dest.Type()) {
		return storeBase(dest, src)
	}
	dval := make([]interface{}, 0, dest.NumField())
	dtype := dest.Type()
	for i := 0; i < dest.NumField(); i++ {
		field := dest.Field(i)
		ftype := dtype.Field(i)
		if ftype.PkgPath != "" {
			continue
		}
		if ftype.Tag.Get("dbus") == "-" {
			continue
		}
		dval = append(dval, field.Addr().Interface())
	}
	if src.Len() != len(dval) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"destination struct does not have "+
				"enough fields need: %d have: %d",
			src.Len(), len(dval))
	}
	return Store(src.Interface().([]interface{}), dval...)
}

func storeSliceIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeSlice(reflect.SliceOf(interfaceType),
			src.Len(), src.Cap())
	} else {
		dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoSlice(dest, src reflect.Value) error {
	if dest.IsNil() || dest.Len() < src.Len() {
		dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap()))
	}
	if dest.Len() != src.Len() {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slices are different lengths "+
				"need: %d have: %d",
			src.Len(), dest.Len())
	}
	for i := 0; i < src.Len(); i++ {
		err := store(dest.Index(i), getVariantValue(src.Index(i)))
		if err != nil {
			return err
		}
	}
	return nil
}

func getVariantValue(in reflect.Value) reflect.Value {
	if isVariant(in.Type()) {
		return reflect.ValueOf(in.Interface().(Variant).Value())
	}
	return in
}

func isVariant(t reflect.Type) bool {
	return t == variantType
}

// An ObjectPath is an object path as defined by the D-Bus spec.
type ObjectPath string

// IsValid returns whether the object path is valid.
func (o ObjectPath) IsValid() bool {
	s := string(o)
	if len(s) == 0 {
		return false
	}
	if s[0] != '/' {
		return false
	}
	if s[len(s)-1] == '/' && len(s) != 1 {
		return false
	}
	// probably not used, but technically possible
	if s == "/" {
		return true
	}
	split := strings.Split(s[1:], "/")
	for _, v := range split {
		if len(v) == 0 {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// A UnixFD is a Unix file descriptor sent over the wire. See the package-level
// documentation for more information about Unix file descriptor passsing.
type UnixFD int32

// A UnixFDIndex is the representation of a Unix file descriptor in a message.
type UnixFDIndex uint32

// alignment returns the alignment of values of type t.
func alignment(t reflect.Type) int {
	switch t {
	case variantType:
		return 1
	case objectPathType:
		return 4
	case signatureType:
		return 1
	case interfacesType:
		return 4
	}
	switch t.Kind() {
	case reflect.Uint8:
		return 1
	case reflect.Uint16, reflect.Int16:
		return 2
	case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
		return 4
	case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
		return 8
	case reflect.Ptr:
		return alignment(t.Elem())
	}
	return 1
}

// isKeyType returns whether t is a valid type for a D-Bus dict.
func isKeyType(t reflect.Type) bool {
	switch t.Kind() {
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
		reflect.String, reflect.Uint, reflect.Int:

		return true
	}
	return false
}

// isValidInterface returns whether s is a valid name for an interface.
func isValidInterface(s string) bool {
	if len(s) == 0 || len(s) > 255 || s[0] == '.' {
		return false
	}
	elem := strings.Split(s, ".")
	if len(elem) < 2 {
		return false
	}
	for _, v := range elem {
		if len(v) == 0 {
			return false
		}
		if v[0] >= '0' && v[0] <= '9' {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// isValidMember returns whether s is a valid name for a member.
func isValidMember(s string) bool {
	if len(s) == 0 || len(s) > 255 {
		return false
	}
	i := strings.Index(s, ".")
	if i != -1 {
		return false
	}
	if s[0] >= '0' && s[0] <= '9' {
		return false
	}
	for _, c := range s {
		if !isMemberChar(c) {
			return false
		}
	}
	return true
}

func isMemberChar(c rune) bool {
	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
		(c >= 'a' && c <= 'z') || c == '_'
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// 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
//
//     https://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 webrisk

import (
	"context"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	pb "github.com/google/webrisk/internal/webrisk_proto"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/jsonpb"
)

const (
	findHashPath    = "v1/hashes:search"
	fetchUpdatePath = "v1/threatLists:computeDiff"
	threatTypeString = "threat_type"
	versionTokenString = "version_token"
	supportedCompressionsString = "constraints.supported_compressions"
	hashPrefixString = "hash_prefix"
	threatTypesString = "threat_types"
)

// The api interface specifies wrappers around the Web Risk API.
type api interface {
	ListUpdate(ctx context.Context, threat_type pb.ThreatType, version_token []byte,
		compressionTypes []pb.CompressionType) (*pb.ComputeThreatListDiffResponse, error)
	HashLookup(ctx context.Context, hashPrefix []byte,
		threatTypes []pb.ThreatType) (*pb.SearchHashesResponse, error)
}

// netAPI is an api object that talks to the server over HTTP.
type netAPI struct {
	client *http.Client
	url    *url.URL
}

// newNetAPI creates a new netAPI object pointed at the provided root URL.
// For every request, it will use the provided API key.
// If a proxy URL is given, it will be used in place of the default $HTTP_PROXY.
// If the protocol is not specified in root, then this defaults to using HTTPS.
func newNetAPI(root string, key string, proxy string) (*netAPI, error) {
	if !strings.Contains(root, "://") {
		root = "https://" + root
	}
	u, err := url.Parse(root)
	if err != nil {
		return nil, err
	}

	httpClient := &http.Client{}

	if proxy != "" {
		proxyUrl, err := url.Parse(proxy)
		if err != nil {
			return nil, err
		}
		httpClient = &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}}
	}

	q := u.Query()
	q.Set("key", key)
	u.RawQuery = q.Encode()
	return &netAPI{url: u, client: httpClient}, nil
}

// doRequests performs a GET to requestPath. It automatically unmarshals the
// response body payload as resp.
func (a *netAPI) doRequest(ctx context.Context, urlString string, resp proto.Message) error {
	httpReq, err := http.NewRequest("GET", urlString, nil)
	httpReq.Header.Add("Content-Type", "application/json")
	httpReq.Header.Add("User-Agent", "Webrisk-Client/0.1.3")
	httpReq = httpReq.WithContext(ctx)
	httpResp, err := a.client.Do(httpReq)
	if err != nil {
		return err
	}
	defer httpResp.Body.Close()
	if httpResp.StatusCode != 200 {
		return fmt.Errorf("webrisk: unexpected server response code: %d", httpResp.StatusCode)
	}
	body, err := ioutil.ReadAll(httpResp.Body)
	if err != nil {
		return err
	}
	return jsonpb.UnmarshalString(string(body), resp)
}

// ListUpdate issues a ComputeThreatListDiff API call and returns the response.
func (a *netAPI) ListUpdate(ctx context.Context, threatType pb.ThreatType, versionToken []byte,
	compressionTypes []pb.CompressionType) (*pb.ComputeThreatListDiffResponse, error) {
	resp := new(pb.ComputeThreatListDiffResponse)
	u := *a.url // Make a copy of URL
	// Add fields from ComputeThreatListDiffRequest to URL request
	q := u.Query()
	q.Set(threatTypeString, threatType.String())
	if string(versionToken) != "" {
		q.Set(versionTokenString, string(versionToken))
	}
	for _, compressionType := range compressionTypes {
		q.Add(supportedCompressionsString, compressionType.String())
	}
	u.RawQuery = q.Encode()
	u.Path = fetchUpdatePath
	return resp, a.doRequest(ctx, u.String(), resp)
}

// HashLookup issues a SearchHashes API call and returns the response.
func (a *netAPI) HashLookup(ctx context.Context, hashPrefix []byte,
	threatTypes []pb.ThreatType) (*pb.SearchHashesResponse, error) {
	resp := new(pb.SearchHashesResponse)
	u := *a.url // Make a copy of URL
	// Add fields from SearchHashesRequest to URL request
	q := u.Query()
	q.Set(hashPrefixString, base64.StdEncoding.EncodeToString(hashPrefix))
	for _, threatType := range threatTypes {
		q.Add(threatTypesString, threatType.String())
	}
	u.RawQuery = q.Encode()
	u.Path = findHashPath
	return resp, a.doRequest(ctx, u.String(), resp)
}
<commit_msg>base64 encode version token<commit_after>// Copyright 2019 Google LLC
//
// 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
//
//     https://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 webrisk

import (
	"context"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	pb "github.com/google/webrisk/internal/webrisk_proto"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/jsonpb"
)

const (
	findHashPath    = "v1/hashes:search"
	fetchUpdatePath = "v1/threatLists:computeDiff"
	threatTypeString = "threat_type"
	versionTokenString = "version_token"
	supportedCompressionsString = "constraints.supported_compressions"
	hashPrefixString = "hash_prefix"
	threatTypesString = "threat_types"
)

// The api interface specifies wrappers around the Web Risk API.
type api interface {
	ListUpdate(ctx context.Context, threat_type pb.ThreatType, version_token []byte,
		compressionTypes []pb.CompressionType) (*pb.ComputeThreatListDiffResponse, error)
	HashLookup(ctx context.Context, hashPrefix []byte,
		threatTypes []pb.ThreatType) (*pb.SearchHashesResponse, error)
}

// netAPI is an api object that talks to the server over HTTP.
type netAPI struct {
	client *http.Client
	url    *url.URL
}

// newNetAPI creates a new netAPI object pointed at the provided root URL.
// For every request, it will use the provided API key.
// If a proxy URL is given, it will be used in place of the default $HTTP_PROXY.
// If the protocol is not specified in root, then this defaults to using HTTPS.
func newNetAPI(root string, key string, proxy string) (*netAPI, error) {
	if !strings.Contains(root, "://") {
		root = "https://" + root
	}
	u, err := url.Parse(root)
	if err != nil {
		return nil, err
	}

	httpClient := &http.Client{}

	if proxy != "" {
		proxyUrl, err := url.Parse(proxy)
		if err != nil {
			return nil, err
		}
		httpClient = &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}}
	}

	q := u.Query()
	q.Set("key", key)
	u.RawQuery = q.Encode()
	return &netAPI{url: u, client: httpClient}, nil
}

// doRequests performs a GET to requestPath. It automatically unmarshals the
// response body payload as resp.
func (a *netAPI) doRequest(ctx context.Context, urlString string, resp proto.Message) error {
	httpReq, err := http.NewRequest("GET", urlString, nil)
	httpReq.Header.Add("Content-Type", "application/json")
	httpReq.Header.Add("User-Agent", "Webrisk-Client/0.1.3")
	httpReq = httpReq.WithContext(ctx)
	httpResp, err := a.client.Do(httpReq)
	if err != nil {
		return err
	}
	defer httpResp.Body.Close()
	if httpResp.StatusCode != 200 {
		return fmt.Errorf("webrisk: unexpected server response code: %d", httpResp.StatusCode)
	}
	body, err := ioutil.ReadAll(httpResp.Body)
	if err != nil {
		return err
	}
	return jsonpb.UnmarshalString(string(body), resp)
}

// ListUpdate issues a ComputeThreatListDiff API call and returns the response.
func (a *netAPI) ListUpdate(ctx context.Context, threatType pb.ThreatType, versionToken []byte,
	compressionTypes []pb.CompressionType) (*pb.ComputeThreatListDiffResponse, error) {
	resp := new(pb.ComputeThreatListDiffResponse)
	u := *a.url // Make a copy of URL
	// Add fields from ComputeThreatListDiffRequest to URL request
	q := u.Query()
	q.Set(threatTypeString, threatType.String())
	if len(versionToken) != 0 {
		q.Set(versionTokenString, base64.StdEncoding.EncodeToString(versionToken))
	}
	for _, compressionType := range compressionTypes {
		q.Add(supportedCompressionsString, compressionType.String())
	}
	u.RawQuery = q.Encode()
	u.Path = fetchUpdatePath
	return resp, a.doRequest(ctx, u.String(), resp)
}

// HashLookup issues a SearchHashes API call and returns the response.
func (a *netAPI) HashLookup(ctx context.Context, hashPrefix []byte,
	threatTypes []pb.ThreatType) (*pb.SearchHashesResponse, error) {
	resp := new(pb.SearchHashesResponse)
	u := *a.url // Make a copy of URL
	// Add fields from SearchHashesRequest to URL request
	q := u.Query()
	q.Set(hashPrefixString, base64.StdEncoding.EncodeToString(hashPrefix))
	for _, threatType := range threatTypes {
		q.Add(threatTypesString, threatType.String())
	}
	u.RawQuery = q.Encode()
	u.Path = findHashPath
	return resp, a.doRequest(ctx, u.String(), resp)
}
<|endoftext|>


<commit_before>package gochatwork

import (
	"encoding/json"
	"io"
	"time"
)

// BaseURL ChatWork API endpooint URL
const BaseURL = `https://api.chatwork.com/v2`

// Me model
type Me struct {
	AccountID        int    `json:"account_id"`
	RoomID           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	Title            string `json:"title"`
	URL              string `json:"url"`
	Introduction     string `json:"introduction"`
	Mail             string `json:"mail"`
	TelOrganization  string `json:"tel_organization"`
	TelExtension     string `json:"tel_extension"`
	TelMobile        string `json:"tel_mobile"`
	Skype            string `json:"skype"`
	Facebook         string `json:"facebook"`
	Twitter          string `json:"twitter"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// Me GET "/me"
func (c *Client) Me() (me Me, err error) {
	ret, err := c.Get("/me", map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &me)
	return
}

// Status model
type Status struct {
	UnreadRoomNum  int `json:"unread_room_num"`
	MentionRoomNum int `json:"mention_room_num"`
	MytaskRoomNum  int `json:"mytask_room_num"`
	UnreadNum      int `json:"unread_num"`
	MentionNum     int `json:"mention_num"`
	MyTaskNum      int `json:"mytask_num"`
}

// MyStatus GET "/my/status"
func (c *Client) MyStatus() (status Status, err error) {
	ret, err := c.Get("/my/status", nil)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &status)
	return
}

// MyTask model
type MyTask struct {
	Task
	Room struct {
		Roomid   int    `json:"room_id"`
		Name     string `json:"name"`
		IconPath string `json:"icon_path"`
	}
}

// MyTasks GET "/my/tasks"
// params keys
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) MyTasks(params map[string]string) (tasks []MyTask, err error) {
	ret, err := c.Get("/my/tasks", params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &tasks)
	return
}

// Contact model
type Contact struct {
	AccountID        int    `json:"account_id"`
	RoomID           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// Contacts GET "/contacts"
func (c *Client) Contacts() (contacts []Contact, err error) {
	ret, err := c.Get("/contacts", map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &contacts)
	return
}

// Room model
type Room struct {
	RoomID         int    `json:"room_id"`
	Name           string `json:"name"`
	Type           string `json:"type"`
	Role           string `json:"role"`
	Sticky         bool   `json:"sticky"`
	UnreadNum      int    `json:"unread_num"`
	MentionNum     int    `json:"mention_num"`
	MytaskNum      int    `json:"mytask_num"`
	MessageNum     int    `json:"message_num"`
	FileNum        int    `json:"file_num"`
	TaskNum        int    `json:"task_num"`
	IconPath       string `json:"icon_path"`
	LastUpdateTime int64  `json:"last_update_time"`
	Description    string `json:"description"`
}

// Rooms GET "/rooms"
func (c *Client) Rooms() (rooms []Room, err error) {
	ret, err := c.Get("/rooms", map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &rooms)
	return
}

// Room GET "/rooms/{room_id}"
func (c *Client) Room(roomID string) (room Room, err error) {
	ret, err := c.Get("/rooms/"+roomID, map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &room)
	return
}

// CreateRoom POST "/rooms"
// params keys
//   * name
//   * members_admin_ids
//   - description
//   - icon_preset
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) CreateRoom(params map[string]string) ([]byte, error) {
	return c.Post("/rooms", params)
}

// UpdateRoom PUT "/rooms/{room_id}"
// params keys
//   - description
//   - icon_preset
//   - name
func (c *Client) UpdateRoom(roomID string, params map[string]string) ([]byte, error) {
	return c.Put("/rooms/"+roomID, params)
}

// DeleteRoom DELETE "/rooms/{room_id}"
// params key
//   * action_type: [leave, delete]
func (c *Client) DeleteRoom(roomID string, params map[string]string) ([]byte, error) {
	return c.Delete("/rooms/"+roomID, params)
}

// Member model
type Member struct {
	AccountID        int    `json:"account_id"`
	Role             string `json:"role"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// RoomMembers GET "/rooms/{room_id}/members"
func (c *Client) RoomMembers(roomID string) (members []Member, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/members", map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &members)
	return
}

// UpdateRoomMembers PUT "/rooms/{room_id}/members"
// params keys
//   * members_admin_ids
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) UpdateRoomMembers(roomID string, params map[string]string) ([]byte, error) {
	return c.Put("/rooms/"+roomID+"/members", params)
}

// Account model
type Account struct {
	AccountID      int    `json:"account_id"`
	Name           string `json:"name"`
	AvatarImageURL string `json:"avatar_image_url"`
}

// Message model
type Message struct {
	MessageID  string  `json:"message_id"`
	Account    Account `json:"account"`
	Body       string  `json:"body"`
	SendTime   int64   `json:"send_time"`
	UpdateTime int64   `json:"update_time"`
}

// SendDate time.Time representation of SendTime
func (m Message) SendDate() time.Time {
	return time.Unix(m.SendTime, 0)
}

// UpdateDate time.Time representation of UpdateTime
func (m Message) UpdateDate() time.Time {
	return time.Unix(m.UpdateTime, 0)
}

// Messages slice of Message
type Messages []Message

// RoomMessages GET "/rooms/{room_id}/messages"
func (c *Client) RoomMessages(roomID string, params map[string]string) (msgs Messages, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/messages", params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &msgs)
	return
}

// PostRoomMessage POST "/rooms/{room_id}/messages"
func (c *Client) PostRoomMessage(roomID string, body string) ([]byte, error) {
	return c.Post("/rooms/"+roomID+"/messages", map[string]string{"body": body})
}

// RoomMessage GET "/rooms/{room_id}/messages/{message_id}"
func (c *Client) RoomMessage(roomID, messageID string) (message Message, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/messages/"+messageID, map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &message)
	return
}

// Task model
type Task struct {
	TaskID            int     `json:"task_id"`
	Account           Account `json:"account"`
	AssignedByAccount Account `json:"assigned_by_account"`
	MessageID         string  `json:"message_id"`
	Body              string  `json:"body"`
	LimitTime         int64   `json:"limit_time"`
	Status            string  `json:"status"`
}

// LimitDate time.Time representation of LimitTime
func (t Task) LimitDate() time.Time {
	return time.Unix(t.LimitTime, 0)
}

// RoomTasks GET "/rooms/{room_id}/tasks"
// params keys
//  - account_id
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) RoomTasks(roomID string, params map[string]string) (tasks []Task, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/tasks", params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &tasks)
	return
}

// PostRoomTask POST "/rooms/{room_id}/tasks"
// params keys
//   * body
//   * to_ids
//   - limit
func (c *Client) PostRoomTask(roomID string, params map[string]string) ([]byte, error) {
	return c.Post("/rooms/"+roomID+"/tasks", params)
}

// RoomTask GET "/rooms/{room_id}/tasks/tasks_id"
func (c *Client) RoomTask(roomID, taskID string) (task Task, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/tasks/"+taskID, map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &task)
	return
}

// File model
type File struct {
	FileID      int     `json:"file_id"`
	Account     Account `json:"account"`
	MessageID   string  `json:"message_id"`
	Filename    string  `json:"filename"`
	Filesize    int     `json:"filesize"`
	UploadTime  int64   `json:"upload_time"`
	DownloadURL string  `json:"download_url"`
}

// UploadDate time.Time representation of UploadTime
func (f File) UploadDate() time.Time {
	return time.Unix(f.UploadTime, 0)
}

// RoomFiles GET "/rooms/{room_id}/files/"
// params key
//   - account_id
func (c *Client) RoomFiles(roomID string, params map[string]string) (files []File, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/files", params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &files)
	return
}

// RoomFile GET "/rooms/{room_id}/files/{file_id}"
// params key
//   - create_download_url: ["0", "1"]
func (c *Client) RoomFile(roomID, fileID string, params map[string]string) (file File, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/files/"+fileID, params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &file)
	return
}

// PostRoomFile POST "/rooms/{room_id}/files"
func (c *Client) PostRoomFile(roomID, message, fileName string, file io.Reader) ([]byte, error) {
	return c.postFile("/rooms/"+roomID+"/files", message, fileName, file)
}

// RateLimit model
type RateLimit struct {
	Limit     int
	Remaining int
	ResetTime int64
}

// ResetDate time.Time representation of ResetTime
func (r RateLimit) ResetDate() time.Time {
	return time.Unix(r.ResetTime, 0)
}

// RateLimit returns rate limit
func (c *Client) RateLimit() *RateLimit {
	if c.latestRateLimit == nil {
		// When API is not called even once, call API and get RateLimit in response header
		c.Me()
	}
	return c.latestRateLimit
}
<commit_msg>add `login_mail` member variable on Me struct #16<commit_after>package gochatwork

import (
	"encoding/json"
	"io"
	"time"
)

// BaseURL ChatWork API endpooint URL
const BaseURL = `https://api.chatwork.com/v2`

// Me model
type Me struct {
	AccountID        int    `json:"account_id"`
	RoomID           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	Title            string `json:"title"`
	URL              string `json:"url"`
	Introduction     string `json:"introduction"`
	Mail             string `json:"mail"`
	TelOrganization  string `json:"tel_organization"`
	TelExtension     string `json:"tel_extension"`
	TelMobile        string `json:"tel_mobile"`
	Skype            string `json:"skype"`
	Facebook         string `json:"facebook"`
	Twitter          string `json:"twitter"`
	AvatarImageURL   string `json:"avatar_image_url"`
	LoginMail        string `json:"login_mail"`
}

// Me GET "/me"
func (c *Client) Me() (me Me, err error) {
	ret, err := c.Get("/me", map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &me)
	return
}

// Status model
type Status struct {
	UnreadRoomNum  int `json:"unread_room_num"`
	MentionRoomNum int `json:"mention_room_num"`
	MytaskRoomNum  int `json:"mytask_room_num"`
	UnreadNum      int `json:"unread_num"`
	MentionNum     int `json:"mention_num"`
	MyTaskNum      int `json:"mytask_num"`
}

// MyStatus GET "/my/status"
func (c *Client) MyStatus() (status Status, err error) {
	ret, err := c.Get("/my/status", nil)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &status)
	return
}

// MyTask model
type MyTask struct {
	Task
	Room struct {
		Roomid   int    `json:"room_id"`
		Name     string `json:"name"`
		IconPath string `json:"icon_path"`
	}
}

// MyTasks GET "/my/tasks"
// params keys
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) MyTasks(params map[string]string) (tasks []MyTask, err error) {
	ret, err := c.Get("/my/tasks", params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &tasks)
	return
}

// Contact model
type Contact struct {
	AccountID        int    `json:"account_id"`
	RoomID           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// Contacts GET "/contacts"
func (c *Client) Contacts() (contacts []Contact, err error) {
	ret, err := c.Get("/contacts", map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &contacts)
	return
}

// Room model
type Room struct {
	RoomID         int    `json:"room_id"`
	Name           string `json:"name"`
	Type           string `json:"type"`
	Role           string `json:"role"`
	Sticky         bool   `json:"sticky"`
	UnreadNum      int    `json:"unread_num"`
	MentionNum     int    `json:"mention_num"`
	MytaskNum      int    `json:"mytask_num"`
	MessageNum     int    `json:"message_num"`
	FileNum        int    `json:"file_num"`
	TaskNum        int    `json:"task_num"`
	IconPath       string `json:"icon_path"`
	LastUpdateTime int64  `json:"last_update_time"`
	Description    string `json:"description"`
}

// Rooms GET "/rooms"
func (c *Client) Rooms() (rooms []Room, err error) {
	ret, err := c.Get("/rooms", map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &rooms)
	return
}

// Room GET "/rooms/{room_id}"
func (c *Client) Room(roomID string) (room Room, err error) {
	ret, err := c.Get("/rooms/"+roomID, map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &room)
	return
}

// CreateRoom POST "/rooms"
// params keys
//   * name
//   * members_admin_ids
//   - description
//   - icon_preset
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) CreateRoom(params map[string]string) ([]byte, error) {
	return c.Post("/rooms", params)
}

// UpdateRoom PUT "/rooms/{room_id}"
// params keys
//   - description
//   - icon_preset
//   - name
func (c *Client) UpdateRoom(roomID string, params map[string]string) ([]byte, error) {
	return c.Put("/rooms/"+roomID, params)
}

// DeleteRoom DELETE "/rooms/{room_id}"
// params key
//   * action_type: [leave, delete]
func (c *Client) DeleteRoom(roomID string, params map[string]string) ([]byte, error) {
	return c.Delete("/rooms/"+roomID, params)
}

// Member model
type Member struct {
	AccountID        int    `json:"account_id"`
	Role             string `json:"role"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// RoomMembers GET "/rooms/{room_id}/members"
func (c *Client) RoomMembers(roomID string) (members []Member, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/members", map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &members)
	return
}

// UpdateRoomMembers PUT "/rooms/{room_id}/members"
// params keys
//   * members_admin_ids
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) UpdateRoomMembers(roomID string, params map[string]string) ([]byte, error) {
	return c.Put("/rooms/"+roomID+"/members", params)
}

// Account model
type Account struct {
	AccountID      int    `json:"account_id"`
	Name           string `json:"name"`
	AvatarImageURL string `json:"avatar_image_url"`
}

// Message model
type Message struct {
	MessageID  string  `json:"message_id"`
	Account    Account `json:"account"`
	Body       string  `json:"body"`
	SendTime   int64   `json:"send_time"`
	UpdateTime int64   `json:"update_time"`
}

// SendDate time.Time representation of SendTime
func (m Message) SendDate() time.Time {
	return time.Unix(m.SendTime, 0)
}

// UpdateDate time.Time representation of UpdateTime
func (m Message) UpdateDate() time.Time {
	return time.Unix(m.UpdateTime, 0)
}

// Messages slice of Message
type Messages []Message

// RoomMessages GET "/rooms/{room_id}/messages"
func (c *Client) RoomMessages(roomID string, params map[string]string) (msgs Messages, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/messages", params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &msgs)
	return
}

// PostRoomMessage POST "/rooms/{room_id}/messages"
func (c *Client) PostRoomMessage(roomID string, body string) ([]byte, error) {
	return c.Post("/rooms/"+roomID+"/messages", map[string]string{"body": body})
}

// RoomMessage GET "/rooms/{room_id}/messages/{message_id}"
func (c *Client) RoomMessage(roomID, messageID string) (message Message, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/messages/"+messageID, map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &message)
	return
}

// Task model
type Task struct {
	TaskID            int     `json:"task_id"`
	Account           Account `json:"account"`
	AssignedByAccount Account `json:"assigned_by_account"`
	MessageID         string  `json:"message_id"`
	Body              string  `json:"body"`
	LimitTime         int64   `json:"limit_time"`
	Status            string  `json:"status"`
}

// LimitDate time.Time representation of LimitTime
func (t Task) LimitDate() time.Time {
	return time.Unix(t.LimitTime, 0)
}

// RoomTasks GET "/rooms/{room_id}/tasks"
// params keys
//  - account_id
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) RoomTasks(roomID string, params map[string]string) (tasks []Task, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/tasks", params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &tasks)
	return
}

// PostRoomTask POST "/rooms/{room_id}/tasks"
// params keys
//   * body
//   * to_ids
//   - limit
func (c *Client) PostRoomTask(roomID string, params map[string]string) ([]byte, error) {
	return c.Post("/rooms/"+roomID+"/tasks", params)
}

// RoomTask GET "/rooms/{room_id}/tasks/tasks_id"
func (c *Client) RoomTask(roomID, taskID string) (task Task, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/tasks/"+taskID, map[string]string{})
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &task)
	return
}

// File model
type File struct {
	FileID      int     `json:"file_id"`
	Account     Account `json:"account"`
	MessageID   string  `json:"message_id"`
	Filename    string  `json:"filename"`
	Filesize    int     `json:"filesize"`
	UploadTime  int64   `json:"upload_time"`
	DownloadURL string  `json:"download_url"`
}

// UploadDate time.Time representation of UploadTime
func (f File) UploadDate() time.Time {
	return time.Unix(f.UploadTime, 0)
}

// RoomFiles GET "/rooms/{room_id}/files/"
// params key
//   - account_id
func (c *Client) RoomFiles(roomID string, params map[string]string) (files []File, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/files", params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &files)
	return
}

// RoomFile GET "/rooms/{room_id}/files/{file_id}"
// params key
//   - create_download_url: ["0", "1"]
func (c *Client) RoomFile(roomID, fileID string, params map[string]string) (file File, err error) {
	ret, err := c.Get("/rooms/"+roomID+"/files/"+fileID, params)
	if err != nil {
		return
	}
	err = json.Unmarshal(ret, &file)
	return
}

// PostRoomFile POST "/rooms/{room_id}/files"
func (c *Client) PostRoomFile(roomID, message, fileName string, file io.Reader) ([]byte, error) {
	return c.postFile("/rooms/"+roomID+"/files", message, fileName, file)
}

// RateLimit model
type RateLimit struct {
	Limit     int
	Remaining int
	ResetTime int64
}

// ResetDate time.Time representation of ResetTime
func (r RateLimit) ResetDate() time.Time {
	return time.Unix(r.ResetTime, 0)
}

// RateLimit returns rate limit
func (c *Client) RateLimit() *RateLimit {
	if c.latestRateLimit == nil {
		// When API is not called even once, call API and get RateLimit in response header
		c.Me()
	}
	return c.latestRateLimit
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/exercism/cli/configuration"
)

const VERSION = "1.5.2"
const USER_AGENT = "github.com/exercism/cli v" + VERSION

var FetchEndpoints = map[string]string{
	"current":  "/api/v1/user/assignments/current",
	"next":     "/api/v1/user/assignments/next",
	"restore":  "/api/v1/user/assignments/restore",
	"demo":     "/api/v1/assignments/demo",
	"exercise": "/api/v1/assignments",
}

type submitResponse struct {
	Id             string
	Status         string
	Language       string
	Exercise       string
	SubmissionPath string `json:"submission_path"`
	Error          string
}

type submitRequest struct {
	Key  string `json:"key"`
	Code string `json:"code"`
	Path string `json:"path"`
}

func FetchAssignments(config configuration.Config, path string) (as []Assignment, err error) {
	url := fmt.Sprintf("%s%s?key=%s", config.Hostname, path, config.ApiKey)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error fetching assignments: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	if err != nil {
		err = fmt.Errorf("Error fetching assignments: [%v]", err)
		return
	}

	if resp.StatusCode != http.StatusOK {
		var apiError struct {
			Error string `json:"error"`
		}
		err = json.Unmarshal(body, &apiError)
		if err != nil {
			err = fmt.Errorf("Error parsing API response: [%v]", err)
			return
		}

		err = fmt.Errorf("Error fetching assignments. HTTP Status Code: %d\n%s", resp.StatusCode, apiError.Error)
		return
	}

	var fr struct {
		Assignments []Assignment
	}

	err = json.Unmarshal(body, &fr)
	if err != nil {
		err = fmt.Errorf("Error parsing API response: [%v]", err)
		return
	}

	return fr.Assignments, err
}

func UnsubmitAssignment(config configuration.Config) (r string, err error) {
	path := "api/v1/user/assignments"

	url := fmt.Sprintf("%s/%s?key=%s", config.Hostname, path, config.ApiKey)

	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return
	}

	req.Header.Set("User-Agent", USER_AGENT)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error destroying submission: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return
	}

	if resp.StatusCode != http.StatusNoContent {

		var ur struct {
			Error string
		}

		err = json.Unmarshal(body, &ur)
		if err != nil {
			return
		}

		err = fmt.Errorf("Status: %d, Error: %v", resp.StatusCode, ur.Error)
		return ur.Error, err
	}

	return
}
func SubmitAssignment(config configuration.Config, filePath string, code []byte) (r submitResponse, err error) {
	path := "api/v1/user/assignments"

	url := fmt.Sprintf("%s/%s", config.Hostname, path)

	submission := submitRequest{Key: config.ApiKey, Code: string(code), Path: filePath}
	submissionJson, err := json.Marshal(submission)
	if err != nil {
		return
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(submissionJson))
	if err != nil {
		return
	}

	req.Header.Set("User-Agent", USER_AGENT)
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error posting assignment: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return
	}

	if resp.StatusCode != http.StatusCreated {
		err = json.Unmarshal(body, &r)
		if err != nil {
			return
		}
		err = fmt.Errorf("Status: %d, Error: %v", resp.StatusCode, r)
		return
	}

	err = json.Unmarshal(body, &r)
	if err != nil {
		err = fmt.Errorf("Error parsing API response: [%v]", err)
	}

	return
}
<commit_msg>Bump version<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/exercism/cli/configuration"
)

const VERSION = "1.6.0"
const USER_AGENT = "github.com/exercism/cli v" + VERSION

var FetchEndpoints = map[string]string{
	"current":  "/api/v1/user/assignments/current",
	"next":     "/api/v1/user/assignments/next",
	"restore":  "/api/v1/user/assignments/restore",
	"demo":     "/api/v1/assignments/demo",
	"exercise": "/api/v1/assignments",
}

type submitResponse struct {
	Id             string
	Status         string
	Language       string
	Exercise       string
	SubmissionPath string `json:"submission_path"`
	Error          string
}

type submitRequest struct {
	Key  string `json:"key"`
	Code string `json:"code"`
	Path string `json:"path"`
}

func FetchAssignments(config configuration.Config, path string) (as []Assignment, err error) {
	url := fmt.Sprintf("%s%s?key=%s", config.Hostname, path, config.ApiKey)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error fetching assignments: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	if err != nil {
		err = fmt.Errorf("Error fetching assignments: [%v]", err)
		return
	}

	if resp.StatusCode != http.StatusOK {
		var apiError struct {
			Error string `json:"error"`
		}
		err = json.Unmarshal(body, &apiError)
		if err != nil {
			err = fmt.Errorf("Error parsing API response: [%v]", err)
			return
		}

		err = fmt.Errorf("Error fetching assignments. HTTP Status Code: %d\n%s", resp.StatusCode, apiError.Error)
		return
	}

	var fr struct {
		Assignments []Assignment
	}

	err = json.Unmarshal(body, &fr)
	if err != nil {
		err = fmt.Errorf("Error parsing API response: [%v]", err)
		return
	}

	return fr.Assignments, err
}

func UnsubmitAssignment(config configuration.Config) (r string, err error) {
	path := "api/v1/user/assignments"

	url := fmt.Sprintf("%s/%s?key=%s", config.Hostname, path, config.ApiKey)

	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return
	}

	req.Header.Set("User-Agent", USER_AGENT)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error destroying submission: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return
	}

	if resp.StatusCode != http.StatusNoContent {

		var ur struct {
			Error string
		}

		err = json.Unmarshal(body, &ur)
		if err != nil {
			return
		}

		err = fmt.Errorf("Status: %d, Error: %v", resp.StatusCode, ur.Error)
		return ur.Error, err
	}

	return
}
func SubmitAssignment(config configuration.Config, filePath string, code []byte) (r submitResponse, err error) {
	path := "api/v1/user/assignments"

	url := fmt.Sprintf("%s/%s", config.Hostname, path)

	submission := submitRequest{Key: config.ApiKey, Code: string(code), Path: filePath}
	submissionJson, err := json.Marshal(submission)
	if err != nil {
		return
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(submissionJson))
	if err != nil {
		return
	}

	req.Header.Set("User-Agent", USER_AGENT)
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error posting assignment: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return
	}

	if resp.StatusCode != http.StatusCreated {
		err = json.Unmarshal(body, &r)
		if err != nil {
			return
		}
		err = fmt.Errorf("Status: %d, Error: %v", resp.StatusCode, r)
		return
	}

	err = json.Unmarshal(body, &r)
	if err != nil {
		err = fmt.Errorf("Error parsing API response: [%v]", err)
	}

	return
}
<|endoftext|>


<commit_before>/**
* Copyright 2012 Matthew Baird
*
* 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 gochimp

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
)

const mandrill_uri string = "mandrillapp.com/api/"
const mandrill_version string = "1.0"

type MandrillAPI struct {
	Key      string
	endpoint string
}

type ChimpAPI struct {
	Key      string
	endpoint string
}

// see https://mandrillapp.com/api/docs/
// currently supporting json output formats
func NewMandrill(apiKey string) (*MandrillAPI, error) {
	u := url.URL{}
	u.Scheme = "https"
	u.Host = mandrill_uri
	u.Path = mandrill_version
	return &MandrillAPI{apiKey, u.String()}, nil
}

const mailchimp_uri string = "%s.api.mailchimp.com"
const mailchimp_version string = "/1.3/"
const debug bool = false

var mailchimp_datacenter = regexp.MustCompile("[a-z]+[0-9]+$")

func NewChimp(apiKey string, https bool) (*ChimpAPI, error) {
	u := url.URL{}
	if https {
		u.Scheme = "https"
	} else {
		u.Scheme = "http"
	}
	u.Host = mandrill_uri
	u.Path = mandrill_version
	u.Host = fmt.Sprintf("%s.api.mailchimp.com", mailchimp_datacenter.FindString(apiKey))
	u.Path = mailchimp_version
	return &ChimpAPI{apiKey, u.String() + "?method="}, nil
}

func runChimp(api *ChimpAPI, path string, parameters map[string]interface{}) ([]byte, error) {
	if parameters == nil {
		parameters = make(map[string]interface{})
	}
	parameters["key"] = api.Key
	b, err := json.Marshal(parameters)
	if err != nil {
		return nil, err
	}
	requestUrl := fmt.Sprintf("%s%s", api.endpoint, path)
	if debug {
		log.Printf("Request URL:%s", requestUrl)
	}
	resp, err := http.Post(requestUrl, "application/json", bytes.NewBuffer(b))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if debug {
		log.Printf("Response Body:%s", string(body))
	}
	if err = chimpErrorCheck(body); err != nil {
		return nil, err
	}
	return body, nil
}

func runMandrill(api *MandrillAPI, path string, parameters map[string]interface{}) ([]byte, error) {
	if parameters == nil {
		parameters = make(map[string]interface{})
	}
	parameters["key"] = api.Key
	b, err := json.Marshal(parameters)
	if debug {
		log.Printf("Payload:%s", string(b))
	}
	if err != nil {
		return nil, err
	}
	requestUrl := fmt.Sprintf("%s%s", api.endpoint, path)
	if debug {
		log.Printf("Request URL:%s", requestUrl)
	}
	resp, err := http.Post(requestUrl, "application/json", bytes.NewBuffer(b))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if debug {
		log.Printf("Response Body:%s", string(body))
	}
	if err = mandrillErrorCheck(body); err != nil {
		return nil, err
	}
	return body, nil
}

func parseString(body []byte, err error) (string, error) {
	if err != nil {
		return "", err
	}
	return strconv.Unquote(string(body))
}

func parseMandrillJson(api *MandrillAPI, path string, parameters map[string]interface{}, retval interface{}) error {
	body, err := runMandrill(api, path, parameters)
	if err != nil {
		return err
	}
	json.Unmarshal(body, retval)
	return nil
}

func parseChimpJson(api *ChimpAPI, method string, parameters map[string]interface{}, retval interface{}) error {
	body, err := runChimp(api, method, parameters)
	if err != nil {
		return err
	}
	return parseJson(body, retval)
}

type JsonAlterer interface {
	alterJson(b []byte) []byte
}

func parseJson(body []byte, retval interface{}) error {
	switch r := retval.(type) {
	case JsonAlterer:
		json.Unmarshal(r.alterJson(body), retval)
	default:
		json.Unmarshal(body, retval)
	}
	return nil
}
<commit_msg>Allow http Transport override.<commit_after>/**
* Copyright 2012 Matthew Baird
*
* 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 gochimp

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
)

const mandrill_uri string = "mandrillapp.com/api/"
const mandrill_version string = "1.0"

type MandrillAPI struct {
	Key       string
	Transport http.RoundTripper
	endpoint  string
}

type ChimpAPI struct {
	Key       string
	Transport http.RoundTripper
	endpoint  string
}

// see https://mandrillapp.com/api/docs/
// currently supporting json output formats
func NewMandrill(apiKey string) (*MandrillAPI, error) {
	u := url.URL{}
	u.Scheme = "https"
	u.Host = mandrill_uri
	u.Path = mandrill_version
	return &MandrillAPI{Key: apiKey, endpoint: u.String()}, nil
}

const mailchimp_uri string = "%s.api.mailchimp.com"
const mailchimp_version string = "/1.3/"
const debug bool = false

var mailchimp_datacenter = regexp.MustCompile("[a-z]+[0-9]+$")

func NewChimp(apiKey string, https bool) (*ChimpAPI, error) {
	u := url.URL{}
	if https {
		u.Scheme = "https"
	} else {
		u.Scheme = "http"
	}
	u.Host = mandrill_uri
	u.Path = mandrill_version
	u.Host = fmt.Sprintf("%s.api.mailchimp.com", mailchimp_datacenter.FindString(apiKey))
	u.Path = mailchimp_version
	return &ChimpAPI{Key: apiKey, endpoint: u.String() + "?method="}, nil
}

func runChimp(api *ChimpAPI, path string, parameters map[string]interface{}) ([]byte, error) {
	if parameters == nil {
		parameters = make(map[string]interface{})
	}
	parameters["key"] = api.Key
	b, err := json.Marshal(parameters)
	if err != nil {
		return nil, err
	}
	requestUrl := fmt.Sprintf("%s%s", api.endpoint, path)
	if debug {
		log.Printf("Request URL:%s", requestUrl)
	}
	client := &http.Client{Transport: api.Transport}
	resp, err := client.Post(requestUrl, "application/json", bytes.NewBuffer(b))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if debug {
		log.Printf("Response Body:%s", string(body))
	}
	if err = chimpErrorCheck(body); err != nil {
		return nil, err
	}
	return body, nil
}

func runMandrill(api *MandrillAPI, path string, parameters map[string]interface{}) ([]byte, error) {
	if parameters == nil {
		parameters = make(map[string]interface{})
	}
	parameters["key"] = api.Key
	b, err := json.Marshal(parameters)
	if debug {
		log.Printf("Payload:%s", string(b))
	}
	if err != nil {
		return nil, err
	}
	requestUrl := fmt.Sprintf("%s%s", api.endpoint, path)
	if debug {
		log.Printf("Request URL:%s", requestUrl)
	}
	client := &http.Client{Transport: api.Transport}
	resp, err := client.Post(requestUrl, "application/json", bytes.NewBuffer(b))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if debug {
		log.Printf("Response Body:%s", string(body))
	}
	if err = mandrillErrorCheck(body); err != nil {
		return nil, err
	}
	return body, nil
}

func parseString(body []byte, err error) (string, error) {
	if err != nil {
		return "", err
	}
	return strconv.Unquote(string(body))
}

func parseMandrillJson(api *MandrillAPI, path string, parameters map[string]interface{}, retval interface{}) error {
	body, err := runMandrill(api, path, parameters)
	if err != nil {
		return err
	}
	json.Unmarshal(body, retval)
	return nil
}

func parseChimpJson(api *ChimpAPI, method string, parameters map[string]interface{}, retval interface{}) error {
	body, err := runChimp(api, method, parameters)
	if err != nil {
		return err
	}
	return parseJson(body, retval)
}

type JsonAlterer interface {
	alterJson(b []byte) []byte
}

func parseJson(body []byte, retval interface{}) error {
	switch r := retval.(type) {
	case JsonAlterer:
		json.Unmarshal(r.alterJson(body), retval)
	default:
		json.Unmarshal(body, retval)
	}
	return nil
}
<|endoftext|>


<commit_before>package web

import (
    "io"
	"net/http"
	"draringi/codejam2013/src/forecasting"
	"draringi/codejam2013/src/data"
    "encoding/json"
    "time"
    "sync"
)

type dataError struct {
    What string
    When time.Time
}

func (self *dataError) Error() string {
    return "["+self.When.Format(data.ISO)+"] " + self.What
}

type future struct {
    Records []record
}

type record struct {
    Date string
    Power float64
}

type dashboardHelper struct {
    Data *data.CSVData
    Forcast *future
    Lock *sync.Mutex
}

type Dashboard struct {
	channel chan (*data.CSVData)
	JSONAid *dashboardHelper
}

func (self *Dashboard) Init () {
    self.Lock = new(sync.Mutex)
    self.Lock.Lock()
	self.channel = make(chan (*data.CSVData), 1)
    self.JSONAid = new(dashboardHelper)
    self.Lock.Unlock()
    self.JSONAid.Data = nil
    self.JSONAid.Forcast = nil
	forecasting.PredictPulse(self.channel)
	go func () {
		for {
			tmp := <-self.channel
            if tmp != nil {
				self.JSONAid.Data = tmp
			}
		}
	} ()
    return
}

func (self *Dashboard) ServeHTTP (w http.ResponseWriter, request *http.Request) {
	http.ServeFile(w, request, "dashboard.html")
}

func (self *dashboardHelper) Build (Data *data.CSVData) {
    self.Data = Data
    self.Forcast = new(future)
    self.Forcast.Records = make([]record,len(Data.Data))
    for i :=0; i<len(Data.Data); i++ {
        self.Forcast.Records[i].Date = Data.Data[i].Time.Format(data.ISO)
        self.Forcast.Records[i].Power = Data.Data[i].Power
    }
}

func (self *dashboardHelper) jsonify (w io.Writer) error {
    encoder := json.NewEncoder(w)
    if self.Data != nil {
        encoder.Encode(self.Forcast)
        return nil
    } else {
        return &dataError{"Error: Could not load data", time.Now()}
    }
}

func (self *dashboardHelper) ServeHTTP (w http.ResponseWriter, request *http.Request) {
    err := self.jsonify(w)
    if err != nil {
        http.Error(w,err.Error(), 404)
    }
}
<commit_msg>please put the lock in the right place...<commit_after>package web

import (
    "io"
	"net/http"
	"draringi/codejam2013/src/forecasting"
	"draringi/codejam2013/src/data"
    "encoding/json"
    "time"
    "sync"
)

type dataError struct {
    What string
    When time.Time
}

func (self *dataError) Error() string {
    return "["+self.When.Format(data.ISO)+"] " + self.What
}

type future struct {
    Records []record
}

type record struct {
    Date string
    Power float64
}

type dashboardHelper struct {
    Data *data.CSVData
    Forcast *future
}

type Dashboard struct {
	channel chan (*data.CSVData)
	JSONAid *dashboardHelper
    Lock *sync.Mutex
}

func (self *Dashboard) Init () {
    self.Lock = new(sync.Mutex)
    self.Lock.Lock()
	self.channel = make(chan (*data.CSVData), 1)
    self.JSONAid = new(dashboardHelper)
    self.Lock.Unlock()
    self.JSONAid.Data = nil
    self.JSONAid.Forcast = nil
	forecasting.PredictPulse(self.channel)
	go func () {
		for {
			tmp := <-self.channel
            if tmp != nil {
				self.JSONAid.Data = tmp
			}
		}
	} ()
    return
}

func (self *Dashboard) ServeHTTP (w http.ResponseWriter, request *http.Request) {
	http.ServeFile(w, request, "dashboard.html")
}

func (self *dashboardHelper) Build (Data *data.CSVData) {
    self.Data = Data
    self.Forcast = new(future)
    self.Forcast.Records = make([]record,len(Data.Data))
    for i :=0; i<len(Data.Data); i++ {
        self.Forcast.Records[i].Date = Data.Data[i].Time.Format(data.ISO)
        self.Forcast.Records[i].Power = Data.Data[i].Power
    }
}

func (self *dashboardHelper) jsonify (w io.Writer) error {
    encoder := json.NewEncoder(w)
    if self.Data != nil {
        encoder.Encode(self.Forcast)
        return nil
    } else {
        return &dataError{"Error: Could not load data", time.Now()}
    }
}

func (self *dashboardHelper) ServeHTTP (w http.ResponseWriter, request *http.Request) {
    err := self.jsonify(w)
    if err != nil {
        http.Error(w,err.Error(), 404)
    }
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "fmt"
    "net/http"
    "strconv"
    "flag"
    "time"
    "io/ioutil"
    "encoding/json"
    "runtime"
)

type Dsp struct {
    DspId   int
    ReqId   string
    SleepMs int
    Status   int
    Price    int
}

// {"id":"gZtaC8svEsDMyXYUukU3GM62gRPZm4mAT7MNINjrnTB3l47gBFbRxmeI4djNejm1","status":1,"price":1000}
type BidResponse struct {
    Id     string
    Status int
    Price  int
}

type Result struct {
    DspId  int
    ReqId  string
    Status  int
    Price   int
}

type Win struct {
    DspId  int
    ReqId  string
    Price  int
}

type Response struct {
    Id      string      `json:"id"`
    DspId   int         `json:"dsp_id"`
    Price   int         `json:"price"`
}

func makeClient() http.Client {
    transport := http.Transport{
        ResponseHeaderTimeout: time.Millisecond * 120,
        MaxIdleConnsPerHost: 200,
    }

    client := http.Client{
        Transport: &transport,
    }

    return client
}

func doRequests(dsps []Dsp) <-chan Result {
    receiver := make(chan Result, len(dsps))

    for _, dsp := range dsps {
        go doRequest(dsp, receiver)
    }

    return receiver
}

var client = makeClient()
func doRequest(dsp Dsp, receiver chan Result) {
    url := fmt.Sprintf("http://dsp/ad?id=%s&t=%d&s=%d&p=%d", dsp.ReqId, dsp.SleepMs, dsp.Status, dsp.Price)
    //log.Println(url)
    resp, err := client.Get(url)

    result := Result{}
    result.DspId = dsp.DspId
    if err != nil {
        //log.Println("error")
    } else if resp != nil {
        defer resp.Body.Close()

        body, errRead := ioutil.ReadAll(resp.Body)
        if errRead != nil {
            log.Println("response read error")
        } else {
            //log.Println(string(body))
            var bidResp BidResponse
            errJson := json.Unmarshal(body, &bidResp)
            if errJson != nil {
                log.Println("json parse error")
            }

            result.ReqId  = bidResp.Id
            result.Status = bidResp.Status
            result.Price  = bidResp.Price
        }
    }

    receiver <- result
}

func doAuction(results []Result) Win {
    win := Win{}
    win.DspId = -1

    var maxResult Result
    for _, result := range results {
        if result.Status != 1 { continue }

        if maxResult.Price == 0 {
            maxResult = result
        } else if result.Price > maxResult.Price {
            maxResult = result
        }
    }

    win.DspId = maxResult.DspId
    win.ReqId = maxResult.ReqId
    win.Price = maxResult.Price

    return win
}

func handler(w http.ResponseWriter, r *http.Request) {
    params     := r.URL.Query()
    id         := params["id"][0]
    dspNum, _ := strconv.Atoi( params["dsp"][0] )
    dsps       := make([]Dsp, dspNum)

    // parse dsp parameters
    for i := 0; i < dspNum; i++ {
        sleepMs, _ := strconv.Atoi( params[fmt.Sprintf("d%d_t", i)][0] )
        status, _   := strconv.Atoi( params[fmt.Sprintf("d%d_s", i)][0] )
        price       := 0
        price_key   := fmt.Sprintf("d%d_p", i)
        if params[price_key] != nil {
            price, _ = strconv.Atoi( params[price_key][0] )
        }

        dsp     := &Dsp{ i, id, sleepMs, status, price }
        dsps[i] = *dsp
    }

    // do request to dsps
    results  := make([]Result, len(dsps))
    receiver := doRequests(dsps)

    // receive result
    resultNum := 0
    for {
        result := <-receiver
        //log.Println(result)
        results[result.DspId] = result

        resultNum++
        if len(results) == resultNum { break }
    }
    //log.Println(results)

    win := doAuction(results)
    //log.Println(win)

    w.Header().Set("Content-Type", "application/json")
    response := Response{
        Id: win.ReqId,
        DspId: win.DspId,
        Price: win.Price,
    }
    bytes, _ := json.Marshal(response)
    jsonStr := string(bytes)
//    log.Println(jsonStr)
    fmt.Fprint(w, jsonStr)
}

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())

    port := flag.Int("port", 5000, "PORT")
    flag.Parse()

    http.HandleFunc("/ad", handler)
    log.Fatal( http.ListenAndServe(fmt.Sprintf(":%d", *port), nil) )
}
<commit_msg>add parameter host<commit_after>package main

import (
    "log"
    "fmt"
    "net/http"
    "strconv"
    "flag"
    "time"
    "io/ioutil"
    "encoding/json"
    "runtime"
)

type Dsp struct {
    DspId   int
    ReqId   string
    SleepMs int
    Status   int
    Price    int
}

// {"id":"gZtaC8svEsDMyXYUukU3GM62gRPZm4mAT7MNINjrnTB3l47gBFbRxmeI4djNejm1","status":1,"price":1000}
type BidResponse struct {
    Id     string
    Status int
    Price  int
}

type Result struct {
    DspId  int
    ReqId  string
    Status  int
    Price   int
}

type Win struct {
    DspId  int
    ReqId  string
    Price  int
}

type Response struct {
    Id      string      `json:"id"`
    DspId   int         `json:"dsp_id"`
    Price   int         `json:"price"`
}

func makeClient() http.Client {
    transport := http.Transport{
        ResponseHeaderTimeout: time.Millisecond * 120,
        MaxIdleConnsPerHost: 200,
    }

    client := http.Client{
        Transport: &transport,
    }

    return client
}

func doRequests(dsps []Dsp) <-chan Result {
    receiver := make(chan Result, len(dsps))

    for _, dsp := range dsps {
        go doRequest(dsp, receiver)
    }

    return receiver
}

var client = makeClient()
func doRequest(dsp Dsp, receiver chan Result) {
    url := fmt.Sprintf("http://%s/ad?id=%s&t=%d&s=%d&p=%d", host, dsp.ReqId, dsp.SleepMs, dsp.Status, dsp.Price)
    //log.Println(url)
    resp, err := client.Get(url)

    result := Result{}
    result.DspId = dsp.DspId
    if err != nil {
        //log.Println("error")
    } else if resp != nil {
        defer resp.Body.Close()

        body, errRead := ioutil.ReadAll(resp.Body)
        if errRead != nil {
            log.Println("response read error")
        } else {
            //log.Println(string(body))
            var bidResp BidResponse
            errJson := json.Unmarshal(body, &bidResp)
            if errJson != nil {
                log.Println("json parse error")
            }

            result.ReqId  = bidResp.Id
            result.Status = bidResp.Status
            result.Price  = bidResp.Price
        }
    }

    receiver <- result
}

func doAuction(results []Result) Win {
    win := Win{}
    win.DspId = -1

    var maxResult Result
    for _, result := range results {
        if result.Status != 1 { continue }

        if maxResult.Price == 0 {
            maxResult = result
        } else if result.Price > maxResult.Price {
            maxResult = result
        }
    }

    win.DspId = maxResult.DspId
    win.ReqId = maxResult.ReqId
    win.Price = maxResult.Price

    return win
}

func handler(w http.ResponseWriter, r *http.Request) {
    params     := r.URL.Query()
    id         := params["id"][0]
    dspNum, _ := strconv.Atoi( params["dsp"][0] )
    dsps       := make([]Dsp, dspNum)

    // parse dsp parameters
    for i := 0; i < dspNum; i++ {
        sleepMs, _ := strconv.Atoi( params[fmt.Sprintf("d%d_t", i)][0] )
        status, _   := strconv.Atoi( params[fmt.Sprintf("d%d_s", i)][0] )
        price       := 0
        price_key   := fmt.Sprintf("d%d_p", i)
        if params[price_key] != nil {
            price, _ = strconv.Atoi( params[price_key][0] )
        }

        dsp     := &Dsp{ i, id, sleepMs, status, price }
        dsps[i] = *dsp
    }

    // do request to dsps
    results  := make([]Result, len(dsps))
    receiver := doRequests(dsps)

    // receive result
    resultNum := 0
    for {
        result := <-receiver
        //log.Println(result)
        results[result.DspId] = result

        resultNum++
        if len(results) == resultNum { break }
    }
    //log.Println(results)

    win := doAuction(results)
    //log.Println(win)

    w.Header().Set("Content-Type", "application/json")
    response := Response{
        Id: win.ReqId,
        DspId: win.DspId,
        Price: win.Price,
    }
    bytes, _ := json.Marshal(response)
    jsonStr := string(bytes)
//    log.Println(jsonStr)
    fmt.Fprint(w, jsonStr)
}

var host *string
func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())

    port := flag.Int("port", 5000, "PORT")
    host = flag.String("host", "dsp", "HOST")
    flag.Parse()

    http.HandleFunc("/ad", handler)
    log.Fatal( http.ListenAndServe(fmt.Sprintf(":%d", *port), nil) )
}
<|endoftext|>


<commit_before>package op

import (
	"fmt"
	"testing"
)

func calcRMS(a, b Parameter) float64 {
	sum := float64(0)
	for it := a.IndexIterator(); it.Next(); {
		i := it.Index()
		diff := a.Get(i) - b.Get(i)
		sum += float64(diff * diff)
	}
	return sum / float64(a.IndexIterator().Size())
}

// We need to test projected_gradient so that we have the confidence to use it
// in other places.
func TestPGMinimize0(t *testing.T) {
	copy := 1
	epsilon := 1e-5
	lower := NewAllTheSameParameter(-20.0, copy*2)
	upper := NewAllTheSameParameter(+20.0, copy*2)
	ground_truth := NewAllTheSameParameter(1.0, copy*2)

	proj := &Projection{lower_bound: lower, upper_bound: upper}
	minimizer := &ProjectedGradient{projector: proj, beta: 0.1, sigma: 0.01, alpha: 1.0}
	loss := &Rosenbrock{numOfCopies: copy, count: 0}
	stpCount := MakeFixCountStopCriteria(1200)

	stt0 := createParam(3.0, -2.0, copy)

	minimizer.Minimize(loss, stpCount, stt0)
	fmt.Println(stt0)

	rms0 := calcRMS(stt0, ground_truth)
	if rms0 > epsilon {
		t.Errorf("RMS error larger than threshold: actual %f, expected %f", rms0, epsilon)
	}
}

func TestPGMinimize1(t *testing.T) {
	copy := 20
	epsilon := 1e-5
	lower := NewAllTheSameParameter(-20.0, copy*2)
	upper := NewAllTheSameParameter(+20.0, copy*2)
	ground_truth := NewAllTheSameParameter(1.0, copy*2)

	proj := &Projection{lower_bound: lower, upper_bound: upper}
	minimizer := &ProjectedGradient{projector: proj, beta: 0.1, sigma: 0.01, alpha: 1.0}
	loss := &Rosenbrock{numOfCopies: copy, count: 0}
	stpNorm := MakeGradientNormStopCriteria(1.0e-4)
	stt1 := createParam(15.0, -10.0, copy)

	minimizer.Minimize(loss, stpNorm, stt1)
	fmt.Println(stt1)

	rms1 := calcRMS(stt1, ground_truth)
	if rms1 > epsilon {
		t.Errorf("RMS error larger than threshold: actual %f, expected %f", rms1, epsilon)
	}
}

func TestPGMinimize2(t *testing.T) {
	copy := 100
	epsilon := 1e-4
	lower := NewAllTheSameParameter(-20.0, copy*2)
	upper := NewAllTheSameParameter(+20.0, copy*2)
	ground_truth := NewAllTheSameParameter(1.0, copy*2)

	proj := &Projection{lower_bound: lower, upper_bound: upper}
	loss := &Rosenbrock{numOfCopies: copy, count: 0}
	minimizer := &ProjectedGradient{projector: proj, beta: 0.1, sigma: 0.01, alpha: 1.0}
	stpComposed := MakeComposedCriterion(MakeFixCountStopCriteria(1e6), MakeGradientNormStopCriteria(1.0e-3))
	stt2 := createParam(15.0, -10.0, copy)

	minimizer.Minimize(loss, stpComposed, stt2)
	fmt.Println(stt2)

	rms2 := calcRMS(stt2, ground_truth)
	if rms2 > epsilon {
		t.Errorf("RMS error larger than threshold: actual %f, expected %f", rms2, epsilon)
	}
}
<commit_msg>Fix TestPGMinimize0 unittest<commit_after>package op

import (
	"fmt"
	"testing"
)

func calcRMS(a, b Parameter) float64 {
	sum := float64(0)
	for it := a.IndexIterator(); it.Next(); {
		i := it.Index()
		diff := a.Get(i) - b.Get(i)
		sum += float64(diff * diff)
	}
	return sum / float64(a.IndexIterator().Size())
}

// We need to test projected_gradient so that we have the confidence to use it
// in other places.
func TestPGMinimize0(t *testing.T) {
	copy := 1
	epsilon := 1e-5
	lower := NewAllTheSameParameter(-20.0, copy*2)
	upper := NewAllTheSameParameter(+20.0, copy*2)
	ground_truth := NewAllTheSameParameter(1.0, copy*2)

	proj := &Projection{lower_bound: lower, upper_bound: upper}
	minimizer := &ProjectedGradient{projector: proj, beta: 0.1, sigma: 0.01, alpha: 1.0}
	loss := &Rosenbrock{numOfCopies: copy, count: 0}
	stpCount := MakeFixCountStopCriteria(1500)

	stt0 := createParam(3.0, -2.0, copy)

	minimizer.Minimize(loss, stpCount, stt0)
	fmt.Println(stt0)

	rms0 := calcRMS(stt0, ground_truth)
	if rms0 > epsilon {
		t.Errorf("RMS error larger than threshold: actual %f, expected %f", rms0, epsilon)
	}
}

func TestPGMinimize1(t *testing.T) {
	copy := 20
	epsilon := 1e-5
	lower := NewAllTheSameParameter(-20.0, copy*2)
	upper := NewAllTheSameParameter(+20.0, copy*2)
	ground_truth := NewAllTheSameParameter(1.0, copy*2)

	proj := &Projection{lower_bound: lower, upper_bound: upper}
	minimizer := &ProjectedGradient{projector: proj, beta: 0.1, sigma: 0.01, alpha: 1.0}
	loss := &Rosenbrock{numOfCopies: copy, count: 0}
	stpNorm := MakeGradientNormStopCriteria(1.0e-4)
	stt1 := createParam(15.0, -10.0, copy)

	minimizer.Minimize(loss, stpNorm, stt1)
	fmt.Println(stt1)

	rms1 := calcRMS(stt1, ground_truth)
	if rms1 > epsilon {
		t.Errorf("RMS error larger than threshold: actual %f, expected %f", rms1, epsilon)
	}
}

func TestPGMinimize2(t *testing.T) {
	copy := 100
	epsilon := 1e-4
	lower := NewAllTheSameParameter(-20.0, copy*2)
	upper := NewAllTheSameParameter(+20.0, copy*2)
	ground_truth := NewAllTheSameParameter(1.0, copy*2)

	proj := &Projection{lower_bound: lower, upper_bound: upper}
	loss := &Rosenbrock{numOfCopies: copy, count: 0}
	minimizer := &ProjectedGradient{projector: proj, beta: 0.1, sigma: 0.01, alpha: 1.0}
	stpComposed := MakeComposedCriterion(MakeFixCountStopCriteria(1e6), MakeGradientNormStopCriteria(1.0e-3))
	stt2 := createParam(15.0, -10.0, copy)

	minimizer.Minimize(loss, stpComposed, stt2)
	fmt.Println(stt2)

	rms2 := calcRMS(stt2, ground_truth)
	if rms2 > epsilon {
		t.Errorf("RMS error larger than threshold: actual %f, expected %f", rms2, epsilon)
	}
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"github.com/boltdb/bolt"
)

type Aggregate struct {
	db *bolt.DB
}

type CreatedAppEvent struct {
	AppId string
}

type RemovedAppEvent struct {
	AppId string
}

func NewAggregate(db *bolt.DB) *Aggregate {
	return &Aggregate{db: db}
}

const (
	appsBucketName = "PuffinApps"
)

func (self *Aggregate) CreateApp(appId string) error {
	return self.db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(appsBucketName))
		if err != nil {
			return err
		}

		v := b.Get([]byte(appId))
		if v != nil {
			return fmt.Errorf("ID already exists")
		}

		event := CreatedAppEvent{AppId: appId}
		return self.onCreatedAppEvent(b, event)
	})
}

func (self *Aggregate) onCreatedAppEvent(b *bolt.Bucket, event CreatedAppEvent) error {
	return b.Put([]byte(event.AppId), []byte{1})
}

func (self *Aggregate) RemoveApp(appId string) error {
	return self.db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(appsBucketName))
		if err != nil {
			return err
		}

		event := RemovedAppEvent{AppId: appId}
		return self.onRemovedAppEvent(b, event)
	})
}

func (self *Aggregate) onRemovedAppEvent(b *bolt.Bucket, event RemovedAppEvent) error {
	return b.Delete([]byte(event.AppId))
}
<commit_msg>getting into shape<commit_after>package app

import (
	"fmt"
	"github.com/boltdb/bolt"
)

type Aggregate struct {
	db *bolt.DB
}

type CreatedAppEvent struct {
	AppId string
}

type RemovedAppEvent struct {
	AppId string
}

func NewAggregate(db *bolt.DB) *Aggregate {
	return &Aggregate{db: db}
}

const (
	appsBucketName = "PuffinApps"
)

func (self *Aggregate) CreateApp(appId string) error {
	return self.db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(appsBucketName))
		if err != nil {
			return err
		}
		event, err := createApp(b, appId)
		if err != nil {
			return err
		}
		return onCreatedAppEvent(b, event)
	})
}

func (self *Aggregate) OnCreatedApp(event CreatedAppEvent) error {
	return self.db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(appsBucketName))
		if err != nil {
			return err
		}
		return onCreatedAppEvent(b, event)
	})
}

func createApp(b *bolt.Bucket, appId string) (event CreatedAppEvent, err error) {
	v := b.Get([]byte(appId))
	if v != nil {
		err = fmt.Errorf("ID already exists")
		return
	}
	event = CreatedAppEvent{AppId: appId}
	return
}

func onCreatedAppEvent(b *bolt.Bucket, event CreatedAppEvent) error {
	return b.Put([]byte(event.AppId), []byte{1})
}

func (self *Aggregate) RemoveApp(appId string) error {
	return self.db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(appsBucketName))
		if err != nil {
			return err
		}
		event, err := removeApp(b, appId)
		if err != nil {
			return err
		}
		return onRemovedAppEvent(b, event)
	})
}

func (self *Aggregate) OnRemovedApp(event RemovedAppEvent) error {
	return self.db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(appsBucketName))
		if err != nil {
			return err
		}
		return onRemovedAppEvent(b, event)
	})
}

func removeApp(b *bolt.Bucket, appId string) (event RemovedAppEvent, err error) {
	event = RemovedAppEvent{AppId: appId}
	return
}

func onRemovedAppEvent(b *bolt.Bucket, event RemovedAppEvent) error {
	return b.Delete([]byte(event.AppId))
}
<|endoftext|>