<commit_before>package engine

import (
	"errors"
	"fmt"
	"sync"
)

type ErrNotLocated struct {
	Location Location
}

func (e *ErrNotLocated) Error() string {
	return "not located"
}

type ErrLocated struct {
	Location Location
}

func (e *ErrLocated) Error() string {
	return "located"
}

type ErrDotsOccupied struct {
	Dots []*Dot // List of occupied dots
}

func (e *ErrDotsOccupied) Error() string {
	return fmt.Sprintf("dots is occupied: %s", e.Dots)
}

// Scene contains locations
type Scene struct {
	area           *Area
	locations      []Location
	locationsMutex *sync.RWMutex
}

// NewScene returns new empty scene
func NewScene(area *Area) (*Scene, error) {
	return &Scene{
		area:           area,
		locations:      make([]Location, 0),
		locationsMutex: &sync.RWMutex{},
	}, nil
}

// unsafeLocated returns true if passed location is located on scene
func (s *Scene) unsafeLocated(location Location) bool {
	for i := range s.locations {
		if s.locations[i].Equals(location) {
			return true
		}
	}
	return false
}

func (s *Scene) Located(location Location) bool {
	s.locationsMutex.RLock()
	defer s.locationsMutex.RUnlock()
	return s.unsafeLocated(location)
}

// unsafeDotOccupied returns true if passed dot already used by a location on scene
func (s *Scene) unsafeDotOccupied(dot *Dot) bool {
	if s.area.Contains(dot) {
		for _, location := range s.locations {
			if location.Contains(dot) {
				return true
			}
		}
	}
	return false
}

func (s *Scene) DotOccupied(dot *Dot) bool {
	s.locationsMutex.RLock()
	defer s.locationsMutex.RUnlock()
	return s.unsafeDotOccupied(dot)
}

// unsafeGetLocationByDot returns location which contains passed dot
func (s *Scene) unsafeGetLocationByDot(dot *Dot) Location {
	if s.area.Contains(dot) {
		for _, location := range s.locations {
			if location.Contains(dot) {
				return location.Copy()
			}
		}
	}
	return nil
}

func (s *Scene) GetLocationByDot(dot *Dot) Location {
	s.locationsMutex.RLock()
	defer s.locationsMutex.RUnlock()
	return s.unsafeGetLocationByDot(dot)
}

type ErrLocate struct {
	Err error
}

func (e *ErrLocate) Error() string {
	return "cannot locate: " + e.Err.Error()
}

func (s *Scene) unsafeLocate(location Location) *ErrLocate {
	if s.unsafeLocated(location) {
		return &ErrLocate{
			Err: &ErrLocated{
				Location: location.Copy(),
			},
		}
	}

	location = location.Copy()
	occupiedDots := make([]*Dot, 0)

	// Check each dot of passed location
	for i := uint16(0); i < location.DotCount(); i++ {
		var dot = location.Dot(i)

		if s.area.Contains(dot) {
			return &ErrLocate{
				Err: &ErrAreaNotContainsDot{
					Dot: dot,
				},
			}
		}

		for i := range s.locations {
			if s.locations[i].Contains(dot) {
				occupiedDots = append(occupiedDots, dot)
				break
			}
		}
	}

	if len(occupiedDots) > 0 {
		return &ErrLocate{
			Err: &ErrDotsOccupied{
				Dots: occupiedDots,
			},
		}
	}

	// Add to location list of scene
	s.locations = append(s.locations, location)

	return nil
}

// Locate tries to create location to scene
func (s *Scene) Locate(location Location) *ErrLocate {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeLocate(location)
}

func (s *Scene) unsafeLocateAvailableDots(location Location) Location {
	if s.unsafeLocated(location) {
		return Location{}
	}

	location = location.Copy()
	locationMirror := location.Copy()

	// Check each dot of passed location
	for i := uint16(0); i < locationMirror.DotCount(); i++ {
		var dot = locationMirror.Dot(i)

		if !s.area.Contains(dot) {
			location = location.Delete(dot)
			continue
		}

		for i := range s.locations {
			if s.locations[i].Contains(dot) {
				location = location.Delete(dot)
				break
			}
		}
	}

	if len(location) > 0 {
		s.locations = append(s.locations, location)
	}

	return location.Copy()
}

func (s *Scene) LocateAvailableDots(location Location) Location {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeLocateAvailableDots(location)
}

type ErrDelete struct {
	Err error
}

func (e *ErrDelete) Error() string {
	return "cannot delete"
}

// unsafeDelete deletes passed location from scene and returns error if there is a problem
func (s *Scene) unsafeDelete(location Location) *ErrDelete {
	for i := range s.locations {
		if s.locations[i].Equals(location) {
			s.locations = append(s.locations[:i], s.locations[i+1:]...)
			return nil
		}
	}

	return &ErrDelete{
		Err: &ErrNotLocated{
			Location: location.Copy(),
		},
	}
}

// Delete deletes passed location from scene and returns error if there is a problem
func (s *Scene) Delete(location Location) *ErrDelete {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeDelete(location)
}

type ErrRelocate struct {
	Err error
}

func (e *ErrRelocate) Error() string {
	return "cannot relocate"
}

func (s *Scene) unsafeRelocate(old, new Location) *ErrRelocate {
	if !s.unsafeLocated(old) {
		return &ErrRelocate{
			Err: &ErrNotLocated{
				Location: old.Copy(),
			},
		}
	}

	if s.unsafeLocated(new) {
		return &ErrRelocate{
			Err: &ErrLocated{
				Location: new.Copy(),
			},
		}
	}

	if err := s.unsafeDelete(old); err != nil {
		return &ErrRelocate{
			Err: err,
		}
	}

	if err := s.unsafeLocate(new); err != nil {
		return &ErrRelocate{
			Err: err,
		}
	}

	return nil
}

func (s *Scene) Relocate(old, new Location) *ErrRelocate {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeRelocate(old, new)
}

type ErrRelocateAvailableDots struct {
	Err error
}

func (e *ErrRelocateAvailableDots) Error() string {
	return "cannot relocate with available dots"
}

func (s *Scene) unsafeRelocateAvailableDots(old, new Location) (*ErrRelocateAvailableDots, Location) {
	if !s.unsafeLocated(old) {
		return &ErrRelocateAvailableDots{
			Err: &ErrNotLocated{
				Location: old.Copy(),
			},
		}, nil
	}

	if err := s.unsafeDelete(old); err != nil {
		return &ErrRelocateAvailableDots{
			Err: err,
		}, nil
	}

	dots := s.unsafeLocateAvailableDots(new)
	if len(dots) == 0 {
		return &ErrRelocateAvailableDots{
			Err: fmt.Errorf("all dots are not available"),
		}, nil
	}

	return nil, dots.Copy()
}

func (s *Scene) RelocateAvailableDots(old, new Location) (error, Location) {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeRelocateAvailableDots(old, new)
}

var FindRetriesNumber = 32

var ErrRetriesLimit = errors.New("retries limit was reached")

func (s *Scene) unsafeLocateRandomDot() (Location, error) {
	for count := 0; count < FindRetriesNumber; count++ {
		if dot := s.area.NewRandomDot(0, 0); !s.unsafeDotOccupied(dot) {
			if err := s.unsafeLocate(Location{dot}); err != nil {
				return nil, err
			}
			return Location{dot}, nil
		}
	}

	return nil, ErrRetriesLimit
}

func (s *Scene) LocateRandomDot() (Location, error) {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeLocateRandomDot()
}

func (s *Scene) unsafeLocateRandomRectTryOnce(rw, rh uint8) (Location, error) {
	if rect, err := s.area.NewRandomRect(rw, rh, 0, 0); err == nil {
		if err := s.unsafeLocate(rect.Location()); err != nil {
			return nil, err
		}
		return rect.Location(), nil
	} else {
		return nil, err
	}
}

func (s *Scene) unsafeLocateRandomRect(rw, rh uint8) (Location, error) {
	for count := 0; count < FindRetriesNumber; count++ {
		if rect, err := s.unsafeLocateRandomRectTryOnce(rw, rh); err == nil {
			return rect, nil
		}
	}

	return nil, ErrRetriesLimit
}

func (s *Scene) LocateRandomRect(rw, rh uint8) (Location, error) {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeLocateRandomRect(rw, rh)
}
<commit_msg>Create method navigate for scene<commit_after>package engine

import (
	"errors"
	"fmt"
	"sync"
)

type ErrNotLocated struct {
	Location Location
}

func (e *ErrNotLocated) Error() string {
	return "not located"
}

type ErrLocated struct {
	Location Location
}

func (e *ErrLocated) Error() string {
	return "located"
}

type ErrDotsOccupied struct {
	Dots []*Dot // List of occupied dots
}

func (e *ErrDotsOccupied) Error() string {
	return fmt.Sprintf("dots is occupied: %s", e.Dots)
}

// Scene contains locations
type Scene struct {
	area           *Area
	locations      []Location
	locationsMutex *sync.RWMutex
}

// NewScene returns new empty scene
func NewScene(area *Area) (*Scene, error) {
	return &Scene{
		area:           area,
		locations:      make([]Location, 0),
		locationsMutex: &sync.RWMutex{},
	}, nil
}

// unsafeLocated returns true if passed location is located on scene
func (s *Scene) unsafeLocated(location Location) bool {
	for i := range s.locations {
		if s.locations[i].Equals(location) {
			return true
		}
	}
	return false
}

func (s *Scene) Located(location Location) bool {
	s.locationsMutex.RLock()
	defer s.locationsMutex.RUnlock()
	return s.unsafeLocated(location)
}

// unsafeDotOccupied returns true if passed dot already used by a location on scene
func (s *Scene) unsafeDotOccupied(dot *Dot) bool {
	if s.area.Contains(dot) {
		for _, location := range s.locations {
			if location.Contains(dot) {
				return true
			}
		}
	}
	return false
}

func (s *Scene) DotOccupied(dot *Dot) bool {
	s.locationsMutex.RLock()
	defer s.locationsMutex.RUnlock()
	return s.unsafeDotOccupied(dot)
}

// unsafeGetLocationByDot returns location which contains passed dot
func (s *Scene) unsafeGetLocationByDot(dot *Dot) Location {
	if s.area.Contains(dot) {
		for _, location := range s.locations {
			if location.Contains(dot) {
				return location.Copy()
			}
		}
	}
	return nil
}

func (s *Scene) GetLocationByDot(dot *Dot) Location {
	s.locationsMutex.RLock()
	defer s.locationsMutex.RUnlock()
	return s.unsafeGetLocationByDot(dot)
}

type ErrLocate struct {
	Err error
}

func (e *ErrLocate) Error() string {
	return "cannot locate: " + e.Err.Error()
}

func (s *Scene) unsafeLocate(location Location) *ErrLocate {
	if s.unsafeLocated(location) {
		return &ErrLocate{
			Err: &ErrLocated{
				Location: location.Copy(),
			},
		}
	}

	location = location.Copy()
	occupiedDots := make([]*Dot, 0)

	// Check each dot of passed location
	for i := uint16(0); i < location.DotCount(); i++ {
		var dot = location.Dot(i)

		if s.area.Contains(dot) {
			return &ErrLocate{
				Err: &ErrAreaNotContainsDot{
					Dot: dot,
				},
			}
		}

		for i := range s.locations {
			if s.locations[i].Contains(dot) {
				occupiedDots = append(occupiedDots, dot)
				break
			}
		}
	}

	if len(occupiedDots) > 0 {
		return &ErrLocate{
			Err: &ErrDotsOccupied{
				Dots: occupiedDots,
			},
		}
	}

	// Add to location list of scene
	s.locations = append(s.locations, location)

	return nil
}

// Locate tries to create location to scene
func (s *Scene) Locate(location Location) *ErrLocate {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeLocate(location)
}

func (s *Scene) unsafeLocateAvailableDots(location Location) Location {
	if s.unsafeLocated(location) {
		return Location{}
	}

	location = location.Copy()
	locationMirror := location.Copy()

	// Check each dot of passed location
	for i := uint16(0); i < locationMirror.DotCount(); i++ {
		var dot = locationMirror.Dot(i)

		if !s.area.Contains(dot) {
			location = location.Delete(dot)
			continue
		}

		for i := range s.locations {
			if s.locations[i].Contains(dot) {
				location = location.Delete(dot)
				break
			}
		}
	}

	if len(location) > 0 {
		s.locations = append(s.locations, location)
	}

	return location.Copy()
}

func (s *Scene) LocateAvailableDots(location Location) Location {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeLocateAvailableDots(location)
}

type ErrDelete struct {
	Err error
}

func (e *ErrDelete) Error() string {
	return "cannot delete"
}

// unsafeDelete deletes passed location from scene and returns error if there is a problem
func (s *Scene) unsafeDelete(location Location) *ErrDelete {
	for i := range s.locations {
		if s.locations[i].Equals(location) {
			s.locations = append(s.locations[:i], s.locations[i+1:]...)
			return nil
		}
	}

	return &ErrDelete{
		Err: &ErrNotLocated{
			Location: location.Copy(),
		},
	}
}

// Delete deletes passed location from scene and returns error if there is a problem
func (s *Scene) Delete(location Location) *ErrDelete {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeDelete(location)
}

type ErrRelocate struct {
	Err error
}

func (e *ErrRelocate) Error() string {
	return "cannot relocate"
}

func (s *Scene) unsafeRelocate(old, new Location) *ErrRelocate {
	if !s.unsafeLocated(old) {
		return &ErrRelocate{
			Err: &ErrNotLocated{
				Location: old.Copy(),
			},
		}
	}

	if s.unsafeLocated(new) {
		return &ErrRelocate{
			Err: &ErrLocated{
				Location: new.Copy(),
			},
		}
	}

	if err := s.unsafeDelete(old); err != nil {
		return &ErrRelocate{
			Err: err,
		}
	}

	if err := s.unsafeLocate(new); err != nil {
		return &ErrRelocate{
			Err: err,
		}
	}

	return nil
}

func (s *Scene) Relocate(old, new Location) *ErrRelocate {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeRelocate(old, new)
}

type ErrRelocateAvailableDots struct {
	Err error
}

func (e *ErrRelocateAvailableDots) Error() string {
	return "cannot relocate with available dots"
}

func (s *Scene) unsafeRelocateAvailableDots(old, new Location) (*ErrRelocateAvailableDots, Location) {
	if !s.unsafeLocated(old) {
		return &ErrRelocateAvailableDots{
			Err: &ErrNotLocated{
				Location: old.Copy(),
			},
		}, nil
	}

	if err := s.unsafeDelete(old); err != nil {
		return &ErrRelocateAvailableDots{
			Err: err,
		}, nil
	}

	dots := s.unsafeLocateAvailableDots(new)
	if len(dots) == 0 {
		return &ErrRelocateAvailableDots{
			Err: fmt.Errorf("all dots are not available"),
		}, nil
	}

	return nil, dots.Copy()
}

func (s *Scene) RelocateAvailableDots(old, new Location) (error, Location) {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeRelocateAvailableDots(old, new)
}

var FindRetriesNumber = 32

var ErrRetriesLimit = errors.New("retries limit was reached")

func (s *Scene) unsafeLocateRandomDot() (Location, error) {
	for count := 0; count < FindRetriesNumber; count++ {
		if dot := s.area.NewRandomDot(0, 0); !s.unsafeDotOccupied(dot) {
			if err := s.unsafeLocate(Location{dot}); err != nil {
				return nil, err
			}
			return Location{dot}, nil
		}
	}

	return nil, ErrRetriesLimit
}

func (s *Scene) LocateRandomDot() (Location, error) {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeLocateRandomDot()
}

func (s *Scene) unsafeLocateRandomRectTryOnce(rw, rh uint8) (Location, error) {
	if rect, err := s.area.NewRandomRect(rw, rh, 0, 0); err == nil {
		if err := s.unsafeLocate(rect.Location()); err != nil {
			return nil, err
		}
		return rect.Location(), nil
	} else {
		return nil, err
	}
}

func (s *Scene) unsafeLocateRandomRect(rw, rh uint8) (Location, error) {
	for count := 0; count < FindRetriesNumber; count++ {
		if rect, err := s.unsafeLocateRandomRectTryOnce(rw, rh); err == nil {
			return rect, nil
		}
	}

	return nil, ErrRetriesLimit
}

func (s *Scene) LocateRandomRect(rw, rh uint8) (Location, error) {
	s.locationsMutex.Lock()
	defer s.locationsMutex.Unlock()
	return s.unsafeLocateRandomRect(rw, rh)
}

func (s *Scene) Navigate(dot *Dot, dir Direction, dis uint8) (*Dot, error) {
	return s.area.Navigate(dot, dir, dis)
}
<|endoftext|>


<commit_before>package kafka

type Producer interface {
	Close()
	SendBytes(message []byte, topic, key string) error
}

type ConsumerEvent struct {
	Err       error
	Message   []byte
	Offset    int64
	Partition int32
}

type ConsumerChannel interface {
	Events() <-chan *ConsumerEvent
	Close() error
}

type PartitionIndex int32
type Offset int64

type Sender interface {
	SendBytes(message []byte, topic, key string)
}

// DividePartitions - splits the number of partitions in to buckets numbering the splitBy
func DividePartitions(partitions, splitBy int) [][]int {
	buckets := make([][]int, splitBy, splitBy)

	if splitBy > partitions {
		splitBy = partitions
	}

	count := partitions / splitBy
	extra := partitions % splitBy

	for j := 0; j < splitBy; j++ {
		index := 0 + j
		bucketSize := count
		if j < extra {
			bucketSize += 1
		}

		bucket := make([]int, bucketSize, bucketSize)
		buckets[j] = bucket

		for i := 0; i < bucketSize; i++ {
			bucket[i] = index
			index += splitBy
		}
	}
	return buckets
}
<commit_msg>removed error<commit_after>package kafka

type Producer interface {
	Close()
	SendBytes(message []byte, topic, key string)
}

type ConsumerEvent struct {
	Err       error
	Message   []byte
	Offset    int64
	Partition int32
}

type ConsumerChannel interface {
	Events() <-chan *ConsumerEvent
	Close() error
}

type PartitionIndex int32
type Offset int64

type Sender interface {
	SendBytes(message []byte, topic, key string)
}

// DividePartitions - splits the number of partitions in to buckets numbering the splitBy
func DividePartitions(partitions, splitBy int) [][]int {
	buckets := make([][]int, splitBy, splitBy)

	if splitBy > partitions {
		splitBy = partitions
	}

	count := partitions / splitBy
	extra := partitions % splitBy

	for j := 0; j < splitBy; j++ {
		index := 0 + j
		bucketSize := count
		if j < extra {
			bucketSize += 1
		}

		bucket := make([]int, bucketSize, bucketSize)
		buckets[j] = bucket

		for i := 0; i < bucketSize; i++ {
			bucket[i] = index
			index += splitBy
		}
	}
	return buckets
}
<|endoftext|>


<commit_before>package users

import (
	"bytes"
	"fmt"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"reflect"
	"strings"

	"gnd.la/app"
	"gnd.la/net/httpclient"
	"gnd.la/signal"
	"gnd.la/template"
)

var (
	ImageHandler app.Handler
	ImageFetcher func(ctx *app.Context, url string) (id string, format string, err error)

	imagePrefix string
)

func userImageId(val reflect.Value) (string, string) {
	if image, _ := getUserValue(val, "Image").(string); image != "" {
		return image, getUserValue(val, "ImageFormat").(string)
	}
	for val.Kind() == reflect.Ptr {
		if val.IsNil() {
			return "", ""
		}
		val = val.Elem()
	}
	for _, v := range enabledSocialTypes() {
		fval := val.FieldByName(v.Name)
		if fval.IsValid() {
			image := fval.Elem().FieldByName("Image")
			if image.String() != "" {
				imageFormat := fval.Elem().FieldByName("ImageFormat")
				return image.String(), imageFormat.String()
			}
		}
	}
	return "", ""
}

func Image(user interface{}) (string, error) {
	if imagePrefix == "" || user == nil {
		return "", nil
	}
	val := reflect.ValueOf(user)
	if !val.IsValid() {
		return "", nil
	}
	for val.Kind() == reflect.Ptr {
		if val.IsNil() {
			return "", nil
		}
		val = val.Elem()
	}
	if val.Type() != userType {
		return "", fmt.Errorf("invalid user type %s, must be %s", val.Type(), userType)
	}
	id, format := userImageId(val)
	if id != "" {
		if format == "jpeg" {
			format = "jpg"
		}
		return imagePrefix + id + "." + format, nil
	}
	return "", nil
}

func imageHandler(ctx *app.Context) {
	if ImageHandler != nil {
		ImageHandler(ctx)
		return
	}
	id := ctx.IndexValue(0)
	format := ctx.IndexValue(1)
	if lower := strings.ToLower(format); lower != format {
		ctx.MustRedirectReverse(true, ImageHandlerName, id, lower)
		return
	}
	ctx.SetHeader("Content-Type", "image/"+format)
	bs := ctx.Blobstore()
	if err := bs.Serve(ctx, id, nil); err != nil {
		panic(err)
	}
}

func getImage(ctx *app.Context, url string) (string, string, error) {
	if ImageFetcher != nil {
		return ImageFetcher(ctx, url)
	}
	return defaultFetchImage(ctx, url)
}

func fetchImage(ctx *app.Context, url string) (string, string, string) {
	return mightFetchImage(ctx, url, "", "", "")
}

func mightFetchImage(ctx *app.Context, url string, prevId string, prevFormat string, prevURL string) (string, string, string) {
	if url == prevURL {
		return prevId, prevFormat, prevURL
	}
	if url == "" {
		if prevId != "" {
			ctx.Blobstore().Remove(prevId)
		}
		return "", "", ""
	}
	id, format, err := getImage(ctx, url)
	if err != nil {
		// Keep previous
		return prevId, prevFormat, prevURL
	}
	if prevId != "" {
		ctx.Blobstore().Remove(prevId)
	}
	return id, format, url
}

func defaultFetchImage(ctx *app.Context, url string) (string, string, error) {
	resp, err := httpclient.New(ctx).Get(url)
	if err != nil {
		return "", "", err
	}
	defer resp.Close()
	data, err := resp.ReadAll()
	if err != nil {
		return "", "", err
	}
	_, format, err := image.DecodeConfig(bytes.NewReader(data))
	if err != nil {
		return "", "", err
	}
	bs := ctx.Blobstore()
	id, err := bs.Store(data, nil)
	if err != nil {
		return "", "", err
	}
	return id, strings.ToLower(format), nil
}

func init() {
	template.AddFuncs(template.FuncMap{
		"user_image": Image,
	})
	signal.Listen(app.WILL_LISTEN, func(_ string, obj interface{}) {
		a := obj.(*app.App)
		placeholder := "0000placeholder0000"
		rev, err := a.Reverse(ImageHandlerName, placeholder, placeholder)
		if err == nil {
			if pos := strings.Index(rev, placeholder); pos >= 0 {
				imagePrefix = rev[:pos]
			}
		}
	})
}
<commit_msg>Fix panic when looking for user image<commit_after>package users

import (
	"bytes"
	"fmt"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"reflect"
	"strings"

	"gnd.la/app"
	"gnd.la/net/httpclient"
	"gnd.la/signal"
	"gnd.la/template"
)

var (
	ImageHandler app.Handler
	ImageFetcher func(ctx *app.Context, url string) (id string, format string, err error)

	imagePrefix string
)

func userImageId(val reflect.Value) (string, string) {
	if image, _ := getUserValue(val, "Image").(string); image != "" {
		return image, getUserValue(val, "ImageFormat").(string)
	}
	for val.Kind() == reflect.Ptr {
		if val.IsNil() {
			return "", ""
		}
		val = val.Elem()
	}
	for _, v := range enabledSocialTypes() {
		fval := val.FieldByName(v.Name)
		if fval.IsValid() && fval.Elem().IsValid() {
			image := fval.Elem().FieldByName("Image")
			if image.String() != "" {
				imageFormat := fval.Elem().FieldByName("ImageFormat")
				return image.String(), imageFormat.String()
			}
		}
	}
	return "", ""
}

func Image(user interface{}) (string, error) {
	if imagePrefix == "" || user == nil {
		return "", nil
	}
	val := reflect.ValueOf(user)
	if !val.IsValid() {
		return "", nil
	}
	for val.Kind() == reflect.Ptr {
		if val.IsNil() {
			return "", nil
		}
		val = val.Elem()
	}
	if val.Type() != userType {
		return "", fmt.Errorf("invalid user type %s, must be %s", val.Type(), userType)
	}
	id, format := userImageId(val)
	if id != "" {
		if format == "jpeg" {
			format = "jpg"
		}
		return imagePrefix + id + "." + format, nil
	}
	return "", nil
}

func imageHandler(ctx *app.Context) {
	if ImageHandler != nil {
		ImageHandler(ctx)
		return
	}
	id := ctx.IndexValue(0)
	format := ctx.IndexValue(1)
	if lower := strings.ToLower(format); lower != format {
		ctx.MustRedirectReverse(true, ImageHandlerName, id, lower)
		return
	}
	ctx.SetHeader("Content-Type", "image/"+format)
	bs := ctx.Blobstore()
	if err := bs.Serve(ctx, id, nil); err != nil {
		panic(err)
	}
}

func getImage(ctx *app.Context, url string) (string, string, error) {
	if ImageFetcher != nil {
		return ImageFetcher(ctx, url)
	}
	return defaultFetchImage(ctx, url)
}

func fetchImage(ctx *app.Context, url string) (string, string, string) {
	return mightFetchImage(ctx, url, "", "", "")
}

func mightFetchImage(ctx *app.Context, url string, prevId string, prevFormat string, prevURL string) (string, string, string) {
	if url == prevURL {
		return prevId, prevFormat, prevURL
	}
	if url == "" {
		if prevId != "" {
			ctx.Blobstore().Remove(prevId)
		}
		return "", "", ""
	}
	id, format, err := getImage(ctx, url)
	if err != nil {
		// Keep previous
		return prevId, prevFormat, prevURL
	}
	if prevId != "" {
		ctx.Blobstore().Remove(prevId)
	}
	return id, format, url
}

func defaultFetchImage(ctx *app.Context, url string) (string, string, error) {
	resp, err := httpclient.New(ctx).Get(url)
	if err != nil {
		return "", "", err
	}
	defer resp.Close()
	data, err := resp.ReadAll()
	if err != nil {
		return "", "", err
	}
	_, format, err := image.DecodeConfig(bytes.NewReader(data))
	if err != nil {
		return "", "", err
	}
	bs := ctx.Blobstore()
	id, err := bs.Store(data, nil)
	if err != nil {
		return "", "", err
	}
	return id, strings.ToLower(format), nil
}

func init() {
	template.AddFuncs(template.FuncMap{
		"user_image": Image,
	})
	signal.Listen(app.WILL_LISTEN, func(_ string, obj interface{}) {
		a := obj.(*app.App)
		placeholder := "0000placeholder0000"
		rev, err := a.Reverse(ImageHandlerName, placeholder, placeholder)
		if err == nil {
			if pos := strings.Index(rev, placeholder); pos >= 0 {
				imagePrefix = rev[:pos]
			}
		}
	})
}
<|endoftext|>


<commit_before>package ethpub

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethcrypto"
	"github.com/ethereum/eth-go/ethstate"
	"github.com/ethereum/eth-go/ethtrie"
	"github.com/ethereum/eth-go/ethutil"
)

// Peer interface exposed to QML

type PPeer struct {
	ref          *ethchain.Peer
	Inbound      bool   `json:"isInbound"`
	LastSend     int64  `json:"lastSend"`
	LastPong     int64  `json:"lastPong"`
	Ip           string `json:"ip"`
	Port         int    `json:"port"`
	Version      string `json:"version"`
	LastResponse string `json:"lastResponse"`
	Latency      string `json:"latency"`
}

func NewPPeer(peer ethchain.Peer) *PPeer {
	if peer == nil {
		return nil
	}

	// TODO: There must be something build in to do this?
	var ip []string
	for _, i := range peer.Host() {
		ip = append(ip, fmt.Sprintf("%d", i))
	}
	ipAddress := strings.Join(ip, ".")

	return &PPeer{ref: &peer, Inbound: peer.Inbound(), LastSend: peer.LastSend().Unix(), LastPong: peer.LastPong(), Version: peer.Version(), Ip: ipAddress, Port: int(peer.Port()), Latency: peer.PingTime()}
}

// Block interface exposed to QML
type PBlock struct {
	ref          *ethchain.Block
	Number       int    `json:"number"`
	Hash         string `json:"hash"`
	Transactions string `json:"transactions"`
	Time         int64  `json:"time"`
	Coinbase     string `json:"coinbase"`
	Name         string `json:"name"`
	GasLimit     string `json:"gasLimit"`
	GasUsed      string `json:"gasUsed"`
}

// Creates a new QML Block from a chain block
func NewPBlock(block *ethchain.Block) *PBlock {
	if block == nil {
		return nil
	}

	var ptxs []PTx
	for _, tx := range block.Transactions() {
		ptxs = append(ptxs, *NewPTx(tx))
	}

	txJson, err := json.Marshal(ptxs)
	if err != nil {
		return nil
	}

	return &PBlock{ref: block, Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)}
}

func (self *PBlock) ToString() string {
	if self.ref != nil {
		return self.ref.String()
	}

	return ""
}

func (self *PBlock) GetTransaction(hash string) *PTx {
	tx := self.ref.GetTransaction(ethutil.Hex2Bytes(hash))
	if tx == nil {
		return nil
	}

	return NewPTx(tx)
}

type PTx struct {
	ref *ethchain.Transaction

	Value           string `json:"value"`
	Gas             string `json:"gas"`
	GasPrice        string `json:"gasPrice"`
	Hash            string `json:"hash"`
	Address         string `json:"address"`
	Sender          string `json:"sender"`
	RawData         string `json:"rawData"`
	Data            string `json:"data"`
	Contract        bool   `json:"isContract"`
	CreatesContract bool   `json:"createsContract"`
	Confirmations   int    `json:"confirmations"`
}

func NewPTx(tx *ethchain.Transaction) *PTx {
	hash := ethutil.Bytes2Hex(tx.Hash())
	receiver := ethutil.Bytes2Hex(tx.Recipient)
	if receiver == "0000000000000000000000000000000000000000" {
		receiver = ethutil.Bytes2Hex(tx.CreationAddress())
	}
	sender := ethutil.Bytes2Hex(tx.Sender())
	createsContract := tx.CreatesContract()

	var data string
	if tx.CreatesContract() {
		data = strings.Join(ethchain.Disassemble(tx.Data), "\n")
	} else {
		data = ethutil.Bytes2Hex(tx.Data)
	}

	return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: tx.CreatesContract(), Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: ethutil.Bytes2Hex(tx.Data)}
}

func (self *PTx) ToString() string {
	return self.ref.String()
}

type PKey struct {
	Address    string `json:"address"`
	PrivateKey string `json:"privateKey"`
	PublicKey  string `json:"publicKey"`
}

func NewPKey(key *ethcrypto.KeyPair) *PKey {
	return &PKey{ethutil.Bytes2Hex(key.Address()), ethutil.Bytes2Hex(key.PrivateKey), ethutil.Bytes2Hex(key.PublicKey)}
}

type PReceipt struct {
	CreatedContract bool   `json:"createdContract"`
	Address         string `json:"address"`
	Hash            string `json:"hash"`
	Sender          string `json:"sender"`
}

func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *PReceipt {
	return &PReceipt{
		contractCreation,
		ethutil.Bytes2Hex(creationAddress),
		ethutil.Bytes2Hex(hash),
		ethutil.Bytes2Hex(address),
	}
}

type PStateObject struct {
	object *ethstate.StateObject
}

func NewPStateObject(object *ethstate.StateObject) *PStateObject {
	return &PStateObject{object: object}
}

func (c *PStateObject) GetStorage(address string) string {
	// Because somehow, even if you return nil to QML it
	// still has some magical object so we can't rely on
	// undefined or null at the QML side
	if c.object != nil {
		val := c.object.GetStorage(ethutil.Big("0x" + address))

		return val.BigInt().String()
	}

	return ""
}

func (c *PStateObject) Balance() string {
	if c.object != nil {
		return c.object.Balance.String()
	}

	return ""
}

func (c *PStateObject) Address() string {
	if c.object != nil {
		return ethutil.Bytes2Hex(c.object.Address())
	}

	return ""
}

func (c *PStateObject) Nonce() int {
	if c.object != nil {
		return int(c.object.Nonce)
	}

	return 0
}

func (c *PStateObject) Root() string {
	if c.object != nil {
		return ethutil.Bytes2Hex(ethutil.NewValue(c.object.State.Root()).Bytes())
	}

	return "<err>"
}

func (c *PStateObject) IsContract() bool {
	if c.object != nil {
		return len(c.object.Code) > 0
	}

	return false
}

func (self *PStateObject) EachStorage(cb ethtrie.EachCallback) {
	self.object.EachStorage(cb)
}

type KeyVal struct {
	Key   string
	Value string
}

func (c *PStateObject) StateKeyVal(asJson bool) interface{} {
	var values []KeyVal
	if c.object != nil {
		c.object.EachStorage(func(name string, value *ethutil.Value) {
			values = append(values, KeyVal{name, ethutil.Bytes2Hex(value.Bytes())})
		})
	}

	if asJson {
		valuesJson, err := json.Marshal(values)
		if err != nil {
			return nil
		}
		fmt.Println(string(valuesJson))
		return string(valuesJson)
	}

	return values
}

func (c *PStateObject) Script() string {
	if c.object != nil {
		return strings.Join(ethchain.Disassemble(c.object.Code), " ")
	}

	return ""
}

func (c *PStateObject) HexScript() string {
	if c.object != nil {
		return ethutil.Bytes2Hex(c.object.Code)
	}

	return ""
}

type PStorageState struct {
	StateAddress string
	Address      string
	Value        string
}

func NewPStorageState(storageObject *ethstate.StorageState) *PStorageState {
	return &PStorageState{ethutil.Bytes2Hex(storageObject.StateAddress), ethutil.Bytes2Hex(storageObject.Address), storageObject.Value.String()}
}
<commit_msg>Convert to hex<commit_after>package ethpub

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethcrypto"
	"github.com/ethereum/eth-go/ethstate"
	"github.com/ethereum/eth-go/ethtrie"
	"github.com/ethereum/eth-go/ethutil"
)

// Peer interface exposed to QML

type PPeer struct {
	ref          *ethchain.Peer
	Inbound      bool   `json:"isInbound"`
	LastSend     int64  `json:"lastSend"`
	LastPong     int64  `json:"lastPong"`
	Ip           string `json:"ip"`
	Port         int    `json:"port"`
	Version      string `json:"version"`
	LastResponse string `json:"lastResponse"`
	Latency      string `json:"latency"`
}

func NewPPeer(peer ethchain.Peer) *PPeer {
	if peer == nil {
		return nil
	}

	// TODO: There must be something build in to do this?
	var ip []string
	for _, i := range peer.Host() {
		ip = append(ip, fmt.Sprintf("%d", i))
	}
	ipAddress := strings.Join(ip, ".")

	return &PPeer{ref: &peer, Inbound: peer.Inbound(), LastSend: peer.LastSend().Unix(), LastPong: peer.LastPong(), Version: peer.Version(), Ip: ipAddress, Port: int(peer.Port()), Latency: peer.PingTime()}
}

// Block interface exposed to QML
type PBlock struct {
	ref          *ethchain.Block
	Number       int    `json:"number"`
	Hash         string `json:"hash"`
	Transactions string `json:"transactions"`
	Time         int64  `json:"time"`
	Coinbase     string `json:"coinbase"`
	Name         string `json:"name"`
	GasLimit     string `json:"gasLimit"`
	GasUsed      string `json:"gasUsed"`
}

// Creates a new QML Block from a chain block
func NewPBlock(block *ethchain.Block) *PBlock {
	if block == nil {
		return nil
	}

	var ptxs []PTx
	for _, tx := range block.Transactions() {
		ptxs = append(ptxs, *NewPTx(tx))
	}

	txJson, err := json.Marshal(ptxs)
	if err != nil {
		return nil
	}

	return &PBlock{ref: block, Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)}
}

func (self *PBlock) ToString() string {
	if self.ref != nil {
		return self.ref.String()
	}

	return ""
}

func (self *PBlock) GetTransaction(hash string) *PTx {
	tx := self.ref.GetTransaction(ethutil.Hex2Bytes(hash))
	if tx == nil {
		return nil
	}

	return NewPTx(tx)
}

type PTx struct {
	ref *ethchain.Transaction

	Value           string `json:"value"`
	Gas             string `json:"gas"`
	GasPrice        string `json:"gasPrice"`
	Hash            string `json:"hash"`
	Address         string `json:"address"`
	Sender          string `json:"sender"`
	RawData         string `json:"rawData"`
	Data            string `json:"data"`
	Contract        bool   `json:"isContract"`
	CreatesContract bool   `json:"createsContract"`
	Confirmations   int    `json:"confirmations"`
}

func NewPTx(tx *ethchain.Transaction) *PTx {
	hash := ethutil.Bytes2Hex(tx.Hash())
	receiver := ethutil.Bytes2Hex(tx.Recipient)
	if receiver == "0000000000000000000000000000000000000000" {
		receiver = ethutil.Bytes2Hex(tx.CreationAddress())
	}
	sender := ethutil.Bytes2Hex(tx.Sender())
	createsContract := tx.CreatesContract()

	var data string
	if tx.CreatesContract() {
		data = strings.Join(ethchain.Disassemble(tx.Data), "\n")
	} else {
		data = ethutil.Bytes2Hex(tx.Data)
	}

	return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: tx.CreatesContract(), Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: ethutil.Bytes2Hex(tx.Data)}
}

func (self *PTx) ToString() string {
	return self.ref.String()
}

type PKey struct {
	Address    string `json:"address"`
	PrivateKey string `json:"privateKey"`
	PublicKey  string `json:"publicKey"`
}

func NewPKey(key *ethcrypto.KeyPair) *PKey {
	return &PKey{ethutil.Bytes2Hex(key.Address()), ethutil.Bytes2Hex(key.PrivateKey), ethutil.Bytes2Hex(key.PublicKey)}
}

type PReceipt struct {
	CreatedContract bool   `json:"createdContract"`
	Address         string `json:"address"`
	Hash            string `json:"hash"`
	Sender          string `json:"sender"`
}

func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *PReceipt {
	return &PReceipt{
		contractCreation,
		ethutil.Bytes2Hex(creationAddress),
		ethutil.Bytes2Hex(hash),
		ethutil.Bytes2Hex(address),
	}
}

type PStateObject struct {
	object *ethstate.StateObject
}

func NewPStateObject(object *ethstate.StateObject) *PStateObject {
	return &PStateObject{object: object}
}

func (c *PStateObject) GetStorage(address string) string {
	// Because somehow, even if you return nil to QML it
	// still has some magical object so we can't rely on
	// undefined or null at the QML side
	if c.object != nil {
		val := c.object.GetStorage(ethutil.Big("0x" + address))

		return val.BigInt().String()
	}

	return ""
}

func (c *PStateObject) Balance() string {
	if c.object != nil {
		return c.object.Balance.String()
	}

	return ""
}

func (c *PStateObject) Address() string {
	if c.object != nil {
		return ethutil.Bytes2Hex(c.object.Address())
	}

	return ""
}

func (c *PStateObject) Nonce() int {
	if c.object != nil {
		return int(c.object.Nonce)
	}

	return 0
}

func (c *PStateObject) Root() string {
	if c.object != nil {
		return ethutil.Bytes2Hex(ethutil.NewValue(c.object.State.Root()).Bytes())
	}

	return "<err>"
}

func (c *PStateObject) IsContract() bool {
	if c.object != nil {
		return len(c.object.Code) > 0
	}

	return false
}

func (self *PStateObject) EachStorage(cb ethtrie.EachCallback) {
	self.object.EachStorage(cb)
}

type KeyVal struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

func (c *PStateObject) StateKeyVal(asJson bool) interface{} {
	var values []KeyVal
	if c.object != nil {
		c.object.EachStorage(func(name string, value *ethutil.Value) {
			value.Decode()
			values = append(values, KeyVal{ethutil.Bytes2Hex([]byte(name)), ethutil.Bytes2Hex(value.Bytes())})
		})
	}

	if asJson {
		valuesJson, err := json.Marshal(values)
		if err != nil {
			return nil
		}

		return string(valuesJson)
	}

	return values
}

func (c *PStateObject) Script() string {
	if c.object != nil {
		return strings.Join(ethchain.Disassemble(c.object.Code), " ")
	}

	return ""
}

func (c *PStateObject) HexScript() string {
	if c.object != nil {
		return ethutil.Bytes2Hex(c.object.Code)
	}

	return ""
}

type PStorageState struct {
	StateAddress string
	Address      string
	Value        string
}

func NewPStorageState(storageObject *ethstate.StorageState) *PStorageState {
	return &PStorageState{ethutil.Bytes2Hex(storageObject.StateAddress), ethutil.Bytes2Hex(storageObject.Address), storageObject.Value.String()}
}
<|endoftext|>


<commit_before>package etl_test

import (
	"fmt"
	"testing"

	"github.com/m-lab/etl/etl"
)

func TestValidation(t *testing.T) {
	// These should fail:
	// Leading character before gs://
	_, err := etl.ValidateTestPath(
		`xgs://m-lab-sandbox/ndt/2016/01/26/20160126T123456Z-mlab1-prg01-ndt-0007.tgz`)
	if err == nil {
		t.Error("Should be invalid: ")
	}
	// Wrong trailing characters
	_, err = etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/01/26/20160126T000000Z-mlab1-prg01-ndt-0007.gz.baz`)
	if err == nil {
		t.Error("Should be invalid: ")
	}
	// Missing mlabN-podNN
	_, err = etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/01/26/20160126T000000Z-mlab1-prg1-ndt-0007.tar.gz`)
	if err == nil {
		t.Error("Should be invalid: ")
	}

	// These should succeed
	data, err := etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/01/26/20160126T000000Z-mlab1-prg01-ndt-0007.tgz`)
	if err != nil {
		t.Error(err)
	}
	data, err = etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/07/14/20160714T123456Z-mlab1-lax04-ndt-0001.tar`)
	if err != nil {
		t.Error(err)
	}
	data, err = etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/07/14/20160714T123456Z-mlab1-lax04-ndt-0001.tar.gz`)
	if err != nil {
		t.Error(err)
	}
	fmt.Printf("%v\n", data)
}

func TestGetMetroName(t *testing.T) {
	metro_name := etl.GetMetroName("20170501T000000Z-mlab1-acc02-paris-traceroute-0000.tgz")
	if metro_name != "acc" {
		fmt.Println(metro_name)
		t.Errorf("Error in getting metro name!\n")
		return
	}
}

func TestCalculateIPDistance(t *testing.T) {
	dist1, _ := etl.CalculateIPDistance("192.168.3.4", "192.168.3.1")
	if dist1 != 29 {
		t.Errorf("Error in calculating IPv4 distance!\n")
		return
	}
	dist2, _ := etl.CalculateIPDistance("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
	if dist2 != 128 {
		fmt.Println(dist2)
		t.Errorf("Error in calculating IPv6 distance!\n")
		return
	}
}
<commit_msg>minor<commit_after>package etl_test

import (
	"fmt"
	"testing"

	"github.com/m-lab/etl/etl"
)

func TestValidation(t *testing.T) {
	// These should fail:
	// Leading character before gs://
	_, err := etl.ValidateTestPath(
		`xgs://m-lab-sandbox/ndt/2016/01/26/20160126T123456Z-mlab1-prg01-ndt-0007.tgz`)
	if err == nil {
		t.Error("Should be invalid: ")
	}
	// Wrong trailing characters
	_, err = etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/01/26/20160126T000000Z-mlab1-prg01-ndt-0007.gz.baz`)
	if err == nil {
		t.Error("Should be invalid: ")
	}
	// Missing mlabN-podNN
	_, err = etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/01/26/20160126T000000Z-mlab1-prg1-ndt-0007.tar.gz`)
	if err == nil {
		t.Error("Should be invalid: ")
	}

	// These should succeed
	data, err := etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/01/26/20160126T000000Z-mlab1-prg01-ndt-0007.tgz`)
	if err != nil {
		t.Error(err)
	}
	data, err = etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/07/14/20160714T123456Z-mlab1-lax04-ndt-0001.tar`)
	if err != nil {
		t.Error(err)
	}
	data, err = etl.ValidateTestPath(
		`gs://m-lab-sandbox/ndt/2016/07/14/20160714T123456Z-mlab1-lax04-ndt-0001.tar.gz`)
	if err != nil {
		t.Error(err)
	}
	fmt.Printf("%v\n", data)
}

func TestGetMetroName(t *testing.T) {
	metro_name := etl.GetMetroName("20170501T000000Z-mlab1-acc02-paris-traceroute-0000.tgz")
	if metro_name != "acc" {
		fmt.Println(metro_name)
		t.Errorf("Error in getting metro name!\n")
		return
	}
}

func TestCalculateIPDistance(t *testing.T) {
	dist1, _ := etl.CalculateIPDistance("192.168.3.4", "192.168.3.1")
	if dist1 != 29 {
		t.Errorf("Error in calculating IPv4 distance!\n")
		return
	}
	dist2, _ := etl.CalculateIPDistance("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
	if dist2 != 128 {
		t.Errorf("Error in calculating IPv6 distance!\n")
		return
	}
}
<|endoftext|>


<commit_before>package event

import "github.com/concourse/atc"

type Error struct {
	Message string `json:"message"`
	Origin  Origin `json:"origin,omitempty"`
}

func (Error) EventType() atc.EventType  { return EventTypeError }
func (Error) Version() atc.EventVersion { return "4.0" }

type FinishTask struct {
	Time       int64  `json:"time"`
	ExitStatus int    `json:"exit_status"`
	Origin     Origin `json:"origin"`
}

func (FinishTask) EventType() atc.EventType  { return EventTypeFinishTask }
func (FinishTask) Version() atc.EventVersion { return "4.0" }

type InitializeTask struct {
	TaskConfig TaskConfig `json:"config"`
	Origin     Origin     `json:"origin"`
}

func (InitializeTask) EventType() atc.EventType  { return EventTypeInitializeTask }
func (InitializeTask) Version() atc.EventVersion { return "4.0" }

// shadow the real atc.TaskConfig
type TaskConfig struct {
	Platform string `json:"platform"`
	Image    string `json:"image"`

	Run    TaskRunConfig     `json:"run"`
	Inputs []TaskInputConfig `json:"inputs"`
}

type TaskRunConfig struct {
	Path string   `json:"path"`
	Args []string `json:"args"`
}

type TaskInputConfig struct {
	Name string `json:"name"`
	Path string `json:"path"`
}

func ShadowTaskConfig(config atc.TaskConfig) TaskConfig {
	var inputConfigs []TaskInputConfig

	for _, input := range config.Inputs {
		inputConfigs = append(inputConfigs, TaskInputConfig{
			Name: input.Name,
			Path: input.Path,
		})
	}

	return TaskConfig{
		Platform: config.Platform,
		Image:    config.Image,
		Run: TaskRunConfig{
			Path: config.Run.Path,
			Args: config.Run.Args,
		},
		Inputs: inputConfigs,
	}
}

type StartTask struct {
	Time   int64  `json:"time"`
	Origin Origin `json:"origin"`
}

func (StartTask) EventType() atc.EventType  { return EventTypeStartTask }
func (StartTask) Version() atc.EventVersion { return "4.0" }

type Status struct {
	Status atc.BuildStatus `json:"status"`
	Time   int64           `json:"time"`
}

func (Status) EventType() atc.EventType  { return EventTypeStatus }
func (Status) Version() atc.EventVersion { return "1.0" }

type Log struct {
	Origin  Origin `json:"origin"`
	Payload string `json:"payload"`
}

func (Log) EventType() atc.EventType  { return EventTypeLog }
func (Log) Version() atc.EventVersion { return "5.0" }

type Origin struct {
	ID     OriginID     `json:"id"`
	Source OriginSource `json:"source,omitempty"`
}

type OriginID string

type OriginSource string

const (
	OriginSourceStdout OriginSource = "stdout"
	OriginSourceStderr OriginSource = "stderr"
)

type FinishGet struct {
	Origin          Origin              `json:"origin"`
	Plan            GetPlan             `json:"plan"`
	ExitStatus      int                 `json:"exit_status"`
	FetchedVersion  atc.Version         `json:"version"`
	FetchedMetadata []atc.MetadataField `json:"metadata,omitempty"`
}

func (FinishGet) EventType() atc.EventType  { return EventTypeFinishGet }
func (FinishGet) Version() atc.EventVersion { return "4.0" }

type GetPlan struct {
	Name     string      `json:"name"`
	Resource string      `json:"resource"`
	Type     string      `json:"type"`
	Version  atc.Version `json:"version"`
}

type FinishPut struct {
	Origin          Origin              `json:"origin"`
	Plan            PutPlan             `json:"plan"`
	CreatedVersion  atc.Version         `json:"version"`
	CreatedMetadata []atc.MetadataField `json:"metadata,omitempty"`
	ExitStatus      int                 `json:"exit_status"`
}

func (FinishPut) EventType() atc.EventType  { return EventTypeFinishPut }
func (FinishPut) Version() atc.EventVersion { return "4.0" }

type PutPlan struct {
	Name     string `json:"name"`
	Resource string `json:"resource"`
	Type     string `json:"type"`
}
<commit_msg>omit origin ID if empty<commit_after>package event

import "github.com/concourse/atc"

type Error struct {
	Message string `json:"message"`
	Origin  Origin `json:"origin,omitempty"`
}

func (Error) EventType() atc.EventType  { return EventTypeError }
func (Error) Version() atc.EventVersion { return "4.0" }

type FinishTask struct {
	Time       int64  `json:"time"`
	ExitStatus int    `json:"exit_status"`
	Origin     Origin `json:"origin"`
}

func (FinishTask) EventType() atc.EventType  { return EventTypeFinishTask }
func (FinishTask) Version() atc.EventVersion { return "4.0" }

type InitializeTask struct {
	TaskConfig TaskConfig `json:"config"`
	Origin     Origin     `json:"origin"`
}

func (InitializeTask) EventType() atc.EventType  { return EventTypeInitializeTask }
func (InitializeTask) Version() atc.EventVersion { return "4.0" }

// shadow the real atc.TaskConfig
type TaskConfig struct {
	Platform string `json:"platform"`
	Image    string `json:"image"`

	Run    TaskRunConfig     `json:"run"`
	Inputs []TaskInputConfig `json:"inputs"`
}

type TaskRunConfig struct {
	Path string   `json:"path"`
	Args []string `json:"args"`
}

type TaskInputConfig struct {
	Name string `json:"name"`
	Path string `json:"path"`
}

func ShadowTaskConfig(config atc.TaskConfig) TaskConfig {
	var inputConfigs []TaskInputConfig

	for _, input := range config.Inputs {
		inputConfigs = append(inputConfigs, TaskInputConfig{
			Name: input.Name,
			Path: input.Path,
		})
	}

	return TaskConfig{
		Platform: config.Platform,
		Image:    config.Image,
		Run: TaskRunConfig{
			Path: config.Run.Path,
			Args: config.Run.Args,
		},
		Inputs: inputConfigs,
	}
}

type StartTask struct {
	Time   int64  `json:"time"`
	Origin Origin `json:"origin"`
}

func (StartTask) EventType() atc.EventType  { return EventTypeStartTask }
func (StartTask) Version() atc.EventVersion { return "4.0" }

type Status struct {
	Status atc.BuildStatus `json:"status"`
	Time   int64           `json:"time"`
}

func (Status) EventType() atc.EventType  { return EventTypeStatus }
func (Status) Version() atc.EventVersion { return "1.0" }

type Log struct {
	Origin  Origin `json:"origin"`
	Payload string `json:"payload"`
}

func (Log) EventType() atc.EventType  { return EventTypeLog }
func (Log) Version() atc.EventVersion { return "5.0" }

type Origin struct {
	ID     OriginID     `json:"id,omitempty"`
	Source OriginSource `json:"source,omitempty"`
}

type OriginID string

type OriginSource string

const (
	OriginSourceStdout OriginSource = "stdout"
	OriginSourceStderr OriginSource = "stderr"
)

type FinishGet struct {
	Origin          Origin              `json:"origin"`
	Plan            GetPlan             `json:"plan"`
	ExitStatus      int                 `json:"exit_status"`
	FetchedVersion  atc.Version         `json:"version"`
	FetchedMetadata []atc.MetadataField `json:"metadata,omitempty"`
}

func (FinishGet) EventType() atc.EventType  { return EventTypeFinishGet }
func (FinishGet) Version() atc.EventVersion { return "4.0" }

type GetPlan struct {
	Name     string      `json:"name"`
	Resource string      `json:"resource"`
	Type     string      `json:"type"`
	Version  atc.Version `json:"version"`
}

type FinishPut struct {
	Origin          Origin              `json:"origin"`
	Plan            PutPlan             `json:"plan"`
	CreatedVersion  atc.Version         `json:"version"`
	CreatedMetadata []atc.MetadataField `json:"metadata,omitempty"`
	ExitStatus      int                 `json:"exit_status"`
}

func (FinishPut) EventType() atc.EventType  { return EventTypeFinishPut }
func (FinishPut) Version() atc.EventVersion { return "4.0" }

type PutPlan struct {
	Name     string `json:"name"`
	Resource string `json:"resource"`
	Type     string `json:"type"`
}
<|endoftext|>


<commit_before>package kitsu

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/nstratos/go-kitsu/kitsu/internal/jsonapi"
)

const (
	defaultBaseURL    = "https://kitsu.io/"
	defaultAPIVersion = "api/edge/"

	defaultMediaType = "application/vnd.api+json"
)

// Client manages communication with the kitsu.io API.
type Client struct {
	client *http.Client

	BaseURL *url.URL

	common service

	Anime   *AnimeService
	User    *UserService
	Library *LibraryService
}

type service struct {
	client *Client
}

// NewClient returns a new kitsu.io API client.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{client: httpClient, BaseURL: baseURL}

	c.common.client = c

	c.Anime = (*AnimeService)(&c.common)
	c.User = (*UserService)(&c.common)
	c.Library = (*LibraryService)(&c.common)

	return c
}

// URLOption allows to specify URL parameters to the Kitsu API to change the
// data that will be retrieved.
type URLOption func(v *url.Values)

// Pagination allows to choose how many pages of a resource to receive by
// specifying pagination parameters limit and offset. Resources are paginated
// by default.
func Pagination(limit, offset int) URLOption {
	return func(v *url.Values) {
		v.Set("page[limit]", strconv.Itoa(limit))
		v.Set("page[offset]", strconv.Itoa(offset))
	}
}

// Limit allows to control the number of results that will be retrieved. It can
// be used together with Offset to control the pagination results. Results have
// a default limit.
func Limit(limit int) URLOption {
	return func(v *url.Values) {
		v.Set("page[limit]", strconv.Itoa(limit))
	}
}

// Offset is meant to be used together with Limit and allows to control the
// offset of the pagination.
func Offset(offset int) URLOption {
	return func(v *url.Values) {
		v.Set("page[offset]", strconv.Itoa(offset))
	}
}

// Filter allows to query data that contains certain matching attributes or
// relationships. For example, to retrieve all the anime of the Action genre,
// "genres" can be passed as the attribute and "action" as one of the values
// like so:
//
//     Filter("genres", "action").
//
// More than one values can be provided to be filtered:
//
//     Filter("genres", "action", "drama").
//
// Some resources support additional filters.
//
// Anime: text, season, streamers
//
// Manga: text
//
// Drama: text
//
// LibraryEntry: userId
func Filter(attribute string, values ...string) URLOption {
	return func(v *url.Values) {
		v.Set(fmt.Sprintf("filter[%s]", attribute), strings.Join(values, ","))
	}
}

// Search can be passed as an option and allows to search for media based on
// query text.
//
// Search can only be used for media such as Anime and Manga. Passing the
// search option to one of the User methods will return an error. Alternatively
// the Filter option with the "name" attribute could be used instead.
func Search(query string) URLOption {
	return func(v *url.Values) {
		v.Set("filter[text]", query)
	}
}

// Sort can be specified to provide sorting for one or more attributes. By default, sorts are applied in ascending order.
// For descending order a - can be prepended to the sort parameter (e.g.
// -averageRating for Anime).
//
// For example to sort by the attribute "averageRating" of Anime:
//
//    Sort("averageRating")
//
// And for descending order:
//
//    Sort("-averageRating")
//
// Many sort parameters can be specified:
//
//    Sort("followersCount", "-followingCount")
//
func Sort(attributes ...string) URLOption {
	return func(v *url.Values) {
		v.Set("sort", strings.Join(attributes, ","))
	}
}

// Include allows to include one or more related resources by specifying the
// relationships and successive relationships using a dot notation. For example
// for Anime to also include Casting:
//
//    Include("castings")
//
// If Casting is needed to also include Person and Character:
//
//    Include("castings.character", "castings.person"),
//
func Include(relationships ...string) URLOption {
	return func(v *url.Values) {
		v.Set("include", strings.Join(relationships, ","))
	}
}

// NewRequest creates an API request. If a relative URL is provided in urlStr,
// it will be resolved relative to the BaseURL of the Client. Relative URLs
// should always be specified without a preceding slash. If body is specified,
// it will be encoded to JSON and used as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}, opts ...URLOption) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	v := rel.Query()
	if opts != nil {
		for _, opt := range opts {
			if opt != nil { // Avoid panic in case the user passes a nil option.
				opt(&v)
			}
		}
	}
	rel.RawQuery = v.Encode()

	var buf io.ReadWriter
	if body != nil {
		buf = new(bytes.Buffer)
		if err := encode(buf, body); err != nil {
			return nil, err
		}
	}

	u := c.BaseURL.ResolveReference(rel)

	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, err
	}

	if body != nil {
		req.Header.Set("Content-type", defaultMediaType)
	}
	req.Header.Set("Accept", defaultMediaType)

	return req, nil
}

func encode(w io.Writer, v interface{}) error {
	switch v := v.(type) {
	default:
		return fmt.Errorf("cannot encode unknown type %T", v)
	case *Anime, *User, *LibraryEntry:
		return jsonapi.EncodeOne(w, v)
	case []*Anime, []*User, []*LibraryEntry:
		return jsonapi.EncodeMany(w, v)
	}
}

// Response is a Kitsu API response. It wraps the standard http.Response
// returned from the request and provides access to pagination offsets for
// responses that return many results.
type Response struct {
	*http.Response

	Offset PageOffset
}

// PageOffset holds the offset values for each pagination link that is returned
// in the JSON API document. It is contained in the Response that is returned
// from each method of the API. A common usage is to use the Next value
// together with the Pagination option to access the next page of results.
type PageOffset struct {
	Next, Prev, First, Last int
}

func makePageOffset(o jsonapi.Offset) PageOffset {
	return PageOffset{
		First: o.First,
		Next:  o.Next,
		Last:  o.Last,
		Prev:  o.Prev,
	}
}

func newResponse(r *http.Response) *Response {
	return &Response{Response: r}
}

func (c *Client) Do(req *http.Request) (*Response, error) {

	dumpRequest(req, true)

	resp, err := c.client.Do(req)
	dumpResponse(resp, true)
	if err != nil {
		return nil, err
	}

	return newResponse(resp), checkResponse(resp)
}

// Do sends an API request and returns the API response for resources that
// return one result. If an API error has occurred both the response and the
// error will be returned in case the caller wishes to inspect the response
// further. If v is passed as an argument, then the API response is JSON
// decoded and stored to v.
func (c *Client) DoOne(req *http.Request, v interface{}) (*Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	err = checkResponse(resp)
	if err != nil {
		return newResponse(resp), err
	}

	if v != nil {
		err = jsonapi.DecodeOne(resp.Body, v)
	}
	return newResponse(resp), err
}

// DoMany sends an API request and returns the API response for resources that
// return many results. If an API error has occurred both the response and the
// error will be returned in case the caller wishes to inspect the response
// further. The type t of the results has to be provided. The response contains
// offset values to aid with pagination.
func (c *Client) DoMany(req *http.Request, t reflect.Type) ([]interface{}, *Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, nil, err
	}

	defer resp.Body.Close()

	err = checkResponse(resp)
	if err != nil {
		return nil, newResponse(resp), err
	}

	v, o, err := jsonapi.DecodeMany(resp.Body, t)
	response := &Response{
		Response: resp,
		Offset:   makePageOffset(o),
	}
	return v, response, err
}

// ErrorResponse reports one or more errors caused by an API request.
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Errors   []Error        `json:"errors"`
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %+v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Errors)
}

// Error holds the details of each invidivual error in an ErrorResponse.
//
// JSON API docs: http://jsonapi.org/format/#error-objects
type Error struct {
	Title  string `json:"title"`
	Detail string `json:"detail"`
	Code   string `json:"code"`
	Status string `json:"status"`
}

func (e *Error) Error() string {
	return fmt.Sprintf("%v: error %v: %v(%v)",
		e.Status, e.Code, e.Title, e.Detail)
}

// checkResponse checks the API response for errors and returns them if
// present. A response is considered an error if it has a status code outside
// the 200 range.
//
// API error responses are expected to have either no response body, or a JSON
// response body that maps to ErrorResponse. Any other response body will be
// silently ignored.
func checkResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	errorResponse := &ErrorResponse{Response: r}
	body, err := ioutil.ReadAll(r.Body)
	if err == nil && body != nil {
		json.Unmarshal(body, errorResponse)
	}
	return errorResponse
}
<commit_msg>Add documentation for Do method<commit_after>package kitsu

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/nstratos/go-kitsu/kitsu/internal/jsonapi"
)

const (
	defaultBaseURL    = "https://kitsu.io/"
	defaultAPIVersion = "api/edge/"

	defaultMediaType = "application/vnd.api+json"
)

// Client manages communication with the kitsu.io API.
type Client struct {
	client *http.Client

	BaseURL *url.URL

	common service

	Anime   *AnimeService
	User    *UserService
	Library *LibraryService
}

type service struct {
	client *Client
}

// NewClient returns a new kitsu.io API client.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{client: httpClient, BaseURL: baseURL}

	c.common.client = c

	c.Anime = (*AnimeService)(&c.common)
	c.User = (*UserService)(&c.common)
	c.Library = (*LibraryService)(&c.common)

	return c
}

// URLOption allows to specify URL parameters to the Kitsu API to change the
// data that will be retrieved.
type URLOption func(v *url.Values)

// Pagination allows to choose how many pages of a resource to receive by
// specifying pagination parameters limit and offset. Resources are paginated
// by default.
func Pagination(limit, offset int) URLOption {
	return func(v *url.Values) {
		v.Set("page[limit]", strconv.Itoa(limit))
		v.Set("page[offset]", strconv.Itoa(offset))
	}
}

// Limit allows to control the number of results that will be retrieved. It can
// be used together with Offset to control the pagination results. Results have
// a default limit.
func Limit(limit int) URLOption {
	return func(v *url.Values) {
		v.Set("page[limit]", strconv.Itoa(limit))
	}
}

// Offset is meant to be used together with Limit and allows to control the
// offset of the pagination.
func Offset(offset int) URLOption {
	return func(v *url.Values) {
		v.Set("page[offset]", strconv.Itoa(offset))
	}
}

// Filter allows to query data that contains certain matching attributes or
// relationships. For example, to retrieve all the anime of the Action genre,
// "genres" can be passed as the attribute and "action" as one of the values
// like so:
//
//     Filter("genres", "action").
//
// More than one values can be provided to be filtered:
//
//     Filter("genres", "action", "drama").
//
// Some resources support additional filters.
//
// Anime: text, season, streamers
//
// Manga: text
//
// Drama: text
//
// LibraryEntry: userId
func Filter(attribute string, values ...string) URLOption {
	return func(v *url.Values) {
		v.Set(fmt.Sprintf("filter[%s]", attribute), strings.Join(values, ","))
	}
}

// Search can be passed as an option and allows to search for media based on
// query text.
//
// Search can only be used for media such as Anime and Manga. Passing the
// search option to one of the User methods will return an error. Alternatively
// the Filter option with the "name" attribute could be used instead.
func Search(query string) URLOption {
	return func(v *url.Values) {
		v.Set("filter[text]", query)
	}
}

// Sort can be specified to provide sorting for one or more attributes. By default, sorts are applied in ascending order.
// For descending order a - can be prepended to the sort parameter (e.g.
// -averageRating for Anime).
//
// For example to sort by the attribute "averageRating" of Anime:
//
//    Sort("averageRating")
//
// And for descending order:
//
//    Sort("-averageRating")
//
// Many sort parameters can be specified:
//
//    Sort("followersCount", "-followingCount")
//
func Sort(attributes ...string) URLOption {
	return func(v *url.Values) {
		v.Set("sort", strings.Join(attributes, ","))
	}
}

// Include allows to include one or more related resources by specifying the
// relationships and successive relationships using a dot notation. For example
// for Anime to also include Casting:
//
//    Include("castings")
//
// If Casting is needed to also include Person and Character:
//
//    Include("castings.character", "castings.person"),
//
func Include(relationships ...string) URLOption {
	return func(v *url.Values) {
		v.Set("include", strings.Join(relationships, ","))
	}
}

// NewRequest creates an API request. If a relative URL is provided in urlStr,
// it will be resolved relative to the BaseURL of the Client. Relative URLs
// should always be specified without a preceding slash. If body is specified,
// it will be encoded to JSON and used as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}, opts ...URLOption) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	v := rel.Query()
	if opts != nil {
		for _, opt := range opts {
			if opt != nil { // Avoid panic in case the user passes a nil option.
				opt(&v)
			}
		}
	}
	rel.RawQuery = v.Encode()

	var buf io.ReadWriter
	if body != nil {
		buf = new(bytes.Buffer)
		if err := encode(buf, body); err != nil {
			return nil, err
		}
	}

	u := c.BaseURL.ResolveReference(rel)

	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, err
	}

	if body != nil {
		req.Header.Set("Content-type", defaultMediaType)
	}
	req.Header.Set("Accept", defaultMediaType)

	return req, nil
}

func encode(w io.Writer, v interface{}) error {
	switch v := v.(type) {
	default:
		return fmt.Errorf("cannot encode unknown type %T", v)
	case *Anime, *User, *LibraryEntry:
		return jsonapi.EncodeOne(w, v)
	case []*Anime, []*User, []*LibraryEntry:
		return jsonapi.EncodeMany(w, v)
	}
}

// Response is a Kitsu API response. It wraps the standard http.Response
// returned from the request and provides access to pagination offsets for
// responses that return many results.
type Response struct {
	*http.Response

	Offset PageOffset
}

// PageOffset holds the offset values for each pagination link that is returned
// in the JSON API document. It is contained in the Response that is returned
// from each method of the API. A common usage is to use the Next value
// together with the Pagination option to access the next page of results.
type PageOffset struct {
	Next, Prev, First, Last int
}

func makePageOffset(o jsonapi.Offset) PageOffset {
	return PageOffset{
		First: o.First,
		Next:  o.Next,
		Last:  o.Last,
		Prev:  o.Prev,
	}
}

func newResponse(r *http.Response) *Response {
	return &Response{Response: r}
}

// Do sends an API request and returns the API response. If an API error has
// occurred both the response and the error will be returned in case the caller
// wishes to inspect the response further.
//
// The caller of is responsibile for closing the response body.
func (c *Client) Do(req *http.Request) (*Response, error) {

	dumpRequest(req, true)

	resp, err := c.client.Do(req)
	dumpResponse(resp, true)
	if err != nil {
		return nil, err
	}

	return newResponse(resp), checkResponse(resp)
}

// DoOne sends an API request and returns the API response for resources that
// return one result. If an API error has occurred both the response and the
// error will be returned in case the caller wishes to inspect the response
// further. If v is passed as an argument, then the API response is JSON
// decoded and stored to v.
func (c *Client) DoOne(req *http.Request, v interface{}) (*Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	err = checkResponse(resp)
	if err != nil {
		return newResponse(resp), err
	}

	if v != nil {
		err = jsonapi.DecodeOne(resp.Body, v)
	}
	return newResponse(resp), err
}

// DoMany sends an API request and returns the API response for resources that
// return many results. If an API error has occurred both the response and the
// error will be returned in case the caller wishes to inspect the response
// further. The type t of the results has to be provided. The response contains
// offset values to aid with pagination.
func (c *Client) DoMany(req *http.Request, t reflect.Type) ([]interface{}, *Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, nil, err
	}

	defer resp.Body.Close()

	err = checkResponse(resp)
	if err != nil {
		return nil, newResponse(resp), err
	}

	v, o, err := jsonapi.DecodeMany(resp.Body, t)
	response := &Response{
		Response: resp,
		Offset:   makePageOffset(o),
	}
	return v, response, err
}

// ErrorResponse reports one or more errors caused by an API request.
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Errors   []Error        `json:"errors"`
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %+v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Errors)
}

// Error holds the details of each invidivual error in an ErrorResponse.
//
// JSON API docs: http://jsonapi.org/format/#error-objects
type Error struct {
	Title  string `json:"title"`
	Detail string `json:"detail"`
	Code   string `json:"code"`
	Status string `json:"status"`
}

func (e *Error) Error() string {
	return fmt.Sprintf("%v: error %v: %v(%v)",
		e.Status, e.Code, e.Title, e.Detail)
}

// checkResponse checks the API response for errors and returns them if
// present. A response is considered an error if it has a status code outside
// the 200 range.
//
// API error responses are expected to have either no response body, or a JSON
// response body that maps to ErrorResponse. Any other response body will be
// silently ignored.
func checkResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	errorResponse := &ErrorResponse{Response: r}
	body, err := ioutil.ReadAll(r.Body)
	if err == nil && body != nil {
		json.Unmarshal(body, errorResponse)
	}
	return errorResponse
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"time"

	"github.com/getlantern/systray"
	"github.com/getlantern/systray/example/icon"
)

func main() {
	onExit := func() {
		fmt.Println("Starting onExit")
		now := time.Now()
		ioutil.WriteFile(fmt.Sprintf(`on_exit_%d.txt`, now.UnixNano()), []byte(now.String()), 0644)
		fmt.Println("Finished onExit")
	}
	// Should be called at the very beginning of main().
	systray.RunWithAppWindow("Lantern", 1024, 768, onReady, onExit)
}

func onReady() {
	systray.SetIcon(icon.Data)
	systray.SetTitle("Awesome App")
	systray.SetTooltip("Lantern")
	mQuitOrig := systray.AddMenuItem("Quit", "Quit the whole app")
	go func() {
		<-mQuitOrig.ClickedCh
		fmt.Println("Requesting quit")
		systray.Quit()
		fmt.Println("Finished quitting")
	}()

	// We can manipulate the systray in other goroutines
	go func() {
		systray.SetIcon(icon.Data)
		systray.SetTitle("Awesome App")
		systray.SetTooltip("Pretty awesome棒棒嗒")
		mChange := systray.AddMenuItem("Change Me", "Change Me")
		mChecked := systray.AddMenuItem("Unchecked", "Check Me")
		mEnabled := systray.AddMenuItem("Enabled", "Enabled")
		systray.AddMenuItem("Ignored", "Ignored")

		subMenuTop := systray.AddMenuItem("SubMenu", "SubMenu Test (top)")
		subMenuMiddle := subMenuTop.AddSubMenuItem("SubMenu - Level 2", "SubMenu Test (middle")
		subMenuMiddle.AddSubMenuItem("SubMenu - Level 3", "SubMenu Test (bottom)")
		subMenuBottom2 := subMenuMiddle.AddSubMenuItem("Panic!", "SubMenu Test (bottom)")

		mUrl := systray.AddMenuItem("Open UI", "my home")
		mQuit := systray.AddMenuItem("退出", "Quit the whole app")

		// Sets the icon of a menu item. Only available on Mac.
		mQuit.SetIcon(icon.Data)

		systray.AddSeparator()
		mToggle := systray.AddMenuItem("Toggle", "Toggle the Quit button")
		shown := true
		for {
			select {
			case <-mChange.ClickedCh:
				mChange.SetTitle("I've Changed")
			case <-mChecked.ClickedCh:
				if mChecked.Checked() {
					mChecked.Uncheck()
					mChecked.SetTitle("Unchecked")
				} else {
					mChecked.Check()
					mChecked.SetTitle("Checked")
				}
			case <-mEnabled.ClickedCh:
				mEnabled.SetTitle("Disabled")
				mEnabled.Disable()
			case <-mUrl.ClickedCh:
				systray.ShowAppWindow("https://www.getlantern.org")
			case <-subMenuBottom2.ClickedCh:
				panic("panic button pressed")
			case <-mToggle.ClickedCh:
				if shown {
					mQuitOrig.Hide()
					mEnabled.Hide()
					shown = false
				} else {
					mQuitOrig.Show()
					mEnabled.Show()
					shown = true
				}
			case <-mQuit.ClickedCh:
				systray.Quit()
				fmt.Println("Quit2 now...")
				return
			}
		}
	}()
}
<commit_msg>Fix missing paren in tooltip<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"time"

	"github.com/getlantern/systray"
	"github.com/getlantern/systray/example/icon"
)

func main() {
	onExit := func() {
		fmt.Println("Starting onExit")
		now := time.Now()
		ioutil.WriteFile(fmt.Sprintf(`on_exit_%d.txt`, now.UnixNano()), []byte(now.String()), 0644)
		fmt.Println("Finished onExit")
	}
	// Should be called at the very beginning of main().
	systray.RunWithAppWindow("Lantern", 1024, 768, onReady, onExit)
}

func onReady() {
	systray.SetIcon(icon.Data)
	systray.SetTitle("Awesome App")
	systray.SetTooltip("Lantern")
	mQuitOrig := systray.AddMenuItem("Quit", "Quit the whole app")
	go func() {
		<-mQuitOrig.ClickedCh
		fmt.Println("Requesting quit")
		systray.Quit()
		fmt.Println("Finished quitting")
	}()

	// We can manipulate the systray in other goroutines
	go func() {
		systray.SetIcon(icon.Data)
		systray.SetTitle("Awesome App")
		systray.SetTooltip("Pretty awesome棒棒嗒")
		mChange := systray.AddMenuItem("Change Me", "Change Me")
		mChecked := systray.AddMenuItem("Unchecked", "Check Me")
		mEnabled := systray.AddMenuItem("Enabled", "Enabled")
		systray.AddMenuItem("Ignored", "Ignored")

		subMenuTop := systray.AddMenuItem("SubMenu", "SubMenu Test (top)")
		subMenuMiddle := subMenuTop.AddSubMenuItem("SubMenu - Level 2", "SubMenu Test (middle)")
		subMenuMiddle.AddSubMenuItem("SubMenu - Level 3", "SubMenu Test (bottom)")
		subMenuBottom2 := subMenuMiddle.AddSubMenuItem("Panic!", "SubMenu Test (bottom)")

		mUrl := systray.AddMenuItem("Open UI", "my home")
		mQuit := systray.AddMenuItem("退出", "Quit the whole app")

		// Sets the icon of a menu item. Only available on Mac.
		mQuit.SetIcon(icon.Data)

		systray.AddSeparator()
		mToggle := systray.AddMenuItem("Toggle", "Toggle the Quit button")
		shown := true
		for {
			select {
			case <-mChange.ClickedCh:
				mChange.SetTitle("I've Changed")
			case <-mChecked.ClickedCh:
				if mChecked.Checked() {
					mChecked.Uncheck()
					mChecked.SetTitle("Unchecked")
				} else {
					mChecked.Check()
					mChecked.SetTitle("Checked")
				}
			case <-mEnabled.ClickedCh:
				mEnabled.SetTitle("Disabled")
				mEnabled.Disable()
			case <-mUrl.ClickedCh:
				systray.ShowAppWindow("https://www.getlantern.org")
			case <-subMenuBottom2.ClickedCh:
				panic("panic button pressed")
			case <-mToggle.ClickedCh:
				if shown {
					mQuitOrig.Hide()
					mEnabled.Hide()
					shown = false
				} else {
					mQuitOrig.Show()
					mEnabled.Show()
					shown = true
				}
			case <-mQuit.ClickedCh:
				systray.Quit()
				fmt.Println("Quit2 now...")
				return
			}
		}
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"

	line "github.com/dongri/line-bot-client"
)

var botClient *line.Client

func main() {
	channelID := os.Getenv("LINE_CHANNEL_ID")
	channelSecret := os.Getenv("LINE_CHANNEL_SECRET")
	mid := os.Getenv("LINE_MID")
	proxyURL := getProxyURL() // can set nil if not need

	botClient = line.NewClient(line.EndPoint, channelID, channelSecret, mid, proxyURL)

	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	m, err := botClient.ReceiveMessage(r.Body)
	if err != nil {
		log.Print(err)
	}
	for _, result := range m.Result {
		from := result.Content.From

		// Send Text
		text := result.Content.Text
		sentResult, err := botClient.SendText([]string{from}, text)
		if err != nil {
			log.Print(err)
		}
		if len(sentResult.Failed) == 0 {
			fmt.Fprintf(w, "Failed")
			return
		}

		// Send Sticker
		metadata := new(line.ContentMetadata)
		metadata.STKID = "2"
		metadata.STKPKGID = "1"
		metadata.STKVER = "100"
		sentResult, err = botClient.SendSticker([]string{from}, *metadata)
		if err != nil {
			log.Print(err)
		}
		if len(sentResult.Failed) == 0 {
			fmt.Fprintf(w, "Failed")
			return
		}

		// Send Image
		originalContentURL := "https://upload.wikimedia.org/wikipedia/commons/5/5e/Line_logo.png"
		previewImageURL := "http://i.imgur.com/Aaso4sY.png"
		sentResult, err = botClient.SendImage([]string{from}, originalContentURL, previewImageURL)
		if err != nil {
			log.Print(err)
		}
		if len(sentResult.Failed) == 0 {
			fmt.Fprintf(w, "Failed")
			return
		}

		// Send Video ....

	}
	fmt.Fprintf(w, "Success")
}

func getProxyURL() *url.URL {
	proxyURL, err := url.Parse(os.Getenv("PROXY_URL"))
	if err != nil {
		log.Fatal(err)
	}
	return proxyURL
}
<commit_msg>Fix example<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"

	line "github.com/dongri/line-bot-client"
)

var botClient *line.Client

func main() {
	channelID := os.Getenv("LINE_CHANNEL_ID")
	channelSecret := os.Getenv("LINE_CHANNEL_SECRET")
	mid := os.Getenv("LINE_MID")
	proxyURL := getProxyURL() // can set nil if not need

	botClient = line.NewClient(line.EndPoint, channelID, channelSecret, mid, proxyURL)

	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	m, err := botClient.ReceiveMessage(r.Body)
	if err != nil {
		log.Print(err)
	}
	for _, result := range m.Result {
		from := result.Content.From

		// Get User Profile
		fromUser, err := botClient.GetUserProfiles(from)
		if err != nil {
			log.Print(err)
		}
		displayName := fromUser.Contacts[0].DisplayName
		// Send Text
		text := result.Content.Text
		sentResult, err := botClient.SendText([]string{from}, text+"\n\nBy "+displayName)
		if err != nil {
			log.Print(err)
		}
		if len(sentResult.Failed) == 0 {
			fmt.Fprintf(w, "Failed")
			return
		}

		// Send Sticker
		metadata := new(line.ContentMetadata)
		metadata.STKID = "2"
		metadata.STKPKGID = "1"
		metadata.STKVER = "100"
		sentResult, err = botClient.SendSticker([]string{from}, *metadata)
		if err != nil {
			log.Print(err)
		}
		if len(sentResult.Failed) == 0 {
			fmt.Fprintf(w, "Failed")
			return
		}

		// Send Image
		originalContentURL := "https://upload.wikimedia.org/wikipedia/commons/5/5e/Line_logo.png"
		previewImageURL := "http://i.imgur.com/Aaso4sY.png"
		sentResult, err = botClient.SendImage([]string{from}, originalContentURL, previewImageURL)
		if err != nil {
			log.Print(err)
		}
		if len(sentResult.Failed) == 0 {
			fmt.Fprintf(w, "Failed")
			return
		}

		// Send Video ....

	}
	fmt.Fprintf(w, "Success")
}

func getProxyURL() *url.URL {
	proxyURL, err := url.Parse(os.Getenv("PROXY_URL"))
	if err != nil {
		log.Fatal(err)
	}
	return proxyURL
}
<|endoftext|>


<commit_before>// +build darwin linux

package main

import (
	"github.com/pankona/gomo-simra/example/scene"
	"github.com/pankona/gomo-simra/peer"
	"github.com/pankona/gomo-simra/simra"
)

func eventHandle(onStart, onStop chan bool) {
	for {
		select {
		case <-onStart:
			peer.LogDebug("receive chan. onStart")
			engine := simra.GetInstance()
			engine.SetScene(&scene.Title{})
		case <-onStop:
			peer.LogDebug("receive chan. onStop")
		}
	}
}

func main() {
	peer.LogDebug("[IN]")
	engine := simra.GetInstance()

	onStart := make(chan bool)
	onStop := make(chan bool)
	go eventHandle(onStart, onStop)
	engine.Start(onStart, onStop)
	peer.LogDebug("[OUT]")
}
<commit_msg>insert TODO comment.<commit_after>// +build darwin linux

package main

import (
	"github.com/pankona/gomo-simra/example/scene"
	"github.com/pankona/gomo-simra/peer"
	"github.com/pankona/gomo-simra/simra"
)

func eventHandle(onStart, onStop chan bool) {
	for {
		select {
		case <-onStart:
			peer.LogDebug("receive chan. onStart")
			engine := simra.GetInstance()
			// TODO: this will be called on rotation.
			// to keep state on rotation, SetScene must not call
			// every onStart.
			engine.SetScene(&scene.Title{})
		case <-onStop:
			peer.LogDebug("receive chan. onStop")
		}
	}
}

func main() {
	peer.LogDebug("[IN]")
	engine := simra.GetInstance()

	onStart := make(chan bool)
	onStop := make(chan bool)
	go eventHandle(onStart, onStop)
	engine.Start(onStart, onStop)
	peer.LogDebug("[OUT]")
}
<|endoftext|>


<commit_before>// +Build ignore
package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"os"
	"reflect"
	"strings"

	"github.com/CloudyKit/jet"
)

var views = jet.NewHTMLSet("./views")

type tTODO struct {
	Text string
	Done bool
}

type doneTODOs struct {
	list map[string]*tTODO
	keys []string
	len  int
	i    int
}

func (dt *doneTODOs) New(todos map[string]*tTODO) *doneTODOs {
	dt.len = len(todos)
	for k := range todos {
		dt.keys = append(dt.keys, k)
	}
	dt.list = todos
	return dt
}

// Range satisfies the jet.Ranger interface and only returns TODOs that are done,
// even when the list contains TODOs that not done.
func (dt *doneTODOs) Range() (reflect.Value, reflect.Value, bool) {
	//log.Printf("Range called. Current index is %v, keys are %+v, list is %+v", dt.i, dt.keys, dt.list)
	for dt.i < dt.len {
		key := dt.keys[dt.i]
		dt.i++
		if dt.list[key].Done {
			return reflect.ValueOf(key), reflect.ValueOf(dt.list[key]), (dt.i < dt.len)
		}
	}
	return reflect.Value{}, reflect.Value{}, true
}

// Render implements jet.Renderer interface
func (t *tTODO) Render(r *jet.Runtime) {
	done := "yes"
	if !t.Done {
		done = "no"
	}
	r.Write([]byte(fmt.Sprintf("TODO: %s (done: %s)", t.Text, done)))
}

func main() {
	// remove in production
	views.SetDevelopmentMode(true)

	views.AddGlobalFunc("base64", func(a jet.Arguments) reflect.Value {
		a.RequireNumOfArguments("base64", 1, 1)

		buffer := bytes.NewBuffer(nil)
		fmt.Fprint(buffer, a.Get(0))

		return reflect.ValueOf(base64.URLEncoding.EncodeToString(buffer.Bytes()))
	})
	var todos = map[string]*tTODO{
		"example-todo-1": &tTODO{Text: "Add an show todo page to the example project", Done: true},
		"example-todo-2": &tTODO{Text: "Add an add todo page to the example project"},
		"example-todo-3": &tTODO{Text: "Add an update todo page to the example project"},
		"example-todo-4": &tTODO{Text: "Add an delete todo page to the example project", Done: true},
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		view, err := views.GetTemplate("todos/index.jet")
		if err != nil {
			log.Println("Unexpected template err:", err.Error())
		}
		view.Execute(w, nil, todos)
	})
	http.HandleFunc("/todo", func(w http.ResponseWriter, r *http.Request) {
		view, err := views.GetTemplate("todos/show.jet")
		if err != nil {
			log.Println("Unexpected template err:", err.Error())
		}
		id := r.URL.Query().Get("id")
		todo, ok := todos[id]
		if !ok {
			http.Redirect(w, r, "/", http.StatusNotFound)
		}
		view.Execute(w, nil, todo)
	})
	http.HandleFunc("/all-done", func(w http.ResponseWriter, r *http.Request) {
		view, err := views.GetTemplate("todos/index.jet")
		if err != nil {
			log.Println("Unexpected template err:", err.Error())
		}
		view.Execute(w, jet.VarMap{"showingAllDone": reflect.ValueOf(true)}, (&doneTODOs{}).New(todos))
	})

	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = ":8080"
	} else if !strings.HasPrefix(":", port) {
		port = ":" + port
	}

	log.Println("Serving on " + port)
	http.ListenAndServe(port, nil)
}
<commit_msg>Fix comment in example project<commit_after>// +Build ignore
package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"os"
	"reflect"
	"strings"

	"github.com/CloudyKit/jet"
)

var views = jet.NewHTMLSet("./views")

type tTODO struct {
	Text string
	Done bool
}

type doneTODOs struct {
	list map[string]*tTODO
	keys []string
	len  int
	i    int
}

func (dt *doneTODOs) New(todos map[string]*tTODO) *doneTODOs {
	dt.len = len(todos)
	for k := range todos {
		dt.keys = append(dt.keys, k)
	}
	dt.list = todos
	return dt
}

// Range satisfies the jet.Ranger interface and only returns TODOs that are done,
// even when the list contains TODOs that are not done.
func (dt *doneTODOs) Range() (reflect.Value, reflect.Value, bool) {
	//log.Printf("Range called. Current index is %v, keys are %+v, list is %+v", dt.i, dt.keys, dt.list)
	for dt.i < dt.len {
		key := dt.keys[dt.i]
		dt.i++
		if dt.list[key].Done {
			return reflect.ValueOf(key), reflect.ValueOf(dt.list[key]), (dt.i < dt.len)
		}
	}
	return reflect.Value{}, reflect.Value{}, true
}

// Render implements jet.Renderer interface
func (t *tTODO) Render(r *jet.Runtime) {
	done := "yes"
	if !t.Done {
		done = "no"
	}
	r.Write([]byte(fmt.Sprintf("TODO: %s (done: %s)", t.Text, done)))
}

func main() {
	// remove in production
	views.SetDevelopmentMode(true)

	views.AddGlobalFunc("base64", func(a jet.Arguments) reflect.Value {
		a.RequireNumOfArguments("base64", 1, 1)

		buffer := bytes.NewBuffer(nil)
		fmt.Fprint(buffer, a.Get(0))

		return reflect.ValueOf(base64.URLEncoding.EncodeToString(buffer.Bytes()))
	})
	var todos = map[string]*tTODO{
		"example-todo-1": &tTODO{Text: "Add an show todo page to the example project", Done: true},
		"example-todo-2": &tTODO{Text: "Add an add todo page to the example project"},
		"example-todo-3": &tTODO{Text: "Add an update todo page to the example project"},
		"example-todo-4": &tTODO{Text: "Add an delete todo page to the example project", Done: true},
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		view, err := views.GetTemplate("todos/index.jet")
		if err != nil {
			log.Println("Unexpected template err:", err.Error())
		}
		view.Execute(w, nil, todos)
	})
	http.HandleFunc("/todo", func(w http.ResponseWriter, r *http.Request) {
		view, err := views.GetTemplate("todos/show.jet")
		if err != nil {
			log.Println("Unexpected template err:", err.Error())
		}
		id := r.URL.Query().Get("id")
		todo, ok := todos[id]
		if !ok {
			http.Redirect(w, r, "/", http.StatusNotFound)
		}
		view.Execute(w, nil, todo)
	})
	http.HandleFunc("/all-done", func(w http.ResponseWriter, r *http.Request) {
		view, err := views.GetTemplate("todos/index.jet")
		if err != nil {
			log.Println("Unexpected template err:", err.Error())
		}
		view.Execute(w, jet.VarMap{"showingAllDone": reflect.ValueOf(true)}, (&doneTODOs{}).New(todos))
	})

	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = ":8080"
	} else if !strings.HasPrefix(":", port) {
		port = ":" + port
	}

	log.Println("Serving on " + port)
	http.ListenAndServe(port, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/devfeel/dotweb"
	"github.com/devfeel/dotweb/framework/exception"
	"github.com/devfeel/dotweb/session"
	"net/http"
	"strconv"
)

func main() {

	defer func() {
		var errmsg string
		if err := recover(); err != nil {
			errmsg = exception.CatchError("main", dotweb.LogTarget_HttpServer, err)
			fmt.Println("main error : ", errmsg)
		}
	}()

	//初始化DotServer
	app := dotweb.New()

	//设置dotserver日志目录
	//如果不设置，默认不启用，且默认为当前目录
	app.SetEnabledLog(true)

	//开启development模式
	app.SetProductionMode()

	//设置gzip开关
	app.HttpServer.SetEnabledGzip(true)

	//设置Session开关
	app.HttpServer.SetEnabledSession(true)

	//1.use default config
	//app.HttpServer.Features.SetEnabledCROS()
	//2.use user config
	//app.HttpServer.Features.SetEnabledCROS(true).SetOrigin("*").SetMethod("GET")

	//设置Session配置
	//runtime mode
	app.HttpServer.SetSessionConfig(session.NewDefaultRuntimeConfig())
	//redis mode
	//app.HttpServer.SetSessionConfig(session.NewDefaultRedisConfig("192.168.8.175:6379", ""))

	//设置路由
	InitRoute(app.HttpServer)

	//自定义404输出
	app.SetNotFoundHandle(func(w http.ResponseWriter, req *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("is't app's not found!"))
	})

	//设置HttpModule
	//InitModule(app)

	//启动 监控服务
	app.SetPProfConfig(true, 8081)

	//全局容器
	app.AppContext.Set("gstring", "gvalue")
	app.AppContext.Set("gint", 1)

	// 开始服务
	port := 8080
	fmt.Println("dotweb.StartServer => " + strconv.Itoa(port))
	err := app.StartServer(port)
	fmt.Println("dotweb.StartServer error => ", err)
}

func Index(ctx dotweb.Context) error {
	ctx.Response().Header().Set("Content-Type", "text/html; charset=utf-8")
	_, err := ctx.WriteStringC(201, "index => ", ctx.RemoteIP(), "我是首页")
	return err
}

func IndexReg(ctx dotweb.Context) error {
	ctx.Response().Header().Set("Content-Type", "text/html; charset=utf-8")
	_, err := ctx.WriteString("welcome to dotweb")
	return err
}

func KeyPost(ctx dotweb.Context) error {
	username1 := ctx.PostFormValue("username")
	username2 := ctx.FormValue("username")
	username3 := ctx.PostFormValue("username")
	_, err := ctx.WriteString("username:" + username1 + " - " + username2 + " - " + username3)
	return err
}

func JsonPost(ctx dotweb.Context) error {
	_, err := ctx.WriteString("body:" + string(ctx.Request().PostBody()))
	return err
}

func DefaultError(ctx dotweb.Context) error {
	//panic("my panic error!")
	i := 0
	b := 2 / i
	_, err := ctx.WriteString(b)
	return err
}

func Redirect(ctx dotweb.Context) error {
	err := ctx.Redirect(http.StatusMovedPermanently, "http://www.baidu.com")
	if err != nil {
		ctx.WriteString(err)
	}
	return err
}

func ReturnError(ctx dotweb.Context) error {
	return errors.New("return error")
}

func InitRoute(server *dotweb.HttpServer) {
	server.Router().GET("/", Index)
	server.Router().POST("/keypost", KeyPost)
	server.Router().POST("/jsonpost", JsonPost)
	server.Router().GET("/error", DefaultError)
	server.GET("/returnerr", ReturnError)
	server.Router().GET("/redirect", Redirect)
	server.Router().RegisterRoute(dotweb.RouteMethod_GET, "/index", IndexReg)
}
<commit_msg>optimized code with router.wrap implement server's gzip\session\cors in features update test code<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/devfeel/dotweb"
	"github.com/devfeel/dotweb/framework/exception"
	"github.com/devfeel/dotweb/session"
	"net/http"
	"strconv"
)

func main() {

	defer func() {
		var errmsg string
		if err := recover(); err != nil {
			errmsg = exception.CatchError("main", dotweb.LogTarget_HttpServer, err)
			fmt.Println("main error : ", errmsg)
		}
	}()

	//初始化DotServer
	app := dotweb.New()

	//设置dotserver日志目录
	//如果不设置，默认不启用，且默认为当前目录
	app.SetEnabledLog(true)

	//开启development模式
	app.SetProductionMode()

	//设置gzip开关
	app.HttpServer.SetEnabledGzip(true)

	//设置Session开关
	app.HttpServer.SetEnabledSession(true)

	//1.use default config
	//app.HttpServer.Features.SetEnabledCROS()
	//2.use user config
	//app.HttpServer.Features.SetEnabledCROS(true).SetOrigin("*").SetMethod("GET")

	//设置Session配置
	//runtime mode
	app.HttpServer.SetSessionConfig(session.NewDefaultRuntimeConfig())
	//redis mode
	//app.HttpServer.SetSessionConfig(session.NewDefaultRedisConfig("192.168.8.175:6379", ""))

	//设置路由
	InitRoute(app.HttpServer)

	//自定义404输出
	app.SetNotFoundHandle(func(w http.ResponseWriter, req *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("is't app's not found!"))
	})

	//设置HttpModule
	//InitModule(app)

	//启动 监控服务
	app.SetPProfConfig(true, 8081)

	//全局容器
	app.AppContext.Set("gstring", "gvalue")
	app.AppContext.Set("gint", 1)

	// 开始服务
	port := 8080
	fmt.Println("dotweb.StartServer => " + strconv.Itoa(port))
	err := app.StartServer(port)
	fmt.Println("dotweb.StartServer error => ", err)
}

func Index(ctx dotweb.Context) error {
	ctx.Response().Header().Set("Content-Type", "text/html; charset=utf-8")
	_, err := ctx.WriteStringC(201, "index => ", ctx.RemoteIP(), "我是首页")
	return err
}

func IndexReg(ctx dotweb.Context) error {
	ctx.Response().Header().Set("Content-Type", "text/html; charset=utf-8")
	_, err := ctx.WriteString("welcome to dotweb")
	return err
}

func IndexParam(ctx dotweb.Context) error {
	ctx.Response().Header().Set("Content-Type", "text/html; charset=utf-8")
	_, err := ctx.WriteString("IndexParam", ctx.GetRouterName("id"))
	return err
}

func KeyPost(ctx dotweb.Context) error {
	username1 := ctx.PostFormValue("username")
	username2 := ctx.FormValue("username")
	username3 := ctx.PostFormValue("username")
	_, err := ctx.WriteString("username:" + username1 + " - " + username2 + " - " + username3)
	return err
}

func JsonPost(ctx dotweb.Context) error {
	_, err := ctx.WriteString("body:" + string(ctx.Request().PostBody()))
	return err
}

func DefaultError(ctx dotweb.Context) error {
	//panic("my panic error!")
	i := 0
	b := 2 / i
	_, err := ctx.WriteString(b)
	return err
}

func Redirect(ctx dotweb.Context) error {
	err := ctx.Redirect(http.StatusMovedPermanently, "http://www.baidu.com")
	if err != nil {
		ctx.WriteString(err)
	}
	return err
}

func ReturnError(ctx dotweb.Context) error {
	return errors.New("return error")
}

func InitRoute(server *dotweb.HttpServer) {
	server.GET("/", Index)
	server.GET("/id/:id", IndexParam)
	server.POST("/keypost", KeyPost)
	server.POST("/jsonpost", JsonPost)
	server.GET("/error", DefaultError)
	server.GET("/returnerr", ReturnError)
	server.GET("/redirect", Redirect)
	server.Router().RegisterRoute(dotweb.RouteMethod_GET, "/index", IndexReg)
}
<|endoftext|>


<commit_before>package gotree_test

import (
	"github.com/DiSiqueira/gotree"
)

func ExamplePrintTree() {

	obj := gotree.ReadFolder("/Users/disiqueira/Documents/Arduino/")
	gotree.PrintTree(obj)

}<commit_msg>lower case import name<commit_after>package gotree_test

import (
	"github.com/disiqueira/gotree"
)

func ExamplePrintTree() {

	obj := gotree.ReadFolder("/Users/disiqueira/Documents/Arduino/")
	gotree.PrintTree(obj)

}<|endoftext|>


<commit_before>package shellescape_test

import (
	"fmt"
	"strings"

	"github.com/alessio/shellescape"
)

func ExampleQuote() {
	filename := "myfile; rm -rf /"
	prog := "/bin/ls"
	unescapedCommand := strings.Join([]string{prog, filename}, " ")
	escapedCommand := strings.Join([]string{prog, shellescape.Quote(filename)}, " ")

	fmt.Println(unescapedCommand)
	fmt.Println(escapedCommand)
	// Output:
	// /bin/ls myfile; rm -rf /
	// /bin/ls 'myfile; rm -rf /'
}
<commit_msg>tiny addition to code examples<commit_after>package shellescape_test

import (
	"fmt"
	"strings"

	"github.com/alessio/shellescape"
)

func ExampleQuote() {
	filename := "myfile; rm -rf /"
	prog := "/bin/ls -lh"
	unescapedCommand := strings.Join([]string{prog, filename}, " ")
	escapedCommand := strings.Join([]string{prog, shellescape.Quote(filename)}, " ")

	fmt.Println(unescapedCommand)
	fmt.Println(escapedCommand)
	fmt.Println(strings.Split(unescapedCommand," "))
	fmt.Println(strings.Split(escapedCommand," "))
	// Output:
	// /bin/ls -lh myfile; rm -rf /
	// /bin/ls -lh 'myfile; rm -rf /'
	// [/bin/ls -lh myfile; rm -rf /]
	// [/bin/ls -lh 'myfile; rm -rf /']
}
<|endoftext|>


<commit_before>package geojson_test

import (
	geojson "."
	"fmt"
)

func ExampleUnmarshalFeatureCollection() {
	rawFeatureJSON := []byte(`
		  { "type": "FeatureCollection",
		    "features": [
		      { "type": "Feature",
		        "geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
		        "properties": {"prop0": "value0"}
		      }
		    ]
		  }`)

	fc, err := geojson.UnmarshalFeatureCollection(rawFeatureJSON)
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}

	fmt.Printf("%s", fc.Features[0].Properties["prop0"])
	// Output: value0
}

func ExampleUnmarshalGeometry() {
	rawGeometryJSON := []byte(`{"type": "Point", "coordinates": [102.0, 0.5]}`)
	g, err := geojson.UnmarshalGeometry(rawGeometryJSON)
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}

	fmt.Printf("%s", g.Type)
	// Output: Point
}

func ExampleMarshalJSON() {
	fc := geojson.NewFeatureCollection()
	fc.AddFeature(geojson.NewPointFeature([]float64{1, 2}))
	rawJSON, err := fc.MarshalJSON()
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}

	fmt.Printf("%s", string(rawJSON))
	// Output: {"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[1,2]},"properties":null}]}
}
<commit_msg>Change import path to be absolute.<commit_after>package geojson_test

import (
	"fmt"

	geojson "github.com/paulmach/go.geojson"
)

func ExampleUnmarshalFeatureCollection() {
	rawFeatureJSON := []byte(`
		  { "type": "FeatureCollection",
		    "features": [
		      { "type": "Feature",
		        "geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
		        "properties": {"prop0": "value0"}
		      }
		    ]
		  }`)

	fc, err := geojson.UnmarshalFeatureCollection(rawFeatureJSON)
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}

	fmt.Printf("%s", fc.Features[0].Properties["prop0"])
	// Output: value0
}

func ExampleUnmarshalGeometry() {
	rawGeometryJSON := []byte(`{"type": "Point", "coordinates": [102.0, 0.5]}`)
	g, err := geojson.UnmarshalGeometry(rawGeometryJSON)
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}

	fmt.Printf("%s", g.Type)
	// Output: Point
}

func ExampleMarshalJSON() {
	fc := geojson.NewFeatureCollection()
	fc.AddFeature(geojson.NewPointFeature([]float64{1, 2}))
	rawJSON, err := fc.MarshalJSON()
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}

	fmt.Printf("%s", string(rawJSON))
	// Output: {"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[1,2]},"properties":null}]}
}
<|endoftext|>