<commit_before>package graphql

import (
	"context"
	"fmt"

	"github.com/graphql-go/graphql/gqlerrors"
	"github.com/graphql-go/graphql/language/parser"
	"github.com/graphql-go/graphql/language/source"
)

// SubscribeParams parameters for subscribing
type SubscribeParams struct {
	Schema        Schema
	RequestString string
	RootValue     interface{}
	// ContextValue    context.Context
	VariableValues  map[string]interface{}
	OperationName   string
	FieldResolver   FieldResolveFn
	FieldSubscriber FieldResolveFn
}

// SubscriptableSchema implements `graphql-transport-ws` `GraphQLService` interface: https://github.com/graph-gophers/graphql-transport-ws/blob/40c0484322990a129cac2f2d2763c3315230280c/graphqlws/internal/connection/connection.go#L53
// you can pass `SubscriptableSchema` to `graphql-transport-ws` `NewHandlerFunc`
type SubscriptableSchema struct {
	Schema     Schema
	RootObject map[string]interface{}
}

// Subscribe method let you use SubscriptableSchema with graphql-transport-ws https://github.com/graph-gophers/graphql-transport-ws
func (self *SubscriptableSchema) Subscribe(ctx context.Context, queryString string, operationName string, variables map[string]interface{}) (<-chan interface{}, error) {
	c := Subscribe(Params{
		Schema:         self.Schema,
		Context:        ctx,
		OperationName:  operationName,
		RequestString:  queryString,
		RootObject:     self.RootObject,
		VariableValues: variables,
	})
	to := make(chan interface{})
	go func() {
		defer close(to)
		for {
			select {
			case <-ctx.Done():
				return
			case res, more := <-c:
				if !more {
					return
				}
				to <- res
			}
		}
	}()
	return to, nil
}

// Subscribe performs a subscribe operation on the given query and schema
// To finish a subscription you can simply close the channel from inside the `Subscribe` function
// currently does not support extensions hooks
func Subscribe(p Params) chan *Result {

	source := source.NewSource(&source.Source{
		Body: []byte(p.RequestString),
		Name: "GraphQL request",
	})

	// TODO run extensions hooks

	// parse the source
	AST, err := parser.Parse(parser.ParseParams{Source: source})
	if err != nil {

		// merge the errors from extensions and the original error from parser
		return sendOneResultAndClose(&Result{
			Errors: gqlerrors.FormatErrors(err),
		})
	}

	// validate document
	validationResult := ValidateDocument(&p.Schema, AST, nil)

	if !validationResult.IsValid {
		// run validation finish functions for extensions
		return sendOneResultAndClose(&Result{
			Errors: validationResult.Errors,
		})

	}
	return ExecuteSubscription(ExecuteParams{
		Schema:        p.Schema,
		Root:          p.RootObject,
		AST:           AST,
		OperationName: p.OperationName,
		Args:          p.VariableValues,
		Context:       p.Context,
	})
}

func sendOneResultAndClose(res *Result) chan *Result {
	resultChannel := make(chan *Result, 1)
	resultChannel <- res
	close(resultChannel)
	return resultChannel
}

// ExecuteSubscription is similar to graphql.Execute but returns a channel instead of a Result
// currently does not support extensions
func ExecuteSubscription(p ExecuteParams) chan *Result {

	if p.Context == nil {
		p.Context = context.Background()
	}

	var mapSourceToResponse = func(payload interface{}) *Result {
		return Execute(ExecuteParams{
			Schema:        p.Schema,
			Root:          payload,
			AST:           p.AST,
			OperationName: p.OperationName,
			Args:          p.Args,
			Context:       p.Context,
		})
	}
	var resultChannel = make(chan *Result)
	go func() {
		defer close(resultChannel)
		defer func() {
			if err := recover(); err != nil {
				e, ok := err.(error)
				if !ok {
					fmt.Println("strange program path")
					return
				}
				resultChannel <- &Result{
					Errors: gqlerrors.FormatErrors(e),
				}
			}
			return
		}()

		exeContext, err := buildExecutionContext(buildExecutionCtxParams{
			Schema:        p.Schema,
			Root:          p.Root,
			AST:           p.AST,
			OperationName: p.OperationName,
			Args:          p.Args,
			Context:       p.Context,
		})

		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		operationType, err := getOperationRootType(p.Schema, exeContext.Operation)
		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		fields := collectFields(collectFieldsParams{
			ExeContext:   exeContext,
			RuntimeType:  operationType,
			SelectionSet: exeContext.Operation.GetSelectionSet(),
		})

		responseNames := []string{}
		for name := range fields {
			responseNames = append(responseNames, name)
		}
		responseName := responseNames[0]
		fieldNodes := fields[responseName]
		fieldNode := fieldNodes[0]
		fieldName := fieldNode.Name.Value
		fieldDef := getFieldDef(p.Schema, operationType, fieldName)

		if fieldDef == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("the subscription field %q is not defined", fieldName)),
			}

			return
		}

		resolveFn := fieldDef.Subscribe

		if resolveFn == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("the subscription function %q is not defined", fieldName)),
			}
			return
		}
		fieldPath := &ResponsePath{
			Key: responseName,
		}

		args := getArgumentValues(fieldDef.Args, fieldNode.Arguments, exeContext.VariableValues)
		info := ResolveInfo{
			FieldName:      fieldName,
			FieldASTs:      fieldNodes,
			Path:           fieldPath,
			ReturnType:     fieldDef.Type,
			ParentType:     operationType,
			Schema:         p.Schema,
			Fragments:      exeContext.Fragments,
			RootValue:      exeContext.Root,
			Operation:      exeContext.Operation,
			VariableValues: exeContext.VariableValues,
		}

		fieldResult, err := resolveFn(ResolveParams{
			Source:  p.Root,
			Args:    args,
			Info:    info,
			Context: p.Context,
		})
		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		if fieldResult == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("no field result")),
			}

			return
		}

		switch fieldResult.(type) {
		case chan interface{}:
			sub := fieldResult.(chan interface{})
			for {
				select {
				case <-p.Context.Done():
					return

				case res, more := <-sub:
					if !more {
						return
					}
					resultChannel <- mapSourceToResponse(res)
				}
			}
		default:
			resultChannel <- mapSourceToResponse(fieldResult)
			return
		}
	}()

	// return a result channel
	return resultChannel
}
<commit_msg>subscription: removed SubscriptableSchema<commit_after>package graphql

import (
	"context"
	"fmt"

	"github.com/graphql-go/graphql/gqlerrors"
	"github.com/graphql-go/graphql/language/parser"
	"github.com/graphql-go/graphql/language/source"
)

// SubscribeParams parameters for subscribing
type SubscribeParams struct {
	Schema        Schema
	RequestString string
	RootValue     interface{}
	// ContextValue    context.Context
	VariableValues  map[string]interface{}
	OperationName   string
	FieldResolver   FieldResolveFn
	FieldSubscriber FieldResolveFn
}

// Subscribe performs a subscribe operation on the given query and schema
// To finish a subscription you can simply close the channel from inside the `Subscribe` function
// currently does not support extensions hooks
func Subscribe(p Params) chan *Result {

	source := source.NewSource(&source.Source{
		Body: []byte(p.RequestString),
		Name: "GraphQL request",
	})

	// TODO run extensions hooks

	// parse the source
	AST, err := parser.Parse(parser.ParseParams{Source: source})
	if err != nil {

		// merge the errors from extensions and the original error from parser
		return sendOneResultAndClose(&Result{
			Errors: gqlerrors.FormatErrors(err),
		})
	}

	// validate document
	validationResult := ValidateDocument(&p.Schema, AST, nil)

	if !validationResult.IsValid {
		// run validation finish functions for extensions
		return sendOneResultAndClose(&Result{
			Errors: validationResult.Errors,
		})

	}
	return ExecuteSubscription(ExecuteParams{
		Schema:        p.Schema,
		Root:          p.RootObject,
		AST:           AST,
		OperationName: p.OperationName,
		Args:          p.VariableValues,
		Context:       p.Context,
	})
}

func sendOneResultAndClose(res *Result) chan *Result {
	resultChannel := make(chan *Result, 1)
	resultChannel <- res
	close(resultChannel)
	return resultChannel
}

// ExecuteSubscription is similar to graphql.Execute but returns a channel instead of a Result
// currently does not support extensions
func ExecuteSubscription(p ExecuteParams) chan *Result {

	if p.Context == nil {
		p.Context = context.Background()
	}

	var mapSourceToResponse = func(payload interface{}) *Result {
		return Execute(ExecuteParams{
			Schema:        p.Schema,
			Root:          payload,
			AST:           p.AST,
			OperationName: p.OperationName,
			Args:          p.Args,
			Context:       p.Context,
		})
	}
	var resultChannel = make(chan *Result)
	go func() {
		defer close(resultChannel)
		defer func() {
			if err := recover(); err != nil {
				e, ok := err.(error)
				if !ok {
					fmt.Println("strange program path")
					return
				}
				resultChannel <- &Result{
					Errors: gqlerrors.FormatErrors(e),
				}
			}
			return
		}()

		exeContext, err := buildExecutionContext(buildExecutionCtxParams{
			Schema:        p.Schema,
			Root:          p.Root,
			AST:           p.AST,
			OperationName: p.OperationName,
			Args:          p.Args,
			Context:       p.Context,
		})

		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		operationType, err := getOperationRootType(p.Schema, exeContext.Operation)
		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		fields := collectFields(collectFieldsParams{
			ExeContext:   exeContext,
			RuntimeType:  operationType,
			SelectionSet: exeContext.Operation.GetSelectionSet(),
		})

		responseNames := []string{}
		for name := range fields {
			responseNames = append(responseNames, name)
		}
		responseName := responseNames[0]
		fieldNodes := fields[responseName]
		fieldNode := fieldNodes[0]
		fieldName := fieldNode.Name.Value
		fieldDef := getFieldDef(p.Schema, operationType, fieldName)

		if fieldDef == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("the subscription field %q is not defined", fieldName)),
			}

			return
		}

		resolveFn := fieldDef.Subscribe

		if resolveFn == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("the subscription function %q is not defined", fieldName)),
			}
			return
		}
		fieldPath := &ResponsePath{
			Key: responseName,
		}

		args := getArgumentValues(fieldDef.Args, fieldNode.Arguments, exeContext.VariableValues)
		info := ResolveInfo{
			FieldName:      fieldName,
			FieldASTs:      fieldNodes,
			Path:           fieldPath,
			ReturnType:     fieldDef.Type,
			ParentType:     operationType,
			Schema:         p.Schema,
			Fragments:      exeContext.Fragments,
			RootValue:      exeContext.Root,
			Operation:      exeContext.Operation,
			VariableValues: exeContext.VariableValues,
		}

		fieldResult, err := resolveFn(ResolveParams{
			Source:  p.Root,
			Args:    args,
			Info:    info,
			Context: p.Context,
		})
		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		if fieldResult == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("no field result")),
			}

			return
		}

		switch fieldResult.(type) {
		case chan interface{}:
			sub := fieldResult.(chan interface{})
			for {
				select {
				case <-p.Context.Done():
					return

				case res, more := <-sub:
					if !more {
						return
					}
					resultChannel <- mapSourceToResponse(res)
				}
			}
		default:
			resultChannel <- mapSourceToResponse(fieldResult)
			return
		}
	}()

	// return a result channel
	return resultChannel
}
<|endoftext|>


<commit_before>package main

import (
	"reflect"
	"regexp"
	"testing"
)

var genMatcherTests = []struct {
	src string
	dst *regexp.Regexp
}{
	// one branch
	{`abc`, regexp.MustCompile(`(abc)`)},
	{`abcdef`, regexp.MustCompile(`(abcdef)`)},

	// multiple branches
	{`a,b`, regexp.MustCompile(`(a|b)`)},
	{`a,,b,c`, regexp.MustCompile(`(a||b|c)`)},
	{`a,bc,def`, regexp.MustCompile(`(a|bc|def)`)},
	{`,a`, regexp.MustCompile(`(|a)`)},
	{`a,`, regexp.MustCompile(`(a|)`)},
	{`,a,`, regexp.MustCompile(`(|a|)`)},

	// use escape
	{`a\,b`, regexp.MustCompile(`(a,b)`)},
	{`a\,bc\,def`, regexp.MustCompile(`(a,bc,def)`)},

	// multiple branches with escape
	{`a\,b,c`, regexp.MustCompile(`(a,b|c)`)},
	{`a,bc\,def`, regexp.MustCompile(`(a|bc,def)`)},

	// regexp quote
	{`a+b`, regexp.MustCompile(`(a\+b)`)},
	{`(a|bc)*def`, regexp.MustCompile(`(\(a\|bc\)\*def)`)},

	// unquote special values
	{`a\\bc`, regexp.MustCompile("(a\\\\bc)")},
	{`a\tb\,c`, regexp.MustCompile("(a\tb,c)")},
	{`a\tbc\n\ndef`, regexp.MustCompile("(a\tbc\n\ndef)")},

	// multiple sequenses
	{`a~b`, regexp.MustCompile("(a)(b)")},
	{`a~~b~c`, regexp.MustCompile(`(a)()(b)(c)`)},
	{`a~bc~def`, regexp.MustCompile("(a)(bc)(def)")},
	{`a,b~c`, regexp.MustCompile("(a|b)(c)")},
	{`~a`, regexp.MustCompile(`()(a)`)},
	{`a~`, regexp.MustCompile(`(a)()`)},
	{`~a~`, regexp.MustCompile(`()(a)()`)},

	// multiple sequenses with escape
	{`a~b\~c`, regexp.MustCompile("(a)(b~c)")},
	{`a~\~bc\~~def`, regexp.MustCompile("(a)(~bc~)(def)")},
	{`a\,b,c~d,e\~f`, regexp.MustCompile("(a,b|c)(d|e~f)")},
}

func TestGenMatcher(t *testing.T) {
	for _, test := range genMatcherTests {
		expect := test.dst
		actual, err := newMatcher(test.src)
		if err != nil {
			t.Errorf("NewSubvert(%q) returns %q, want nil",
				test.src, err)
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("%q: got %q, want %q",
				test.src, actual, expect)
		}
	}
}
<commit_msg>Rewrite test for change separator of sequense from tilda to slash<commit_after>package main

import (
	"reflect"
	"regexp"
	"testing"
)

var genMatcherTests = []struct {
	src string
	dst *regexp.Regexp
}{
	// one branch
	{`abc`, regexp.MustCompile(`(abc)`)},
	{`abcdef`, regexp.MustCompile(`(abcdef)`)},

	// multiple branches
	{`a,b`, regexp.MustCompile(`(a|b)`)},
	{`a,,b,c`, regexp.MustCompile(`(a||b|c)`)},
	{`a,bc,def`, regexp.MustCompile(`(a|bc|def)`)},
	{`,a`, regexp.MustCompile(`(|a)`)},
	{`a,`, regexp.MustCompile(`(a|)`)},
	{`,a,`, regexp.MustCompile(`(|a|)`)},

	// use escape
	{`a\,b`, regexp.MustCompile(`(a,b)`)},
	{`a\,bc\,def`, regexp.MustCompile(`(a,bc,def)`)},

	// multiple branches with escape
	{`a\,b,c`, regexp.MustCompile(`(a,b|c)`)},
	{`a,bc\,def`, regexp.MustCompile(`(a|bc,def)`)},

	// regexp quote
	{`a+b`, regexp.MustCompile(`(a\+b)`)},
	{`(a|bc)*def`, regexp.MustCompile(`(\(a\|bc\)\*def)`)},

	// unquote special values
	{`a\\bc`, regexp.MustCompile("(a\\\\bc)")},
	{`a\tb\,c`, regexp.MustCompile("(a\tb,c)")},
	{`a\tbc\n\ndef`, regexp.MustCompile("(a\tbc\n\ndef)")},

	// multiple sequenses
	{`a/b`, regexp.MustCompile("(a)(b)")},
	{`a//b/c`, regexp.MustCompile(`(a)()(b)(c)`)},
	{`a/bc/def`, regexp.MustCompile("(a)(bc)(def)")},
	{`a,b/c`, regexp.MustCompile("(a|b)(c)")},
	{`/a`, regexp.MustCompile(`()(a)`)},
	{`a/`, regexp.MustCompile(`(a)()`)},
	{`/a/`, regexp.MustCompile(`()(a)()`)},

	// multiple sequenses with escape
	{`a/b\/c`, regexp.MustCompile("(a)(b/c)")},
	{`a/\/bc\//def`, regexp.MustCompile("(a)(/bc/)(def)")},
	{`a\,b,c/d,e\/f`, regexp.MustCompile("(a,b|c)(d|e/f)")},
}

func TestGenMatcher(t *testing.T) {
	for _, test := range genMatcherTests {
		expect := test.dst
		actual, err := newMatcher(test.src)
		if err != nil {
			t.Errorf("NewSubvert(%q) returns %q, want nil",
				test.src, err)
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("%q: got %q, want %q",
				test.src, actual, expect)
		}
	}
}
<|endoftext|>


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

// +build example jsgo

package main

import (
	"bytes"
	"fmt"
	"image"
	_ "image/png"
	"log"
	"math"
	"math/rand"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/ebitenutil"
	"github.com/hajimehoshi/ebiten/examples/resources/images"
)

const (
	screenWidth  = 320
	screenHeight = 240
	maxAngle     = 256
)

var (
	ebitenImage *ebiten.Image
)

type Sprite struct {
	imageWidth  int
	imageHeight int
	x           int
	y           int
	vx          int
	vy          int
	angle       int
}

func (s *Sprite) Update() {
	s.x += s.vx
	s.y += s.vy
	if s.x < 0 {
		s.x = -s.x
		s.vx = -s.vx
	} else if mx := screenWidth - s.imageWidth; mx <= s.x {
		s.x = 2*mx - s.x
		s.vx = -s.vx
	}
	if s.y < 0 {
		s.y = -s.y
		s.vy = -s.vy
	} else if my := screenHeight - s.imageHeight; my <= s.y {
		s.y = 2*my - s.y
		s.vy = -s.vy
	}
	s.angle++
	if s.angle == maxAngle {
		s.angle = 0
	}
}

type Sprites struct {
	sprites []*Sprite
	num     int
}

func (s *Sprites) Update() {
	for _, sprite := range s.sprites {
		sprite.Update()
	}
}

const (
	MinSprites = 0
	MaxSprites = 50000
)

var (
	sprites = &Sprites{make([]*Sprite, MaxSprites), 500}
	op      = &ebiten.DrawImageOptions{}
)

func init() {
	// Decode image from a byte slice instead of a file so that
	// this example works in any working directory.
	// If you want to use a file, there are some options:
	// 1) Use os.Open and pass the file to the image decoder.
	//    This is a very regular way, but doesn't work on browsers.
	// 2) Use ebitenutil.OpenFile and pass the file to the image decoder.
	//    This works even on browsers.
	// 3) Use ebitenutil.NewImageFromFile to create an ebiten.Image directly from a file.
	//    This also works on browsers.
	img, _, err := image.Decode(bytes.NewReader(images.Ebiten_png))
	if err != nil {
		log.Fatal(err)
	}
	origEbitenImage, _ := ebiten.NewImageFromImage(img, ebiten.FilterDefault)

	w, h := origEbitenImage.Size()
	ebitenImage, _ = ebiten.NewImage(w, h, ebiten.FilterNearest)

	op := &ebiten.DrawImageOptions{}
	op.ColorM.Scale(1, 1, 1, 0.5)
	ebitenImage.DrawImage(origEbitenImage, op)

	for i := range sprites.sprites {
		w, h := ebitenImage.Size()
		x, y := rand.Intn(screenWidth-w), rand.Intn(screenHeight-h)
		vx, vy := 2*rand.Intn(2)-1, 2*rand.Intn(2)-1
		a := rand.Intn(maxAngle)
		sprites.sprites[i] = &Sprite{
			imageWidth:  w,
			imageHeight: h,
			x:           x,
			y:           y,
			vx:          vx,
			vy:          vy,
			angle:       a,
		}
	}
}

func update(screen *ebiten.Image) error {
	// Decrease the nubmer of the sprites.
	if ebiten.IsKeyPressed(ebiten.KeyLeft) {
		sprites.num -= 20
		if sprites.num < MinSprites {
			sprites.num = MinSprites
		}
	}

	// Increase the nubmer of the sprites.
	if ebiten.IsKeyPressed(ebiten.KeyRight) {
		sprites.num += 20
		if MaxSprites < sprites.num {
			sprites.num = MaxSprites
		}
	}

	sprites.Update()

	if ebiten.IsRunningSlowly() {
		return nil
	}

	// Draw each sprite.
	// DrawImage can be called many many times, but in the implementation,
	// the actual draw call to GPU is very few since these calls satisfy
	// some conditions e.g. all the rendering sources and targets are same.
	// For more detail, see:
	// https://godoc.org/github.com/hajimehoshi/ebiten#Image.DrawImage
	w, h := ebitenImage.Size()
	for i := 0; i < sprites.num; i++ {
		s := sprites.sprites[i]
		op.GeoM.Reset()
		op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
		op.GeoM.Rotate(2 * math.Pi * float64(s.angle) / maxAngle)
		op.GeoM.Translate(float64(w)/2, float64(h)/2)
		op.GeoM.Translate(float64(s.x), float64(s.y))
		screen.DrawImage(ebitenImage, op)
	}
	msg := fmt.Sprintf(`FPS: %0.2f
Num of sprites: %d
Press <- or -> to change the number of sprites`, ebiten.CurrentFPS(), sprites.num)
	ebitenutil.DebugPrint(screen, msg)
	return nil
}

func main() {
	if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Sprites (Ebiten Demo)"); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>examples/sprites: Update only shown sprites<commit_after>// Copyright 2015 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build example jsgo

package main

import (
	"bytes"
	"fmt"
	"image"
	_ "image/png"
	"log"
	"math"
	"math/rand"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/ebitenutil"
	"github.com/hajimehoshi/ebiten/examples/resources/images"
)

const (
	screenWidth  = 320
	screenHeight = 240
	maxAngle     = 256
)

var (
	ebitenImage *ebiten.Image
)

type Sprite struct {
	imageWidth  int
	imageHeight int
	x           int
	y           int
	vx          int
	vy          int
	angle       int
}

func (s *Sprite) Update() {
	s.x += s.vx
	s.y += s.vy
	if s.x < 0 {
		s.x = -s.x
		s.vx = -s.vx
	} else if mx := screenWidth - s.imageWidth; mx <= s.x {
		s.x = 2*mx - s.x
		s.vx = -s.vx
	}
	if s.y < 0 {
		s.y = -s.y
		s.vy = -s.vy
	} else if my := screenHeight - s.imageHeight; my <= s.y {
		s.y = 2*my - s.y
		s.vy = -s.vy
	}
	s.angle++
	if s.angle == maxAngle {
		s.angle = 0
	}
}

type Sprites struct {
	sprites []*Sprite
	num     int
}

func (s *Sprites) Update() {
	for i := 0; i < s.num; i++ {
		s.sprites[i].Update()
	}
}

const (
	MinSprites = 0
	MaxSprites = 50000
)

var (
	sprites = &Sprites{make([]*Sprite, MaxSprites), 500}
	op      = &ebiten.DrawImageOptions{}
)

func init() {
	// Decode image from a byte slice instead of a file so that
	// this example works in any working directory.
	// If you want to use a file, there are some options:
	// 1) Use os.Open and pass the file to the image decoder.
	//    This is a very regular way, but doesn't work on browsers.
	// 2) Use ebitenutil.OpenFile and pass the file to the image decoder.
	//    This works even on browsers.
	// 3) Use ebitenutil.NewImageFromFile to create an ebiten.Image directly from a file.
	//    This also works on browsers.
	img, _, err := image.Decode(bytes.NewReader(images.Ebiten_png))
	if err != nil {
		log.Fatal(err)
	}
	origEbitenImage, _ := ebiten.NewImageFromImage(img, ebiten.FilterDefault)

	w, h := origEbitenImage.Size()
	ebitenImage, _ = ebiten.NewImage(w, h, ebiten.FilterNearest)

	op := &ebiten.DrawImageOptions{}
	op.ColorM.Scale(1, 1, 1, 0.5)
	ebitenImage.DrawImage(origEbitenImage, op)

	for i := range sprites.sprites {
		w, h := ebitenImage.Size()
		x, y := rand.Intn(screenWidth-w), rand.Intn(screenHeight-h)
		vx, vy := 2*rand.Intn(2)-1, 2*rand.Intn(2)-1
		a := rand.Intn(maxAngle)
		sprites.sprites[i] = &Sprite{
			imageWidth:  w,
			imageHeight: h,
			x:           x,
			y:           y,
			vx:          vx,
			vy:          vy,
			angle:       a,
		}
	}
}

func update(screen *ebiten.Image) error {
	// Decrease the nubmer of the sprites.
	if ebiten.IsKeyPressed(ebiten.KeyLeft) {
		sprites.num -= 20
		if sprites.num < MinSprites {
			sprites.num = MinSprites
		}
	}

	// Increase the nubmer of the sprites.
	if ebiten.IsKeyPressed(ebiten.KeyRight) {
		sprites.num += 20
		if MaxSprites < sprites.num {
			sprites.num = MaxSprites
		}
	}

	sprites.Update()

	if ebiten.IsRunningSlowly() {
		return nil
	}

	// Draw each sprite.
	// DrawImage can be called many many times, but in the implementation,
	// the actual draw call to GPU is very few since these calls satisfy
	// some conditions e.g. all the rendering sources and targets are same.
	// For more detail, see:
	// https://godoc.org/github.com/hajimehoshi/ebiten#Image.DrawImage
	w, h := ebitenImage.Size()
	for i := 0; i < sprites.num; i++ {
		s := sprites.sprites[i]
		op.GeoM.Reset()
		op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
		op.GeoM.Rotate(2 * math.Pi * float64(s.angle) / maxAngle)
		op.GeoM.Translate(float64(w)/2, float64(h)/2)
		op.GeoM.Translate(float64(s.x), float64(s.y))
		screen.DrawImage(ebitenImage, op)
	}
	msg := fmt.Sprintf(`FPS: %0.2f
Num of sprites: %d
Press <- or -> to change the number of sprites`, ebiten.CurrentFPS(), sprites.num)
	ebitenutil.DebugPrint(screen, msg)
	return nil
}

func main() {
	if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Sprites (Ebiten Demo)"); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// synscan implements a TCP syn scanner on top of pcap.
// It's more complicated than arpscan, since it has to handle sending packets
// outside the local network, requiring some routing and ARP work.
//
// Since this is just an example program, it aims for simplicity over
// performance.  It doesn't handle sending packets very quickly, it scans IPs
// serially instead of in parallel, and uses gopacket.Packet instead of
// gopacket.DecodingLayerParser for packet processing.  We also make use of very
// simple timeout logic with time.Since.
//
// Making it blazingly fast is left as an exercise to the reader.
package main

import (
	"errors"
	"flag"
	"log"
	"net"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/examples/util"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"github.com/google/gopacket/routing"
)

// scanner handles scanning a single IP address.
type scanner struct {
	// iface is the interface to send packets on.
	iface *net.Interface
	// destination, gateway (if applicable), and soruce IP addresses to use.
	dst, gw, src net.IP

	handle *pcap.Handle

	// opts and buf allow us to easily serialize packets in the send()
	// method.
	opts gopacket.SerializeOptions
	buf  gopacket.SerializeBuffer
}

// newScanner creates a new scanner for a given destination IP address, using
// router to determine how to route packets to that IP.
func newScanner(ip net.IP, router routing.Router) (*scanner, error) {
	s := &scanner{
		dst: ip,
		opts: gopacket.SerializeOptions{
			FixLengths:       true,
			ComputeChecksums: true,
		},
		buf: gopacket.NewSerializeBuffer(),
	}
	// Figure out the route to the IP.
	iface, gw, src, err := router.Route(ip)
	if err != nil {
		return nil, err
	}
	log.Printf("scanning ip %v with interface %v, gateway %v, src %v", ip, iface.Name, gw, src)
	s.gw, s.src, s.iface = gw, src, iface

	// Open the handle for reading/writing.
	// Note we could very easily add some BPF filtering here to greatly
	// decrease the number of packets we have to look at when getting back
	// scan results.
	handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
	if err != nil {
		return nil, err
	}
	s.handle = handle
	return s, nil
}

// close cleans up the handle.
func (s *scanner) close() {
	s.handle.Close()
}

// getHwAddr is a hacky but effective way to get the destination hardware
// address for our packets.  It does an ARP request for our gateway (if there is
// one) or destination IP (if no gateway is necessary), then waits for an ARP
// reply.  This is pretty slow right now, since it blocks on the ARP
// request/reply.
func (s *scanner) getHwAddr() (net.HardwareAddr, error) {
	start := time.Now()
	arpDst := s.dst
	if s.gw != nil {
		arpDst = s.gw
	}
	// Prepare the layers to send for an ARP request.
	eth := layers.Ethernet{
		SrcMAC:       s.iface.HardwareAddr,
		DstMAC:       net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
		EthernetType: layers.EthernetTypeARP,
	}
	arp := layers.ARP{
		AddrType:          layers.LinkTypeEthernet,
		Protocol:          layers.EthernetTypeIPv4,
		HwAddressSize:     6,
		ProtAddressSize:   4,
		Operation:         layers.ARPRequest,
		SourceHwAddress:   []byte(s.iface.HardwareAddr),
		SourceProtAddress: []byte(s.src),
		DstHwAddress:      []byte{0, 0, 0, 0, 0, 0},
		DstProtAddress:    []byte(arpDst),
	}
	// Send a single ARP request packet (we never retry a send, since this
	// is just an example ;)
	if err := s.send(&eth, &arp); err != nil {
		return nil, err
	}
	// Wait 3 seconds for an ARP reply.
	for {
		if time.Since(start) > time.Second*3 {
			return nil, errors.New("timeout getting ARP reply")
		}
		data, _, err := s.handle.ReadPacketData()
		if err == pcap.NextErrorTimeoutExpired {
			continue
		} else if err != nil {
			return nil, err
		}
		packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
		if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
			arp := arpLayer.(*layers.ARP)
			if net.IP(arp.SourceProtAddress).Equal(net.IP(arpDst)) {
				return net.HardwareAddr(arp.SourceHwAddress), nil
			}
		}
	}
}

// scan scans the dst IP address of this scanner.
func (s *scanner) scan() error {
	// First off, get the MAC address we should be sending packets to.
	hwaddr, err := s.getHwAddr()
	if err != nil {
		return err
	}
	// Construct all the network layers we need.
	eth := layers.Ethernet{
		SrcMAC:       s.iface.HardwareAddr,
		DstMAC:       hwaddr,
		EthernetType: layers.EthernetTypeIPv4,
	}
	ip4 := layers.IPv4{
		SrcIP:    s.src,
		DstIP:    s.dst,
		Version:  4,
		TTL:      64,
		Protocol: layers.IPProtocolTCP,
	}
	tcp := layers.TCP{
		SrcPort: 54321,
		DstPort: 0, // will be incremented during the scan
		SYN:     true,
	}
	tcp.SetNetworkLayerForChecksum(&ip4)

	// Create the flow we expect returning packets to have, so we can check
	// against it and discard useless packets.
	ipFlow := gopacket.NewFlow(layers.EndpointIPv4, s.dst, s.src)
	start := time.Now()
	for {
		// Send one packet per loop iteration until we've sent packets
		// to all of ports [1, 65535].
		if tcp.DstPort < 65535 {
			start = time.Now()
			tcp.DstPort++
			if err := s.send(&eth, &ip4, &tcp); err != nil {
				log.Printf("error sending to port %v: %v", tcp.DstPort, err)
			}
		}
		// Time out 5 seconds after the last packet we sent.
		if time.Since(start) > time.Second*5 {
			log.Printf("timed out for %v, assuming we've seen all we can", s.dst)
			return nil
		}

		// Read in the next packet.
		data, _, err := s.handle.ReadPacketData()
		if err == pcap.NextErrorTimeoutExpired {
			continue
		} else if err != nil {
			log.Printf("error reading packet: %v", err)
			continue
		}

		// Parse the packet.  We'd use DecodingLayerParser here if we
		// wanted to be really fast.
		packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)

		// Find the packets we care about, and print out logging
		// information about them.  All others are ignored.
		if net := packet.NetworkLayer(); net == nil {
			// log.Printf("packet has no network layer")
		} else if net.NetworkFlow() != ipFlow {
			// log.Printf("packet does not match our ip src/dst")
		} else if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer == nil {
			// log.Printf("packet has not tcp layer")
		} else if tcp, ok := tcpLayer.(*layers.TCP); !ok {
			// We panic here because this is guaranteed to never
			// happen.
			panic("tcp layer is not tcp layer :-/")
		} else if tcp.DstPort != 54321 {
			// log.Printf("dst port %v does not match", tcp.DstPort)
		} else if tcp.RST {
			log.Printf("  port %v closed", tcp.SrcPort)
		} else if tcp.SYN && tcp.ACK {
			log.Printf("  port %v open", tcp.SrcPort)
		} else {
			// log.Printf("ignoring useless packet")
		}
	}
}

// send sends the given layers as a single packet on the network.
func (s *scanner) send(l ...gopacket.SerializableLayer) error {
	if err := gopacket.SerializeLayers(s.buf, s.opts, l...); err != nil {
		return err
	}
	return s.handle.WritePacketData(s.buf.Bytes())
}

func main() {
	defer util.Run()()
	router, err := routing.New()
	if err != nil {
		log.Fatal("routing error:", err)
	}
	for _, arg := range flag.Args() {
		var ip net.IP
		if ip = net.ParseIP(arg); ip == nil {
			log.Printf("non-ip target: %q", arg)
			continue
		} else if ip = ip.To4(); ip == nil {
			log.Printf("non-ipv4 target: %q", arg)
			continue
		}
		// Note:  newScanner creates and closes a pcap Handle once for
		// every scan target.  We could do much better, were this not an
		// example ;)
		s, err := newScanner(ip, router)
		if err != nil {
			log.Printf("unable to create scanner for %v: %v", ip, err)
			continue
		}
		if err := s.scan(); err != nil {
			log.Printf("unable to scan %v: %v", ip, err)
		}
		s.close()
	}
}
<commit_msg>fix typo in comment<commit_after>// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// synscan implements a TCP syn scanner on top of pcap.
// It's more complicated than arpscan, since it has to handle sending packets
// outside the local network, requiring some routing and ARP work.
//
// Since this is just an example program, it aims for simplicity over
// performance.  It doesn't handle sending packets very quickly, it scans IPs
// serially instead of in parallel, and uses gopacket.Packet instead of
// gopacket.DecodingLayerParser for packet processing.  We also make use of very
// simple timeout logic with time.Since.
//
// Making it blazingly fast is left as an exercise to the reader.
package main

import (
	"errors"
	"flag"
	"log"
	"net"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/examples/util"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"github.com/google/gopacket/routing"
)

// scanner handles scanning a single IP address.
type scanner struct {
	// iface is the interface to send packets on.
	iface *net.Interface
	// destination, gateway (if applicable), and source IP addresses to use.
	dst, gw, src net.IP

	handle *pcap.Handle

	// opts and buf allow us to easily serialize packets in the send()
	// method.
	opts gopacket.SerializeOptions
	buf  gopacket.SerializeBuffer
}

// newScanner creates a new scanner for a given destination IP address, using
// router to determine how to route packets to that IP.
func newScanner(ip net.IP, router routing.Router) (*scanner, error) {
	s := &scanner{
		dst: ip,
		opts: gopacket.SerializeOptions{
			FixLengths:       true,
			ComputeChecksums: true,
		},
		buf: gopacket.NewSerializeBuffer(),
	}
	// Figure out the route to the IP.
	iface, gw, src, err := router.Route(ip)
	if err != nil {
		return nil, err
	}
	log.Printf("scanning ip %v with interface %v, gateway %v, src %v", ip, iface.Name, gw, src)
	s.gw, s.src, s.iface = gw, src, iface

	// Open the handle for reading/writing.
	// Note we could very easily add some BPF filtering here to greatly
	// decrease the number of packets we have to look at when getting back
	// scan results.
	handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
	if err != nil {
		return nil, err
	}
	s.handle = handle
	return s, nil
}

// close cleans up the handle.
func (s *scanner) close() {
	s.handle.Close()
}

// getHwAddr is a hacky but effective way to get the destination hardware
// address for our packets.  It does an ARP request for our gateway (if there is
// one) or destination IP (if no gateway is necessary), then waits for an ARP
// reply.  This is pretty slow right now, since it blocks on the ARP
// request/reply.
func (s *scanner) getHwAddr() (net.HardwareAddr, error) {
	start := time.Now()
	arpDst := s.dst
	if s.gw != nil {
		arpDst = s.gw
	}
	// Prepare the layers to send for an ARP request.
	eth := layers.Ethernet{
		SrcMAC:       s.iface.HardwareAddr,
		DstMAC:       net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
		EthernetType: layers.EthernetTypeARP,
	}
	arp := layers.ARP{
		AddrType:          layers.LinkTypeEthernet,
		Protocol:          layers.EthernetTypeIPv4,
		HwAddressSize:     6,
		ProtAddressSize:   4,
		Operation:         layers.ARPRequest,
		SourceHwAddress:   []byte(s.iface.HardwareAddr),
		SourceProtAddress: []byte(s.src),
		DstHwAddress:      []byte{0, 0, 0, 0, 0, 0},
		DstProtAddress:    []byte(arpDst),
	}
	// Send a single ARP request packet (we never retry a send, since this
	// is just an example ;)
	if err := s.send(&eth, &arp); err != nil {
		return nil, err
	}
	// Wait 3 seconds for an ARP reply.
	for {
		if time.Since(start) > time.Second*3 {
			return nil, errors.New("timeout getting ARP reply")
		}
		data, _, err := s.handle.ReadPacketData()
		if err == pcap.NextErrorTimeoutExpired {
			continue
		} else if err != nil {
			return nil, err
		}
		packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
		if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
			arp := arpLayer.(*layers.ARP)
			if net.IP(arp.SourceProtAddress).Equal(net.IP(arpDst)) {
				return net.HardwareAddr(arp.SourceHwAddress), nil
			}
		}
	}
}

// scan scans the dst IP address of this scanner.
func (s *scanner) scan() error {
	// First off, get the MAC address we should be sending packets to.
	hwaddr, err := s.getHwAddr()
	if err != nil {
		return err
	}
	// Construct all the network layers we need.
	eth := layers.Ethernet{
		SrcMAC:       s.iface.HardwareAddr,
		DstMAC:       hwaddr,
		EthernetType: layers.EthernetTypeIPv4,
	}
	ip4 := layers.IPv4{
		SrcIP:    s.src,
		DstIP:    s.dst,
		Version:  4,
		TTL:      64,
		Protocol: layers.IPProtocolTCP,
	}
	tcp := layers.TCP{
		SrcPort: 54321,
		DstPort: 0, // will be incremented during the scan
		SYN:     true,
	}
	tcp.SetNetworkLayerForChecksum(&ip4)

	// Create the flow we expect returning packets to have, so we can check
	// against it and discard useless packets.
	ipFlow := gopacket.NewFlow(layers.EndpointIPv4, s.dst, s.src)
	start := time.Now()
	for {
		// Send one packet per loop iteration until we've sent packets
		// to all of ports [1, 65535].
		if tcp.DstPort < 65535 {
			start = time.Now()
			tcp.DstPort++
			if err := s.send(&eth, &ip4, &tcp); err != nil {
				log.Printf("error sending to port %v: %v", tcp.DstPort, err)
			}
		}
		// Time out 5 seconds after the last packet we sent.
		if time.Since(start) > time.Second*5 {
			log.Printf("timed out for %v, assuming we've seen all we can", s.dst)
			return nil
		}

		// Read in the next packet.
		data, _, err := s.handle.ReadPacketData()
		if err == pcap.NextErrorTimeoutExpired {
			continue
		} else if err != nil {
			log.Printf("error reading packet: %v", err)
			continue
		}

		// Parse the packet.  We'd use DecodingLayerParser here if we
		// wanted to be really fast.
		packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)

		// Find the packets we care about, and print out logging
		// information about them.  All others are ignored.
		if net := packet.NetworkLayer(); net == nil {
			// log.Printf("packet has no network layer")
		} else if net.NetworkFlow() != ipFlow {
			// log.Printf("packet does not match our ip src/dst")
		} else if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer == nil {
			// log.Printf("packet has not tcp layer")
		} else if tcp, ok := tcpLayer.(*layers.TCP); !ok {
			// We panic here because this is guaranteed to never
			// happen.
			panic("tcp layer is not tcp layer :-/")
		} else if tcp.DstPort != 54321 {
			// log.Printf("dst port %v does not match", tcp.DstPort)
		} else if tcp.RST {
			log.Printf("  port %v closed", tcp.SrcPort)
		} else if tcp.SYN && tcp.ACK {
			log.Printf("  port %v open", tcp.SrcPort)
		} else {
			// log.Printf("ignoring useless packet")
		}
	}
}

// send sends the given layers as a single packet on the network.
func (s *scanner) send(l ...gopacket.SerializableLayer) error {
	if err := gopacket.SerializeLayers(s.buf, s.opts, l...); err != nil {
		return err
	}
	return s.handle.WritePacketData(s.buf.Bytes())
}

func main() {
	defer util.Run()()
	router, err := routing.New()
	if err != nil {
		log.Fatal("routing error:", err)
	}
	for _, arg := range flag.Args() {
		var ip net.IP
		if ip = net.ParseIP(arg); ip == nil {
			log.Printf("non-ip target: %q", arg)
			continue
		} else if ip = ip.To4(); ip == nil {
			log.Printf("non-ipv4 target: %q", arg)
			continue
		}
		// Note:  newScanner creates and closes a pcap Handle once for
		// every scan target.  We could do much better, were this not an
		// example ;)
		s, err := newScanner(ip, router)
		if err != nil {
			log.Printf("unable to create scanner for %v: %v", ip, err)
			continue
		}
		if err := s.scan(); err != nil {
			log.Printf("unable to scan %v: %v", ip, err)
		}
		s.close()
	}
}
<|endoftext|>


<commit_before>package divsd

// The config
type Config struct {
	Global   globalConfig
	Raft     raftConfig
	Discover discoverConfig
	Mdns     mdnsConfig
	Tun      tunConfig
}

type globalConfig struct {
	Name   string
	Host   string
	Port   int
	Serial string
}

type mdnsConfig struct {
	Port   int
}

type raftConfig struct {
	DataPath string
	IsLeader bool
	Leader   string
}

type discoverConfig struct {
	Port int
}

type tunConfig struct {
	NumReaders int
}

// create a new config
func NewConfig() (c *Config) {
	c = &Config{}
	return
}
<commit_msg>Comments and docs<commit_after>package divsd

// The top config
type Config struct {
	Global   globalConfig
	Raft     raftConfig
	Discover discoverConfig
	Mdns     mdnsConfig
	Tun      tunConfig
}

// Global config
type globalConfig struct {
	Name   string
	Host   string
	Port   int
	Serial string
}

// RAFT
type raftConfig struct {
	DataPath string
	IsLeader bool
	Leader   string
}

// MDNS discovery
type mdnsConfig struct {
	Port   int
}

// DHT discovery
type discoverConfig struct {
	Port int
}

// NAT: TUN config
type tunConfig struct {
	NumReaders int
}

// create a new config
func NewConfig() (c *Config) {
	c = &Config{}
	return
}
<|endoftext|>


<commit_before>// Copyright 2013 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by BSD-style
// license that can be found in the LICENSE file.

package github

import (
	"fmt"
	"time"
)

// GistsService handles communication with the Gist related
// methods of the GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/gists/
type GistsService service

// Gist represents a GitHub's gist.
type Gist struct {
	ID          *string                   `json:"id,omitempty"`
	Description *string                   `json:"description,omitempty"`
	Public      *bool                     `json:"public,omitempty"`
	Owner       *User                     `json:"owner,omitempty"`
	Files       map[GistFilename]GistFile `json:"files,omitempty"`
	Comments    *int                      `json:"comments,omitempty"`
	HTMLURL     *string                   `json:"html_url,omitempty"`
	GitPullURL  *string                   `json:"git_pull_url,omitempty"`
	GitPushURL  *string                   `json:"git_push_url,omitempty"`
	CreatedAt   *time.Time                `json:"created_at,omitempty"`
	UpdatedAt   *time.Time                `json:"updated_at,omitempty"`
}

func (g Gist) String() string {
	return Stringify(g)
}

// GistFilename represents filename on a gist.
type GistFilename string

// GistFile represents a file on a gist.
type GistFile struct {
	Size     *int    `json:"size,omitempty"`
	Filename *string `json:"filename,omitempty"`
	Type     *string `json:"type,omitempty"`
	RawURL   *string `json:"raw_url,omitempty"`
	Content  *string `json:"content,omitempty"`
}

func (g GistFile) String() string {
	return Stringify(g)
}

// GistCommit represents a commit on a gist.
type GistCommit struct {
	URL          *string      `json:"url,omitempty"`
	Version      *string      `json:"version,omitempty"`
	User         *User        `json:"user,omitempty"`
	ChangeStatus *CommitStats `json:"change_status,omitempty"`
	CommitedAt   *Timestamp   `json:"commited_at,omitempty"`
}

func (gc GistCommit) String() string {
	return Stringify(gc)
}

// GistFork represents a fork of a gist.
type GistFork struct {
	URL       *string    `json:"url,omitempty"`
	User      *User      `json:"user,omitempty"`
	ID        *string    `json:"id,omitempty"`
	CreatedAt *Timestamp `json:"created_at,omitempty"`
	UpdatedAt *Timestamp `json:"updated_at,omitempty"`
}

func (gf GistFork) String() string {
	return Stringify(gf)
}

// GistListOptions specifies the optional parameters to the
// GistsService.List, GistsService.ListAll, and GistsService.ListStarred methods.
type GistListOptions struct {
	// Since filters Gists by time.
	Since time.Time `url:"since,omitempty"`

	ListOptions
}

// List gists for a user. Passing the empty string will list
// all public gists if called anonymously. However, if the call
// is authenticated, it will returns all gists for the authenticated
// user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#list-gists
func (s *GistsService) List(user string, opt *GistListOptions) ([]*Gist, *Response, error) {
	var u string
	if user != "" {
		u = fmt.Sprintf("users/%v/gists", user)
	} else {
		u = "gists"
	}
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gists []*Gist
	resp, err := s.client.Do(req, &gists)
	if err != nil {
		return nil, resp, err
	}

	return gists, resp, nil
}

// ListAll lists all public gists.
//
// GitHub API docs: http://developer.github.com/v3/gists/#list-gists
func (s *GistsService) ListAll(opt *GistListOptions) ([]*Gist, *Response, error) {
	u, err := addOptions("gists/public", opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gists []*Gist
	resp, err := s.client.Do(req, &gists)
	if err != nil {
		return nil, resp, err
	}

	return gists, resp, nil
}

// ListStarred lists starred gists of authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#list-gists
func (s *GistsService) ListStarred(opt *GistListOptions) ([]*Gist, *Response, error) {
	u, err := addOptions("gists/starred", opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gists []*Gist
	resp, err := s.client.Do(req, &gists)
	if err != nil {
		return nil, resp, err
	}

	return gists, resp, nil
}

// Get a single gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#get-a-single-gist
func (s *GistsService) Get(id string) (*Gist, *Response, error) {
	u := fmt.Sprintf("gists/%v", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}
	gist := new(Gist)
	resp, err := s.client.Do(req, gist)
	if err != nil {
		return nil, resp, err
	}

	return gist, resp, err
}

// GetRevision gets a specific revision of a gist.
//
// GitHub API docs: https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist
func (s *GistsService) GetRevision(id, sha string) (*Gist, *Response, error) {
	u := fmt.Sprintf("gists/%v/%v", id, sha)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}
	gist := new(Gist)
	resp, err := s.client.Do(req, gist)
	if err != nil {
		return nil, resp, err
	}

	return gist, resp, err
}

// Create a gist for authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#create-a-gist
func (s *GistsService) Create(gist *Gist) (*Gist, *Response, error) {
	u := "gists"
	req, err := s.client.NewRequest("POST", u, gist)
	if err != nil {
		return nil, nil, err
	}
	g := new(Gist)
	resp, err := s.client.Do(req, g)
	if err != nil {
		return nil, resp, err
	}

	return g, resp, err
}

// Edit a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#edit-a-gist
func (s *GistsService) Edit(id string, gist *Gist) (*Gist, *Response, error) {
	u := fmt.Sprintf("gists/%v", id)
	req, err := s.client.NewRequest("PATCH", u, gist)
	if err != nil {
		return nil, nil, err
	}
	g := new(Gist)
	resp, err := s.client.Do(req, g)
	if err != nil {
		return nil, resp, err
	}

	return g, resp, err
}

// ListCommits lists commits of a gist.
//
// Github API docs: https://developer.github.com/v3/gists/#list-gist-commits
func (s *GistsService) ListCommits(id string) ([]*GistCommit, *Response, error) {
	u := fmt.Sprintf("gists/%v/commits", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gistCommits []*GistCommit
	resp, err := s.client.Do(req, &gistCommits)
	if err != nil {
		return nil, resp, err
	}

	return gistCommits, resp, nil
}

// Delete a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#delete-a-gist
func (s *GistsService) Delete(id string) (*Response, error) {
	u := fmt.Sprintf("gists/%v", id)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}

// Star a gist on behalf of authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#star-a-gist
func (s *GistsService) Star(id string) (*Response, error) {
	u := fmt.Sprintf("gists/%v/star", id)
	req, err := s.client.NewRequest("PUT", u, nil)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}

// Unstar a gist on a behalf of authenticated user.
//
// Github API docs: http://developer.github.com/v3/gists/#unstar-a-gist
func (s *GistsService) Unstar(id string) (*Response, error) {
	u := fmt.Sprintf("gists/%v/star", id)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}

// IsStarred checks if a gist is starred by authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#check-if-a-gist-is-starred
func (s *GistsService) IsStarred(id string) (bool, *Response, error) {
	u := fmt.Sprintf("gists/%v/star", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return false, nil, err
	}
	resp, err := s.client.Do(req, nil)
	starred, err := parseBoolResponse(err)
	return starred, resp, err
}

// Fork a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#fork-a-gist
func (s *GistsService) Fork(id string) (*Gist, *Response, error) {
	u := fmt.Sprintf("gists/%v/forks", id)
	req, err := s.client.NewRequest("POST", u, nil)
	if err != nil {
		return nil, nil, err
	}

	g := new(Gist)
	resp, err := s.client.Do(req, g)
	if err != nil {
		return nil, resp, err
	}

	return g, resp, err
}

// ListForks lists forks of a gist.
//
// Github API docs: https://developer.github.com/v3/gists/#list-gist-forks
func (s *GistsService) ListForks(id string) ([]*GistFork, *Response, error) {
	u := fmt.Sprintf("gists/%v/forks", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gistForks []*GistFork
	resp, err := s.client.Do(req, &gistForks)
	if err != nil {
		return nil, resp, err
	}

	return gistForks, resp, nil
}
<commit_msg>Add Language field to GistFile. (#532)<commit_after>// Copyright 2013 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by BSD-style
// license that can be found in the LICENSE file.

package github

import (
	"fmt"
	"time"
)

// GistsService handles communication with the Gist related
// methods of the GitHub API.
//
// GitHub API docs: http://developer.github.com/v3/gists/
type GistsService service

// Gist represents a GitHub's gist.
type Gist struct {
	ID          *string                   `json:"id,omitempty"`
	Description *string                   `json:"description,omitempty"`
	Public      *bool                     `json:"public,omitempty"`
	Owner       *User                     `json:"owner,omitempty"`
	Files       map[GistFilename]GistFile `json:"files,omitempty"`
	Comments    *int                      `json:"comments,omitempty"`
	HTMLURL     *string                   `json:"html_url,omitempty"`
	GitPullURL  *string                   `json:"git_pull_url,omitempty"`
	GitPushURL  *string                   `json:"git_push_url,omitempty"`
	CreatedAt   *time.Time                `json:"created_at,omitempty"`
	UpdatedAt   *time.Time                `json:"updated_at,omitempty"`
}

func (g Gist) String() string {
	return Stringify(g)
}

// GistFilename represents filename on a gist.
type GistFilename string

// GistFile represents a file on a gist.
type GistFile struct {
	Size     *int    `json:"size,omitempty"`
	Filename *string `json:"filename,omitempty"`
	Language *string `json:"language,omitempty"`
	Type     *string `json:"type,omitempty"`
	RawURL   *string `json:"raw_url,omitempty"`
	Content  *string `json:"content,omitempty"`
}

func (g GistFile) String() string {
	return Stringify(g)
}

// GistCommit represents a commit on a gist.
type GistCommit struct {
	URL          *string      `json:"url,omitempty"`
	Version      *string      `json:"version,omitempty"`
	User         *User        `json:"user,omitempty"`
	ChangeStatus *CommitStats `json:"change_status,omitempty"`
	CommitedAt   *Timestamp   `json:"commited_at,omitempty"`
}

func (gc GistCommit) String() string {
	return Stringify(gc)
}

// GistFork represents a fork of a gist.
type GistFork struct {
	URL       *string    `json:"url,omitempty"`
	User      *User      `json:"user,omitempty"`
	ID        *string    `json:"id,omitempty"`
	CreatedAt *Timestamp `json:"created_at,omitempty"`
	UpdatedAt *Timestamp `json:"updated_at,omitempty"`
}

func (gf GistFork) String() string {
	return Stringify(gf)
}

// GistListOptions specifies the optional parameters to the
// GistsService.List, GistsService.ListAll, and GistsService.ListStarred methods.
type GistListOptions struct {
	// Since filters Gists by time.
	Since time.Time `url:"since,omitempty"`

	ListOptions
}

// List gists for a user. Passing the empty string will list
// all public gists if called anonymously. However, if the call
// is authenticated, it will returns all gists for the authenticated
// user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#list-gists
func (s *GistsService) List(user string, opt *GistListOptions) ([]*Gist, *Response, error) {
	var u string
	if user != "" {
		u = fmt.Sprintf("users/%v/gists", user)
	} else {
		u = "gists"
	}
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gists []*Gist
	resp, err := s.client.Do(req, &gists)
	if err != nil {
		return nil, resp, err
	}

	return gists, resp, nil
}

// ListAll lists all public gists.
//
// GitHub API docs: http://developer.github.com/v3/gists/#list-gists
func (s *GistsService) ListAll(opt *GistListOptions) ([]*Gist, *Response, error) {
	u, err := addOptions("gists/public", opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gists []*Gist
	resp, err := s.client.Do(req, &gists)
	if err != nil {
		return nil, resp, err
	}

	return gists, resp, nil
}

// ListStarred lists starred gists of authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#list-gists
func (s *GistsService) ListStarred(opt *GistListOptions) ([]*Gist, *Response, error) {
	u, err := addOptions("gists/starred", opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gists []*Gist
	resp, err := s.client.Do(req, &gists)
	if err != nil {
		return nil, resp, err
	}

	return gists, resp, nil
}

// Get a single gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#get-a-single-gist
func (s *GistsService) Get(id string) (*Gist, *Response, error) {
	u := fmt.Sprintf("gists/%v", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}
	gist := new(Gist)
	resp, err := s.client.Do(req, gist)
	if err != nil {
		return nil, resp, err
	}

	return gist, resp, err
}

// GetRevision gets a specific revision of a gist.
//
// GitHub API docs: https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist
func (s *GistsService) GetRevision(id, sha string) (*Gist, *Response, error) {
	u := fmt.Sprintf("gists/%v/%v", id, sha)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}
	gist := new(Gist)
	resp, err := s.client.Do(req, gist)
	if err != nil {
		return nil, resp, err
	}

	return gist, resp, err
}

// Create a gist for authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#create-a-gist
func (s *GistsService) Create(gist *Gist) (*Gist, *Response, error) {
	u := "gists"
	req, err := s.client.NewRequest("POST", u, gist)
	if err != nil {
		return nil, nil, err
	}
	g := new(Gist)
	resp, err := s.client.Do(req, g)
	if err != nil {
		return nil, resp, err
	}

	return g, resp, err
}

// Edit a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#edit-a-gist
func (s *GistsService) Edit(id string, gist *Gist) (*Gist, *Response, error) {
	u := fmt.Sprintf("gists/%v", id)
	req, err := s.client.NewRequest("PATCH", u, gist)
	if err != nil {
		return nil, nil, err
	}
	g := new(Gist)
	resp, err := s.client.Do(req, g)
	if err != nil {
		return nil, resp, err
	}

	return g, resp, err
}

// ListCommits lists commits of a gist.
//
// Github API docs: https://developer.github.com/v3/gists/#list-gist-commits
func (s *GistsService) ListCommits(id string) ([]*GistCommit, *Response, error) {
	u := fmt.Sprintf("gists/%v/commits", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gistCommits []*GistCommit
	resp, err := s.client.Do(req, &gistCommits)
	if err != nil {
		return nil, resp, err
	}

	return gistCommits, resp, nil
}

// Delete a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#delete-a-gist
func (s *GistsService) Delete(id string) (*Response, error) {
	u := fmt.Sprintf("gists/%v", id)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}

// Star a gist on behalf of authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#star-a-gist
func (s *GistsService) Star(id string) (*Response, error) {
	u := fmt.Sprintf("gists/%v/star", id)
	req, err := s.client.NewRequest("PUT", u, nil)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}

// Unstar a gist on a behalf of authenticated user.
//
// Github API docs: http://developer.github.com/v3/gists/#unstar-a-gist
func (s *GistsService) Unstar(id string) (*Response, error) {
	u := fmt.Sprintf("gists/%v/star", id)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}

// IsStarred checks if a gist is starred by authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/gists/#check-if-a-gist-is-starred
func (s *GistsService) IsStarred(id string) (bool, *Response, error) {
	u := fmt.Sprintf("gists/%v/star", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return false, nil, err
	}
	resp, err := s.client.Do(req, nil)
	starred, err := parseBoolResponse(err)
	return starred, resp, err
}

// Fork a gist.
//
// GitHub API docs: http://developer.github.com/v3/gists/#fork-a-gist
func (s *GistsService) Fork(id string) (*Gist, *Response, error) {
	u := fmt.Sprintf("gists/%v/forks", id)
	req, err := s.client.NewRequest("POST", u, nil)
	if err != nil {
		return nil, nil, err
	}

	g := new(Gist)
	resp, err := s.client.Do(req, g)
	if err != nil {
		return nil, resp, err
	}

	return g, resp, err
}

// ListForks lists forks of a gist.
//
// Github API docs: https://developer.github.com/v3/gists/#list-gist-forks
func (s *GistsService) ListForks(id string) ([]*GistFork, *Response, error) {
	u := fmt.Sprintf("gists/%v/forks", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var gistForks []*GistFork
	resp, err := s.client.Do(req, &gistForks)
	if err != nil {
		return nil, resp, err
	}

	return gistForks, resp, nil
}
<|endoftext|>


<commit_before>// Package math provides math helper functions.
package math

// IntAbs returns the absolute value of n.
func IntAbs(n int) int {
	if n < 0 {
		return -n
	}
	return n
}
<commit_msg>Add IntMax function to math package<commit_after>// Package math provides math helper functions.
package math

// IntAbs returns the absolute value of n.
func IntAbs(n int) int {
	if n < 0 {
		return -n
	}
	return n
}

// IntMax returns the larger of a and b.
func IntMax(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>// The gobinarytest package is used in testing serialization and
// deserialization. It is particularly useful when some sub-sequences of bytes
// can acceptably be written in any order (e.g if they are generated from
// representations that do not provide order guarantees like maps).
package gobinarytest

import (
	"bytes"
	"fmt"
	"strings"
)

type MatchError struct {
	FailedMatcher Matcher
	NextBytes     []byte
	Context       []string
}

func (err *MatchError) Error() string {
	return fmt.Sprintf(
		"failed to match %s %v on remaining bytes: %x",
		strings.Join(err.Context, " within "),
		err.FailedMatcher, err.NextBytes)
}

func (err *MatchError) AddContext(ctx string) {
	err.Context = append(err.Context, ctx)
}

type TrailingBytesError struct {
	FailedMatcher Matcher
	TrailingBytes []byte
}

func (err *TrailingBytesError) Error() string {
	return fmt.Sprintf("trailing bytes when matching %v: %x", err.FailedMatcher, err.TrailingBytes)
}

// Matcher is the interface that tests if a sequence of bytes matches
// expectations.
type Matcher interface {
	// Match tests if the given sequence of bytes matches. It returns
	// matches=true if it matches correctly, and returns the number of bytes
	// matched as n.
	Match(b []byte) (n int, err error)

	// Write writes a sequence of bytes to the buffer that is an acceptable match
	// for the matcher.
	Write(writer *bytes.Buffer)

	String() string
}

// Named is a wrapper for a Matcher that simply provides a name annotation on
// its String method and add its name to any MatchErrors.
type Named struct {
	Name string
	Matcher
}

func (bm Named) Match(b []byte) (n int, err error) {
	n, err = bm.Matcher.Match(b)
	if err != nil {
		if matchErr, ok := err.(*MatchError); ok {
			matchErr.AddContext(bm.Name)
		}
	}
	return
}

func (bm Named) String() string {
	return fmt.Sprintf("(%s) %s", bm.Name, bm.Matcher)
}

// Literal matches a literal sequence of bytes.
type Literal []byte

func LiteralString(s string) Literal {
	return Literal(s)
}

func (bm Literal) Match(b []byte) (n int, err error) {
	if len(b) < len(bm) {
		return 0, &MatchError{bm, b, nil}
	}

	for i, v := range bm {
		if v != b[i] {
			return 0, &MatchError{bm, b, nil}
		}
	}

	return len(bm), nil
}

func (bm Literal) Write(writer *bytes.Buffer) {
	writer.Write(bm)
}

func (bm Literal) String() string {
	return fmt.Sprintf("Literal{%x}", []byte(bm))
}

// InOrder matches a sequence of Matchers that must match in
// the order given.
type InOrder []Matcher

func (bm InOrder) Match(b []byte) (n int, err error) {
	var consumed int

	for _, matcher := range bm {
		remainder := b[n:]

		if consumed, err = matcher.Match(remainder); err != nil {
			return 0, err
		}

		n += consumed
	}

	return n, nil
}

func (bm InOrder) Write(writer *bytes.Buffer) {
	for _, matcher := range bm {
		matcher.Write(writer)
	}
}

func (bm InOrder) String() string {
	parts := make([]string, len(bm))
	for i, matcher := range bm {
		parts[i] = matcher.String()
	}
	s := strings.Join(parts, ", ")
	return fmt.Sprintf("InOrder{%s}", s)
}

// AnyOrder matches a set of Matchers, but they do not have to
// match in any particular order.
type AnyOrder []Matcher

func (bm AnyOrder) Match(b []byte) (n int, err error) {
	toMatch := make([]Matcher, len(bm))
	copy(toMatch, bm)
	var consumed int

	for {
		if len(toMatch) == 0 {
			break
		}

		remainder := b[n:]

		foundMatch := false
		for i, matcher := range toMatch {
			if consumed, err = matcher.Match(remainder); err == nil {
				foundMatch = true
				n += consumed

				// Remove matcher from toMatch.
				if len(toMatch) > 1 {
					toMatch[i] = toMatch[len(toMatch)-1]
				}
				toMatch = toMatch[:len(toMatch)-1]

				break
			}
		}

		if !foundMatch {
			return 0, &MatchError{AnyOrder(toMatch), remainder, nil}
		}
	}

	return n, nil
}

func (bm AnyOrder) Write(writer *bytes.Buffer) {
	for _, matcher := range bm {
		matcher.Write(writer)
	}
}

func (bm AnyOrder) String() string {
	parts := make([]string, len(bm))
	for i, matcher := range bm {
		parts[i] = matcher.String()
	}
	s := strings.Join(parts, ", ")
	return fmt.Sprintf("&AnyOrder{%s}", s)
}

func Matches(matcher Matcher, b []byte) error {
	n, err := matcher.Match(b)
	if err != nil {
		return err
	}
	if n != len(b) {
		return &TrailingBytesError{matcher, b}
	}
	return nil
}
<commit_msg>Improve error messages slightly.<commit_after>// The gobinarytest package is used in testing serialization and
// deserialization. It is particularly useful when some sub-sequences of bytes
// can acceptably be written in any order (e.g if they are generated from
// representations that do not provide order guarantees like maps).
package gobinarytest

import (
	"bytes"
	"fmt"
	"strings"
)

type MatchError struct {
	FailedMatcher Matcher
	NextBytes     []byte
	Context       []string
}

func (err *MatchError) Error() string {
	return fmt.Sprintf(
		"failed to match <%s> %v on remaining bytes: % x",
		strings.Join(err.Context, " within "),
		err.FailedMatcher, err.NextBytes)
}

func (err *MatchError) AddContext(ctx string) {
	err.Context = append(err.Context, ctx)
}

type TrailingBytesError struct {
	FailedMatcher Matcher
	TrailingBytes []byte
}

func (err *TrailingBytesError) Error() string {
	return fmt.Sprintf("%d trailing bytes when matching %v: % x",
		len(err.TrailingBytes), err.FailedMatcher, err.TrailingBytes)
}

// Matcher is the interface that tests if a sequence of bytes matches
// expectations.
type Matcher interface {
	// Match tests if the given sequence of bytes matches. It returns
	// matches=true if it matches correctly, and returns the number of bytes
	// matched as n.
	Match(b []byte) (n int, err error)

	// Write writes a sequence of bytes to the buffer that is an acceptable match
	// for the matcher.
	Write(writer *bytes.Buffer)

	String() string
}

// Named is a wrapper for a Matcher that simply provides a name annotation on
// its String method and add its name to any MatchErrors.
type Named struct {
	Name string
	Matcher
}

func (bm Named) Match(b []byte) (n int, err error) {
	n, err = bm.Matcher.Match(b)
	if err != nil {
		if matchErr, ok := err.(*MatchError); ok {
			matchErr.AddContext(bm.Name)
		}
	}
	return
}

func (bm Named) String() string {
	return fmt.Sprintf("(%s) %s", bm.Name, bm.Matcher)
}

// Literal matches a literal sequence of bytes.
type Literal []byte

func LiteralString(s string) Literal {
	return Literal(s)
}

func (bm Literal) Match(b []byte) (n int, err error) {
	if len(b) < len(bm) {
		return 0, &MatchError{bm, b, nil}
	}

	for i, v := range bm {
		if v != b[i] {
			return 0, &MatchError{bm, b, nil}
		}
	}

	return len(bm), nil
}

func (bm Literal) Write(writer *bytes.Buffer) {
	writer.Write(bm)
}

func (bm Literal) String() string {
	return fmt.Sprintf("Literal{% x}", []byte(bm))
}

// InOrder matches a sequence of Matchers that must match in
// the order given.
type InOrder []Matcher

func (bm InOrder) Match(b []byte) (n int, err error) {
	var consumed int

	for _, matcher := range bm {
		remainder := b[n:]

		if consumed, err = matcher.Match(remainder); err != nil {
			return 0, err
		}

		n += consumed
	}

	return n, nil
}

func (bm InOrder) Write(writer *bytes.Buffer) {
	for _, matcher := range bm {
		matcher.Write(writer)
	}
}

func (bm InOrder) String() string {
	parts := make([]string, len(bm))
	for i, matcher := range bm {
		parts[i] = matcher.String()
	}
	s := strings.Join(parts, ", ")
	return fmt.Sprintf("InOrder{%s}", s)
}

// AnyOrder matches a set of Matchers, but they do not have to
// match in any particular order.
type AnyOrder []Matcher

func (bm AnyOrder) Match(b []byte) (n int, err error) {
	toMatch := make([]Matcher, len(bm))
	copy(toMatch, bm)
	var consumed int

	for {
		if len(toMatch) == 0 {
			break
		}

		remainder := b[n:]

		foundMatch := false
		for i, matcher := range toMatch {
			if consumed, err = matcher.Match(remainder); err == nil {
				foundMatch = true
				n += consumed

				// Remove matcher from toMatch.
				if len(toMatch) > 1 {
					toMatch[i] = toMatch[len(toMatch)-1]
				}
				toMatch = toMatch[:len(toMatch)-1]

				break
			}
		}

		if !foundMatch {
			return 0, &MatchError{AnyOrder(toMatch), remainder, nil}
		}
	}

	return n, nil
}

func (bm AnyOrder) Write(writer *bytes.Buffer) {
	for _, matcher := range bm {
		matcher.Write(writer)
	}
}

func (bm AnyOrder) String() string {
	parts := make([]string, len(bm))
	for i, matcher := range bm {
		parts[i] = matcher.String()
	}
	s := strings.Join(parts, ", ")
	return fmt.Sprintf("&AnyOrder{%s}", s)
}

func Matches(matcher Matcher, b []byte) error {
	n, err := matcher.Match(b)
	if err != nil {
		return err
	}
	if n != len(b) {
		return &TrailingBytesError{matcher, b}
	}
	return nil
}
<|endoftext|>


<commit_before>// Package gohinetradio is to get hichannel radio path and with token to play without flash.
package gohinetradio

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"runtime"
	"sort"
	"strconv"
	"text/tabwriter"
)

var nCPU = runtime.NumCPU()

// Init.
func init() {
	runtime.GOMAXPROCS(nCPU)
}

// Base URL.
const (
	PLAYURL  string = "http://hichannel.hinet.net/radio/play.do?id=%s"
	LISTURL  string = "http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=%d"
	LISTPAGE int    = 1
)

// RadioData is the json of `http://hichannel.hinet.net/radio/play.do?id=232`
type RadioData struct {
	ChannelTitle   string `json:"channel_title"`
	PlayRadio      string `json:"playRadio"`
	ProgramName    string `json:"programName"`
	ChannelCollect bool   `json:"channel_collect"`
}

// GetURL is getting radio channel url with token.
func GetURL(No string) (RadioData, error) {
	var (
		err  error
		r    RadioData
		req  *http.Request
		resp *http.Response
	)

	client := &http.Client{}
	req, _ = http.NewRequest("GET", fmt.Sprintf(PLAYURL, No), nil)
	req.Header.Add("Referer", "http://hichannel.hinet.net/radio/index.do")
	resp, err = client.Do(req)
	if err != nil {
		log.Fatal("No network.")
	}
	defer resp.Body.Close()

	if data, err := ioutil.ReadAll(resp.Body); err == nil {
		json.NewDecoder(bytes.NewReader(data)).Decode(&r)
		if len(r.PlayRadio) == 0 {
			err = errors.New("No channel data.")
		}
	}
	return r, err
}

// RadioListData is the json of `http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=1`
type RadioListData struct {
	PageNo   int              `json:"pageNo"`
	PageSize int              `json:"pageSize"`
	List     []RadioListDatas `json:"list"`
}

//RadioListDatas is RadioListData.List type.
type RadioListDatas struct {
	ChannelImage string `json:"channel_image"`
	ChannelTitle string `json:"channel_title"`
	RadioType    string `json:"radio_type"`
	IsChannel    bool   `json:"isChannel"`
	ProgramName  string `json:"program_name"`
	ChannelID    string `json:"channel_id"`
}

func getRadioPageList(page int) RadioListData {
	var (
		err  error
		r    RadioListData
		resp *http.Response
	)
	if resp, err = http.Get(fmt.Sprintf(LISTURL, page)); err == nil {
		defer resp.Body.Close()
	} else {
		log.Fatal("No network.")
	}

	if data, err := ioutil.ReadAll(resp.Body); err == nil {
		json.NewDecoder(bytes.NewReader(data)).Decode(&r)
	}
	return r
}

// GetRadioList is getting all channel list.
func GetRadioList() []RadioListDatas {
	//queue := make(chan RadioListData, nCPU)
	//defer close(queue)

	//var wg sync.WaitGroup
	//wg.Add(LISTPAGE)
	//for i := 1; i <= LISTPAGE; i++ {
	//	go func(i int) {
	//		runtime.Gosched()
	//		queue <- getRadioPageList(i)
	//	}(i)
	//}
	//var r []RadioListDatas
	//go func() {
	//	for v := range queue {
	//		for _, data := range v.List {
	//			r = append(r, data)
	//		}
	//		wg.Done()
	//	}
	//}()
	//wg.Wait()
	//return r
	return getRadioPageList(LISTPAGE).List
}

type byChannel []RadioListDatas

func (c byChannel) Len() int      { return len(c) }
func (c byChannel) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c byChannel) Less(i, j int) bool {
	a, _ := strconv.Atoi(c[i].ChannelID)
	b, _ := strconv.Atoi(c[j].ChannelID)
	return a < b
}

// GenList is to output table list.
func GenList() {
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 38, 0, 0, ' ', 0)
	var (
		no        int
		output    string
		radioList []RadioListDatas
	)
	radioList = GetRadioList()
	sort.Sort(byChannel(radioList))
	for _, data := range radioList {
		if data.IsChannel {
			output += fmt.Sprintf("%3d. [%v] %s\t", no+1, data.ChannelID, data.ChannelTitle)
			if (no+1)%3 == 0 {
				fmt.Fprintln(w, output)
				output = ""
			}
			no++
		}
	}
	fmt.Fprintln(w, output)
	w.Flush()
}

// PrintChannel is my fav channel XD.
func PrintChannel() {
	fmt.Println("[207] 中廣新聞網")
	fmt.Println("[205] 中廣流行網 i like")
	fmt.Println("[206] 中廣音樂網i radio")
	fmt.Println("[232] 飛碟電台")
	fmt.Println("[222] HitFm聯播網 Taipei 北部")
	fmt.Println("[156] KISS RADIO 大眾廣播電台")
	fmt.Println("[308] KISS RADIO 網路音樂台")
	fmt.Println("[187] NEWS98新聞網")
	fmt.Println("[370] POP Radio 台北流行廣播電台")
}
<commit_msg>Add more error.<commit_after>// Package gohinetradio is to get hichannel radio path and with token to play without flash.
package gohinetradio

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"runtime"
	"sort"
	"strconv"
	"text/tabwriter"
)

// Init.
func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}

// Base URL.
const (
	PLAYURL  string = "http://hichannel.hinet.net/radio/play.do?id=%s"
	LISTURL  string = "http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=%d"
	LISTPAGE int    = 1
)

// RadioData is the json of `http://hichannel.hinet.net/radio/play.do?id=232`
type RadioData struct {
	ChannelTitle   string `json:"channel_title"`
	PlayRadio      string `json:"playRadio"`
	ProgramName    string `json:"programName"`
	ChannelCollect bool   `json:"channel_collect"`
}

// GetURL is getting radio channel url with token.
func GetURL(No string) (RadioData, error) {
	var (
		err  error
		r    RadioData
		req  *http.Request
		resp *http.Response
	)

	client := &http.Client{}
	req, _ = http.NewRequest("GET", fmt.Sprintf(PLAYURL, No), nil)
	req.Header.Add("Referer", "http://hichannel.hinet.net/radio/index.do")
	resp, err = client.Do(req)
	if err != nil {
		log.Fatal("No network.")
	}
	defer resp.Body.Close()

	if data, err := ioutil.ReadAll(resp.Body); err == nil {
		json.NewDecoder(bytes.NewReader(data)).Decode(&r)
		if len(r.PlayRadio) == 0 {
			err = errors.New("No channel data.")
		}
	}
	return r, err
}

// RadioListData is the json of `http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=1`
type RadioListData struct {
	PageNo   int              `json:"pageNo"`
	PageSize int              `json:"pageSize"`
	List     []RadioListDatas `json:"list"`
}

//RadioListDatas is RadioListData.List type.
type RadioListDatas struct {
	ChannelImage string `json:"channel_image"`
	ChannelTitle string `json:"channel_title"`
	RadioType    string `json:"radio_type"`
	IsChannel    bool   `json:"isChannel"`
	ProgramName  string `json:"program_name"`
	ChannelID    string `json:"channel_id"`
}

func getRadioPageList(page int) (RadioListData, error) {
	var (
		data []byte
		err  error
		r    RadioListData
		resp *http.Response
	)
	if resp, err = http.Get(fmt.Sprintf(LISTURL, page)); err == nil {
		defer resp.Body.Close()
	}

	if data, err = ioutil.ReadAll(resp.Body); err == nil {
		json.NewDecoder(bytes.NewReader(data)).Decode(&r)
	}
	return r, err
}

// GetRadioList is getting all channel list.
func GetRadioList() []RadioListDatas {
	//queue := make(chan RadioListData, nCPU)
	//defer close(queue)

	//var wg sync.WaitGroup
	//wg.Add(LISTPAGE)
	//for i := 1; i <= LISTPAGE; i++ {
	//	go func(i int) {
	//		runtime.Gosched()
	//		queue <- getRadioPageList(i)
	//	}(i)
	//}
	//var r []RadioListDatas
	//go func() {
	//	for v := range queue {
	//		for _, data := range v.List {
	//			r = append(r, data)
	//		}
	//		wg.Done()
	//	}
	//}()
	//wg.Wait()
	//return r
	var result []RadioListDatas

	if list, err := getRadioPageList(LISTPAGE); err == nil {
		result = list.List
	}

	return result
}

type byChannel []RadioListDatas

func (c byChannel) Len() int      { return len(c) }
func (c byChannel) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c byChannel) Less(i, j int) bool {
	a, _ := strconv.Atoi(c[i].ChannelID)
	b, _ := strconv.Atoi(c[j].ChannelID)
	return a < b
}

// GenList is to output table list.
func GenList() {
	var (
		no        int
		output    string
		radioList []RadioListDatas
	)
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 38, 0, 0, ' ', 0)
	radioList = GetRadioList()
	sort.Sort(byChannel(radioList))
	for _, data := range radioList {
		if data.IsChannel {
			output += fmt.Sprintf("%3d. [%v] %s\t", no+1, data.ChannelID, data.ChannelTitle)
			if (no+1)%3 == 0 {
				fmt.Fprintln(w, output)
				output = ""
			}
			no++
		}
	}
	fmt.Fprintln(w, output)
	w.Flush()
}

// PrintChannel is my fav channel XD.
func PrintChannel() {
	fmt.Println("[207] 中廣新聞網")
	fmt.Println("[205] 中廣流行網 i like")
	fmt.Println("[206] 中廣音樂網i radio")
	fmt.Println("[232] 飛碟電台")
	fmt.Println("[222] HitFm聯播網 Taipei 北部")
	fmt.Println("[156] KISS RADIO 大眾廣播電台")
	fmt.Println("[308] KISS RADIO 網路音樂台")
	fmt.Println("[187] NEWS98新聞網")
	fmt.Println("[370] POP Radio 台北流行廣播電台")
}
<|endoftext|>


<commit_before>package service

import (
	"bytes"
	"fmt"
	"gosaic/model"
	"sync"

	"gopkg.in/gorp.v1"
)

type PartialComparisonService interface {
	Service
	Insert(*model.PartialComparison) error
	BulkInsert([]*model.PartialComparison) (int64, error)
	Update(*model.PartialComparison) error
	Delete(*model.PartialComparison) error
	Get(int64) (*model.PartialComparison, error)
	GetOneBy(string, ...interface{}) (*model.PartialComparison, error)
	ExistsBy(string, ...interface{}) (bool, error)
	Count() (int64, error)
	CountBy(string, ...interface{}) (int64, error)
	FindAll(string, int, int, string, ...interface{}) ([]*model.PartialComparison, error)
	Find(*model.MacroPartial, *model.GidxPartial) (*model.PartialComparison, error)
	Create(*model.MacroPartial, *model.GidxPartial) (*model.PartialComparison, error)
	FindOrCreate(*model.MacroPartial, *model.GidxPartial) (*model.PartialComparison, error)
	CountMissing(macro *model.Macro) (int64, error)
	FindMissing(*model.Macro, int) ([]*model.MacroGidxView, error)
	CreateFromView(*model.MacroGidxView) (*model.PartialComparison, error)
	GetClosest(*model.MacroPartial) (int64, error)
	GetClosestMax(*model.MacroPartial, *model.Mosaic, int) (int64, error)
}

type partialComparisonServiceImpl struct {
	dbMap *gorp.DbMap
	m     sync.Mutex
}

func NewPartialComparisonService(dbMap *gorp.DbMap) PartialComparisonService {
	return &partialComparisonServiceImpl{dbMap: dbMap}
}

func (s *partialComparisonServiceImpl) DbMap() *gorp.DbMap {
	return s.dbMap
}

func (s *partialComparisonServiceImpl) Register() error {
	s.DbMap().AddTableWithName(model.PartialComparison{}, "partial_comparisons").SetKeys(true, "id")
	return nil
}

func (s *partialComparisonServiceImpl) Insert(pc *model.PartialComparison) error {
	return s.DbMap().Insert(pc)
}

func (s *partialComparisonServiceImpl) BulkInsert(partialComparisons []*model.PartialComparison) (int64, error) {
	if len(partialComparisons) == 0 {
		return int64(0), nil
	} else if len(partialComparisons) == 1 {
		return int64(1), s.Insert(partialComparisons[0])
	}

	var b bytes.Buffer

	b.WriteString("insert into partial_comparisons (id, macro_partial_id, gidx_partial_id, dist) ")
	b.WriteString(fmt.Sprintf("select null as id, %d as macro_partial_id, %d as gidx_partial_id, %f as dist",
		partialComparisons[0].MacroPartialId, partialComparisons[0].GidxPartialId, partialComparisons[0].Dist))

	for i := 1; i < len(partialComparisons); i++ {
		b.WriteString(fmt.Sprintf(" union select null, %d, %d, %f",
			partialComparisons[i].MacroPartialId, partialComparisons[i].GidxPartialId, partialComparisons[i].Dist))
	}

	// ignoring sql.Result
	res, err := s.dbMap.Db.Exec(b.String())
	if err != nil {
		return int64(0), err
	}

	rowsAffected, err := res.RowsAffected()
	if err != nil {
		return int64(0), err
	}

	return rowsAffected, nil
}

func (s *partialComparisonServiceImpl) Update(pc *model.PartialComparison) error {
	_, err := s.DbMap().Update(pc)
	return err
}

func (s *partialComparisonServiceImpl) Delete(pc *model.PartialComparison) error {
	_, err := s.DbMap().Delete(pc)
	return err
}

func (s *partialComparisonServiceImpl) Get(id int64) (*model.PartialComparison, error) {
	partialComparison, err := s.DbMap().Get(model.PartialComparison{}, id)
	if err != nil {
		return nil, err
	}

	if partialComparison == nil {
		return nil, nil
	}

	mp, ok := partialComparison.(*model.PartialComparison)
	if !ok {
		return nil, fmt.Errorf("Received struct is not a PartialComparison")
	}

	if mp.Id == int64(0) {
		return nil, nil
	}

	return mp, nil
}

func (s *partialComparisonServiceImpl) GetOneBy(conditions string, params ...interface{}) (*model.PartialComparison, error) {
	var partialComparison model.PartialComparison
	err := s.DbMap().SelectOne(&partialComparison, fmt.Sprintf("select * from partial_comparisons where %s limit 1", conditions), params...)
	if err != nil {
		return nil, err
	}

	return &partialComparison, nil
}

func (s *partialComparisonServiceImpl) ExistsBy(conditions string, params ...interface{}) (bool, error) {
	count, err := s.DbMap().SelectInt(fmt.Sprintf("select 1 from partial_comparisons where %s limit 1", conditions), params...)
	return count == 1, err
}

func (s *partialComparisonServiceImpl) Count() (int64, error) {
	return s.DbMap().SelectInt("select count(*) from partial_comparisons")
}

func (s *partialComparisonServiceImpl) CountBy(conditions string, params ...interface{}) (int64, error) {
	return s.DbMap().SelectInt(fmt.Sprintf("select count(*) from partial_comparisons where %s", conditions), params...)
}

func (s *partialComparisonServiceImpl) FindAll(order string, limit, offset int, conditions string, params ...interface{}) ([]*model.PartialComparison, error) {
	var partialComparisons []*model.PartialComparison

	sql := fmt.Sprintf("select * from partial_comparisons where %s order by %s limit %d offset %d",
		conditions, order, limit, offset)

	_, err := s.dbMap.Select(&partialComparisons, sql, params...)
	if err != nil {
		return nil, err
	}

	return partialComparisons, nil
}

func (s *partialComparisonServiceImpl) doFind(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	p := model.PartialComparison{
		MacroPartialId: macroPartial.Id,
		GidxPartialId:  gidxPartial.Id,
	}

	err := s.DbMap().SelectOne(&p, "select * from partial_comparisons where macro_partial_id = ? and gidx_partial_id = ? limit 1", p.MacroPartialId, p.GidxPartialId)
	if err != nil {
		return nil, err
	}

	if p.Id == int64(0) {
		return nil, nil
	}

	return &p, nil
}

func (s *partialComparisonServiceImpl) Find(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	s.m.Lock()
	defer s.m.Unlock()

	return s.doFind(macroPartial, gidxPartial)
}

func (s *partialComparisonServiceImpl) doCreate(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	p := model.PartialComparison{
		MacroPartialId: macroPartial.Id,
		GidxPartialId:  gidxPartial.Id,
	}

	dist, err := model.PixelDist(macroPartial, gidxPartial)
	if err != nil {
		return nil, err
	}
	p.Dist = dist

	err = s.Insert(&p)
	if err != nil {
		return nil, err
	}

	return &p, nil
}

func (s *partialComparisonServiceImpl) Create(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	s.m.Lock()
	defer s.m.Unlock()

	return s.doCreate(macroPartial, gidxPartial)
}

func (s *partialComparisonServiceImpl) FindOrCreate(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	s.m.Lock()
	defer s.m.Unlock()

	p, err := s.doFind(macroPartial, gidxPartial)
	if err == nil {
		return p, nil
	}

	// or create
	return s.doCreate(macroPartial, gidxPartial)
}

func (s *partialComparisonServiceImpl) CountMissing(macro *model.Macro) (int64, error) {
	s.m.Lock()
	defer s.m.Unlock()

	sql := `
select count(*)
from macro_partials, gidx_partials
where macro_partials.macro_id = ?
and macro_partials.aspect_id = gidx_partials.aspect_id
and not exists (
	select 1 from partial_comparisons
	where partial_comparisons.macro_partial_id = macro_partials.id
	and partial_comparisons.gidx_partial_id = gidx_partials.id
)
`

	return s.DbMap().SelectInt(sql, macro.Id)
}

func (s *partialComparisonServiceImpl) FindMissing(macro *model.Macro, limit int) ([]*model.MacroGidxView, error) {
	s.m.Lock()
	defer s.m.Unlock()

	sql := `
select macro_partials.id as macro_partial_id,
	macro_partials.macro_id,
	macro_partials.cover_partial_id,
	macro_partials.aspect_id,
	macro_partials.data as macro_partial_data,
	gidx_partials.id as gidx_partial_id,
	gidx_partials.gidx_id,
	gidx_partials.data as gidx_partial_data
from macro_partials join gidx_partials
where macro_partials.macro_id = ?
and macro_partials.aspect_id = gidx_partials.aspect_id
and not exists (
	select 1 from partial_comparisons
	where partial_comparisons.macro_partial_id = macro_partials.id
	and partial_comparisons.gidx_partial_id = gidx_partials.id
)
order by macro_partials.id asc,
	gidx_partials.id asc
limit ?
`

	var macroGidxViews []*model.MacroGidxView
	rows, err := s.dbMap.Db.Query(sql, macro.Id, limit)
	if err != nil {
		return nil, err
	}

	for rows.Next() {
		var r model.MacroGidxView = model.MacroGidxView{
			&model.MacroPartial{},
			&model.GidxPartial{},
		}
		err = rows.Scan(
			&r.MacroPartial.Id,
			&r.MacroPartial.MacroId,
			&r.MacroPartial.CoverPartialId,
			&r.MacroPartial.AspectId,
			&r.MacroPartial.Data,
			&r.GidxPartial.Id,
			&r.GidxPartial.GidxId,
			&r.GidxPartial.Data,
		)
		if err != nil {
			return nil, err
		}
		r.GidxPartial.AspectId = r.MacroPartial.AspectId
		macroGidxViews = append(macroGidxViews, &r)
	}

	return macroGidxViews, nil
}

func (s *partialComparisonServiceImpl) CreateFromView(view *model.MacroGidxView) (*model.PartialComparison, error) {
	s.m.Lock()
	defer s.m.Unlock()

	pc, err := view.PartialComparison()
	if err != nil {
		return nil, err
	}

	err = s.Insert(pc)
	if err != nil {
		return nil, err
	}

	return pc, nil
}

func (s *partialComparisonServiceImpl) GetClosest(macroPartial *model.MacroPartial) (int64, error) {
	sql := `
		select pc.gidx_partial_id
		from partial_comparisons pc
		where pc.macro_partial_id = ?
		order by pc.dist asc
		limit 1
	`
	gidxPartialId, err := s.DbMap().SelectInt(sql, macroPartial.Id)
	if err != nil {
		return int64(0), err
	}

	return gidxPartialId, nil
}

func (s *partialComparisonServiceImpl) GetClosestMax(macroPartial *model.MacroPartial, mosaic *model.Mosaic, maxRepeats int) (int64, error) {
	sql := `
		select pc.gidx_partial_id
		from partial_comparisons pc
		where pc.macro_partial_id = ?
		and not exists (
			select 1
			from mosaic_partials mos
			where mos.gidx_partial_id = pc.gidx_partial_id
			and mos.mosaic_id = ?
			group by mos.gidx_partial_id
			having count(*) >= ?
		)
		order by pc.dist asc
		limit 1
	`
	gidxPartialId, err := s.DbMap().SelectInt(sql, macroPartial.Id, mosaic.Id, maxRepeats)
	if err != nil {
		return int64(0), err
	}

	return gidxPartialId, nil
}
<commit_msg>scope closest count to gidx, not gidx partial<commit_after>package service

import (
	"bytes"
	"fmt"
	"gosaic/model"
	"sync"

	"gopkg.in/gorp.v1"
)

type PartialComparisonService interface {
	Service
	Insert(*model.PartialComparison) error
	BulkInsert([]*model.PartialComparison) (int64, error)
	Update(*model.PartialComparison) error
	Delete(*model.PartialComparison) error
	Get(int64) (*model.PartialComparison, error)
	GetOneBy(string, ...interface{}) (*model.PartialComparison, error)
	ExistsBy(string, ...interface{}) (bool, error)
	Count() (int64, error)
	CountBy(string, ...interface{}) (int64, error)
	FindAll(string, int, int, string, ...interface{}) ([]*model.PartialComparison, error)
	Find(*model.MacroPartial, *model.GidxPartial) (*model.PartialComparison, error)
	Create(*model.MacroPartial, *model.GidxPartial) (*model.PartialComparison, error)
	FindOrCreate(*model.MacroPartial, *model.GidxPartial) (*model.PartialComparison, error)
	CountMissing(macro *model.Macro) (int64, error)
	FindMissing(*model.Macro, int) ([]*model.MacroGidxView, error)
	CreateFromView(*model.MacroGidxView) (*model.PartialComparison, error)
	GetClosest(*model.MacroPartial) (int64, error)
	GetClosestMax(*model.MacroPartial, *model.Mosaic, int) (int64, error)
}

type partialComparisonServiceImpl struct {
	dbMap *gorp.DbMap
	m     sync.Mutex
}

func NewPartialComparisonService(dbMap *gorp.DbMap) PartialComparisonService {
	return &partialComparisonServiceImpl{dbMap: dbMap}
}

func (s *partialComparisonServiceImpl) DbMap() *gorp.DbMap {
	return s.dbMap
}

func (s *partialComparisonServiceImpl) Register() error {
	s.DbMap().AddTableWithName(model.PartialComparison{}, "partial_comparisons").SetKeys(true, "id")
	return nil
}

func (s *partialComparisonServiceImpl) Insert(pc *model.PartialComparison) error {
	return s.DbMap().Insert(pc)
}

func (s *partialComparisonServiceImpl) BulkInsert(partialComparisons []*model.PartialComparison) (int64, error) {
	if len(partialComparisons) == 0 {
		return int64(0), nil
	} else if len(partialComparisons) == 1 {
		return int64(1), s.Insert(partialComparisons[0])
	}

	var b bytes.Buffer

	b.WriteString("insert into partial_comparisons (id, macro_partial_id, gidx_partial_id, dist) ")
	b.WriteString(fmt.Sprintf("select null as id, %d as macro_partial_id, %d as gidx_partial_id, %f as dist",
		partialComparisons[0].MacroPartialId, partialComparisons[0].GidxPartialId, partialComparisons[0].Dist))

	for i := 1; i < len(partialComparisons); i++ {
		b.WriteString(fmt.Sprintf(" union select null, %d, %d, %f",
			partialComparisons[i].MacroPartialId, partialComparisons[i].GidxPartialId, partialComparisons[i].Dist))
	}

	// ignoring sql.Result
	res, err := s.dbMap.Db.Exec(b.String())
	if err != nil {
		return int64(0), err
	}

	rowsAffected, err := res.RowsAffected()
	if err != nil {
		return int64(0), err
	}

	return rowsAffected, nil
}

func (s *partialComparisonServiceImpl) Update(pc *model.PartialComparison) error {
	_, err := s.DbMap().Update(pc)
	return err
}

func (s *partialComparisonServiceImpl) Delete(pc *model.PartialComparison) error {
	_, err := s.DbMap().Delete(pc)
	return err
}

func (s *partialComparisonServiceImpl) Get(id int64) (*model.PartialComparison, error) {
	partialComparison, err := s.DbMap().Get(model.PartialComparison{}, id)
	if err != nil {
		return nil, err
	}

	if partialComparison == nil {
		return nil, nil
	}

	mp, ok := partialComparison.(*model.PartialComparison)
	if !ok {
		return nil, fmt.Errorf("Received struct is not a PartialComparison")
	}

	if mp.Id == int64(0) {
		return nil, nil
	}

	return mp, nil
}

func (s *partialComparisonServiceImpl) GetOneBy(conditions string, params ...interface{}) (*model.PartialComparison, error) {
	var partialComparison model.PartialComparison
	err := s.DbMap().SelectOne(&partialComparison, fmt.Sprintf("select * from partial_comparisons where %s limit 1", conditions), params...)
	if err != nil {
		return nil, err
	}

	return &partialComparison, nil
}

func (s *partialComparisonServiceImpl) ExistsBy(conditions string, params ...interface{}) (bool, error) {
	count, err := s.DbMap().SelectInt(fmt.Sprintf("select 1 from partial_comparisons where %s limit 1", conditions), params...)
	return count == 1, err
}

func (s *partialComparisonServiceImpl) Count() (int64, error) {
	return s.DbMap().SelectInt("select count(*) from partial_comparisons")
}

func (s *partialComparisonServiceImpl) CountBy(conditions string, params ...interface{}) (int64, error) {
	return s.DbMap().SelectInt(fmt.Sprintf("select count(*) from partial_comparisons where %s", conditions), params...)
}

func (s *partialComparisonServiceImpl) FindAll(order string, limit, offset int, conditions string, params ...interface{}) ([]*model.PartialComparison, error) {
	var partialComparisons []*model.PartialComparison

	sql := fmt.Sprintf("select * from partial_comparisons where %s order by %s limit %d offset %d",
		conditions, order, limit, offset)

	_, err := s.dbMap.Select(&partialComparisons, sql, params...)
	if err != nil {
		return nil, err
	}

	return partialComparisons, nil
}

func (s *partialComparisonServiceImpl) doFind(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	p := model.PartialComparison{
		MacroPartialId: macroPartial.Id,
		GidxPartialId:  gidxPartial.Id,
	}

	err := s.DbMap().SelectOne(&p, "select * from partial_comparisons where macro_partial_id = ? and gidx_partial_id = ? limit 1", p.MacroPartialId, p.GidxPartialId)
	if err != nil {
		return nil, err
	}

	if p.Id == int64(0) {
		return nil, nil
	}

	return &p, nil
}

func (s *partialComparisonServiceImpl) Find(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	s.m.Lock()
	defer s.m.Unlock()

	return s.doFind(macroPartial, gidxPartial)
}

func (s *partialComparisonServiceImpl) doCreate(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	p := model.PartialComparison{
		MacroPartialId: macroPartial.Id,
		GidxPartialId:  gidxPartial.Id,
	}

	dist, err := model.PixelDist(macroPartial, gidxPartial)
	if err != nil {
		return nil, err
	}
	p.Dist = dist

	err = s.Insert(&p)
	if err != nil {
		return nil, err
	}

	return &p, nil
}

func (s *partialComparisonServiceImpl) Create(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	s.m.Lock()
	defer s.m.Unlock()

	return s.doCreate(macroPartial, gidxPartial)
}

func (s *partialComparisonServiceImpl) FindOrCreate(macroPartial *model.MacroPartial, gidxPartial *model.GidxPartial) (*model.PartialComparison, error) {
	s.m.Lock()
	defer s.m.Unlock()

	p, err := s.doFind(macroPartial, gidxPartial)
	if err == nil {
		return p, nil
	}

	// or create
	return s.doCreate(macroPartial, gidxPartial)
}

func (s *partialComparisonServiceImpl) CountMissing(macro *model.Macro) (int64, error) {
	s.m.Lock()
	defer s.m.Unlock()

	sql := `
select count(*)
from macro_partials, gidx_partials
where macro_partials.macro_id = ?
and macro_partials.aspect_id = gidx_partials.aspect_id
and not exists (
	select 1 from partial_comparisons
	where partial_comparisons.macro_partial_id = macro_partials.id
	and partial_comparisons.gidx_partial_id = gidx_partials.id
)
`

	return s.DbMap().SelectInt(sql, macro.Id)
}

func (s *partialComparisonServiceImpl) FindMissing(macro *model.Macro, limit int) ([]*model.MacroGidxView, error) {
	s.m.Lock()
	defer s.m.Unlock()

	sql := `
select macro_partials.id as macro_partial_id,
	macro_partials.macro_id,
	macro_partials.cover_partial_id,
	macro_partials.aspect_id,
	macro_partials.data as macro_partial_data,
	gidx_partials.id as gidx_partial_id,
	gidx_partials.gidx_id,
	gidx_partials.data as gidx_partial_data
from macro_partials join gidx_partials
where macro_partials.macro_id = ?
and macro_partials.aspect_id = gidx_partials.aspect_id
and not exists (
	select 1 from partial_comparisons
	where partial_comparisons.macro_partial_id = macro_partials.id
	and partial_comparisons.gidx_partial_id = gidx_partials.id
)
order by macro_partials.id asc,
	gidx_partials.id asc
limit ?
`

	var macroGidxViews []*model.MacroGidxView
	rows, err := s.dbMap.Db.Query(sql, macro.Id, limit)
	if err != nil {
		return nil, err
	}

	for rows.Next() {
		var r model.MacroGidxView = model.MacroGidxView{
			&model.MacroPartial{},
			&model.GidxPartial{},
		}
		err = rows.Scan(
			&r.MacroPartial.Id,
			&r.MacroPartial.MacroId,
			&r.MacroPartial.CoverPartialId,
			&r.MacroPartial.AspectId,
			&r.MacroPartial.Data,
			&r.GidxPartial.Id,
			&r.GidxPartial.GidxId,
			&r.GidxPartial.Data,
		)
		if err != nil {
			return nil, err
		}
		r.GidxPartial.AspectId = r.MacroPartial.AspectId
		macroGidxViews = append(macroGidxViews, &r)
	}

	return macroGidxViews, nil
}

func (s *partialComparisonServiceImpl) CreateFromView(view *model.MacroGidxView) (*model.PartialComparison, error) {
	s.m.Lock()
	defer s.m.Unlock()

	pc, err := view.PartialComparison()
	if err != nil {
		return nil, err
	}

	err = s.Insert(pc)
	if err != nil {
		return nil, err
	}

	return pc, nil
}

func (s *partialComparisonServiceImpl) GetClosest(macroPartial *model.MacroPartial) (int64, error) {
	sql := `
		select pc.gidx_partial_id
		from partial_comparisons pc
		where pc.macro_partial_id = ?
		order by pc.dist asc
		limit 1
	`
	gidxPartialId, err := s.DbMap().SelectInt(sql, macroPartial.Id)
	if err != nil {
		return int64(0), err
	}

	return gidxPartialId, nil
}

func (s *partialComparisonServiceImpl) GetClosestMax(macroPartial *model.MacroPartial, mosaic *model.Mosaic, maxRepeats int) (int64, error) {
	sql := `
		select pc.gidx_partial_id
		from partial_comparisons pc
		where pc.macro_partial_id = ?
		and not exists (
			select 1
			from mosaic_partials mos
			inner join gidx_partials gps
			on mos.gidx_partial_id = gps.id
			where mos.gidx_partial_id = pc.gidx_partial_id
			and mos.mosaic_id = ?
			group by gps.gidx_id
			having count(*) >= ?
		)
		order by pc.dist asc
		limit 1
	`
	gidxPartialId, err := s.DbMap().SelectInt(sql, macroPartial.Id, mosaic.Id, maxRepeats)
	if err != nil {
		return int64(0), err
	}

	return gidxPartialId, nil
}
<|endoftext|>