<commit_before>package ast

import (
	"bufio"
	"bytes"
	"io"
	"regexp"
	"strings"
)

// ReadAnnotationsFromCommentry returns a slice of all annotation passed from the provided list.
func ReadAnnotationsFromCommentry(r io.Reader) []AnnotationDeclaration {
	var annotations []AnnotationDeclaration

	reader := bufio.NewReader(r)

	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			break
		}

		trimmedline := string(cleanWord([]byte(line)))
		if trimmedline == "" {
			continue
		}

		// Do we have a annotation here?
		if !strings.HasPrefix(trimmedline, "@") {
			continue
		}

		params := make(map[string]string, 0)

		if !strings.Contains(trimmedline, "(") {
			annotations = append(annotations, AnnotationDeclaration{Name: trimmedline, Params: params})
			continue
		}

		argIndex := strings.IndexRune(trimmedline, '(')
		argName := trimmedline[:argIndex]
		argContents := trimmedline[argIndex:]

		// Do we have a template associated with this annotation, if not, split the
		// commas and let those be our arguments.
		if !strings.HasSuffix(argContents, "{") {

			argContents = strings.TrimPrefix(strings.TrimSuffix(argContents, ")"), "(")

			var parts []string

			for _, part := range strings.Split(argContents, ",") {
				trimmed := strings.TrimSpace(part)
				if trimmed == "" {
					continue
				}

				parts = append(parts, trimmed)

				// If we are dealing with key value pairs then split, trimspace and set
				// in params. We only expect 2 values, any more and we wont consider the rest.
				if kvPieces := strings.Split(trimmed, "=>"); len(kvPieces) > 1 {
					params[strings.TrimSpace(kvPieces[0])] = strings.TrimSpace(kvPieces[1])
				}
			}

			annotations = append(annotations, AnnotationDeclaration{
				Arguments: parts,
				Name:      argName,
				Params:    params,
			})

			continue
		}

		templateIndex := strings.IndexRune(argContents, '{')
		templateArgs := argContents[:templateIndex]
		templateArgs = strings.TrimPrefix(strings.TrimSuffix(templateArgs, ")"), "(")

		var parts []string

		for _, part := range strings.Split(templateArgs, ",") {
			trimmed := strings.TrimSpace(part)
			if trimmed == "" {
				continue
			}

			parts = append(parts, trimmed)

			// If we are dealing with key value pairs then split, trimspace and set
			// in params. We only expect 2 values, any more and we wont consider the rest.
			if kvPieces := strings.Split(trimmed, "=>"); len(kvPieces) > 1 {
				params[strings.TrimSpace(kvPieces[0])] = strings.TrimSpace(kvPieces[1])
			}
		}

		template := strings.TrimSpace(readTemplate(reader))

		annotations = append(annotations, AnnotationDeclaration{
			Arguments: parts,
			Name:      argName,
			Template:  template,
			Params:    params,
		})

	}

	return annotations
}

var ending = []byte("})")
var newline = []byte("\n")
var empty = []byte("")
var singleComment = []byte("//")
var multiComment = []byte("/*")
var multiCommentItem = []byte("*")
var commentry = regexp.MustCompile(`\s*?([\/\/*|\*|\/]+)`)

func readTemplate(reader *bufio.Reader) string {
	var bu bytes.Buffer

	var seenEnd bool

	for {
		// Do we have another pending prefix, if so, we are at the ending, so return.
		if seenEnd {
			data, _ := reader.Peek(100)
			dataVal := commentry.ReplaceAllString(string(data), "")
			dataVal = string(cleanWord([]byte(dataVal)))

			// fmt.Printf("Peek2: %+q -> %+q\n", dataVal, data)

			if strings.HasPrefix(string(dataVal), "@") {
				return bu.String()
			}

			// If it's all space, then return.
			if strings.TrimSpace(string(dataVal)) == "" {
				return bu.String()
			}
		}

		twoWord, err := reader.ReadString('\n')
		if err != nil {
			bu.WriteString(twoWord)
			return bu.String()
		}

		twoWorded := cleanWord([]byte(twoWord))
		// fmt.Printf("Ending: %+q -> %t\n", twoWorded, bytes.HasPrefix(twoWorded, ending))

		if bytes.HasPrefix(twoWorded, ending) {
			seenEnd = true
			continue
		}

		bu.WriteString(twoWord)
	}

	return bu.String()
}

func cleanWord(word []byte) []byte {
	word = bytes.TrimSpace(word)
	word = bytes.TrimPrefix(word, singleComment)
	word = bytes.TrimPrefix(word, multiComment)
	word = bytes.TrimPrefix(word, multiCommentItem)
	return bytes.TrimSpace(word)
}
<commit_msg>Return from seenEnd immediately<commit_after>package ast

import (
	"bufio"
	"bytes"
	"io"
	"regexp"
	"strings"
)

// ReadAnnotationsFromCommentry returns a slice of all annotation passed from the provided list.
func ReadAnnotationsFromCommentry(r io.Reader) []AnnotationDeclaration {
	var annotations []AnnotationDeclaration

	reader := bufio.NewReader(r)

	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			break
		}

		trimmedline := string(cleanWord([]byte(line)))
		if trimmedline == "" {
			continue
		}

		// Do we have a annotation here?
		if !strings.HasPrefix(trimmedline, "@") {
			continue
		}

		params := make(map[string]string, 0)

		if !strings.Contains(trimmedline, "(") {
			annotations = append(annotations, AnnotationDeclaration{Name: trimmedline, Params: params})
			continue
		}

		argIndex := strings.IndexRune(trimmedline, '(')
		argName := trimmedline[:argIndex]
		argContents := trimmedline[argIndex:]

		// Do we have a template associated with this annotation, if not, split the
		// commas and let those be our arguments.
		if !strings.HasSuffix(argContents, "{") {

			argContents = strings.TrimPrefix(strings.TrimSuffix(argContents, ")"), "(")

			var parts []string

			for _, part := range strings.Split(argContents, ",") {
				trimmed := strings.TrimSpace(part)
				if trimmed == "" {
					continue
				}

				parts = append(parts, trimmed)

				// If we are dealing with key value pairs then split, trimspace and set
				// in params. We only expect 2 values, any more and we wont consider the rest.
				if kvPieces := strings.Split(trimmed, "=>"); len(kvPieces) > 1 {
					params[strings.TrimSpace(kvPieces[0])] = strings.TrimSpace(kvPieces[1])
				}
			}

			annotations = append(annotations, AnnotationDeclaration{
				Arguments: parts,
				Name:      argName,
				Params:    params,
			})

			continue
		}

		templateIndex := strings.IndexRune(argContents, '{')
		templateArgs := argContents[:templateIndex]
		templateArgs = strings.TrimPrefix(strings.TrimSuffix(templateArgs, ")"), "(")

		var parts []string

		for _, part := range strings.Split(templateArgs, ",") {
			trimmed := strings.TrimSpace(part)
			if trimmed == "" {
				continue
			}

			parts = append(parts, trimmed)

			// If we are dealing with key value pairs then split, trimspace and set
			// in params. We only expect 2 values, any more and we wont consider the rest.
			if kvPieces := strings.Split(trimmed, "=>"); len(kvPieces) > 1 {
				params[strings.TrimSpace(kvPieces[0])] = strings.TrimSpace(kvPieces[1])
			}
		}

		template := strings.TrimSpace(readTemplate(reader))

		annotations = append(annotations, AnnotationDeclaration{
			Arguments: parts,
			Name:      argName,
			Template:  template,
			Params:    params,
		})

	}

	return annotations
}

var ending = []byte("})")
var newline = []byte("\n")
var empty = []byte("")
var singleComment = []byte("//")
var multiComment = []byte("/*")
var multiCommentItem = []byte("*")
var commentry = regexp.MustCompile(`\s*?([\/\/*|\*|\/]+)`)

func readTemplate(reader *bufio.Reader) string {
	var bu bytes.Buffer

	var seenEnd bool

	for {
		// Do we have another pending prefix, if so, we are at the ending, so return.
		if seenEnd {
			data, _ := reader.Peek(100)
			dataVal := commentry.ReplaceAllString(string(data), "")
			dataVal = string(cleanWord([]byte(dataVal)))

			// fmt.Printf("Peek2: %+q -> %+q\n", dataVal, data)

			if strings.HasPrefix(string(dataVal), "@") {
				return bu.String()
			}

			// If it's all space, then return.
			// if strings.TrimSpace(string(dataVal)) == "" {
			return bu.String()
			// }
		}

		twoWord, err := reader.ReadString('\n')
		if err != nil {
			bu.WriteString(twoWord)
			return bu.String()
		}

		twoWorded := cleanWord([]byte(twoWord))
		// fmt.Printf("Ending: %+q -> %t\n", twoWorded, bytes.HasPrefix(twoWorded, ending))

		if bytes.HasPrefix(twoWorded, ending) {
			seenEnd = true
			continue
		}

		bu.WriteString(twoWord)
	}

	return bu.String()
}

func cleanWord(word []byte) []byte {
	word = bytes.TrimSpace(word)
	word = bytes.TrimPrefix(word, singleComment)
	word = bytes.TrimPrefix(word, multiComment)
	word = bytes.TrimPrefix(word, multiCommentItem)
	return bytes.TrimSpace(word)
}
<|endoftext|>


<commit_before>package peer

import (
	"bazil.org/bazil/db"
	"bazil.org/bazil/peer"
	"bazil.org/bazil/peer/wire"
	"bazil.org/bazil/server"
	"bazil.org/bazil/util/grpcedtls"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

func (p *peers) auth(ctx context.Context) (*peer.PublicKey, error) {
	pubEd, ok := grpcedtls.FromContext(ctx)
	if !ok {
		return nil, grpc.Errorf(codes.Unauthenticated, "unauthenticated")
	}
	pub := (*peer.PublicKey)(pubEd)
	getPeer := func(tx *db.Tx) error {
		_, err := tx.Peers().Get(pub)
		return err
	}
	if err := p.app.DB.View(getPeer); err != nil {
		if err == db.ErrPeerNotFound {
			return nil, grpc.Errorf(codes.PermissionDenied, "permission denied")
		}
		return nil, err
	}
	return pub, nil
}

type peers struct {
	app *server.App
}

func New(app *server.App) *grpc.Server {
	auth := &grpcedtls.Authenticator{
		Config: app.GetTLSConfig,
		// TODO Lookup:
	}
	srv := grpc.NewServer(
		grpc.WithServerTransportAuthenticator(auth),
	)
	rpc := &peers{app: app}
	wire.RegisterPeerServer(srv, rpc)
	return srv
}
<commit_msg>server/peer: Adjust to gRPC changes, use Creds<commit_after>package peer

import (
	"bazil.org/bazil/db"
	"bazil.org/bazil/peer"
	"bazil.org/bazil/peer/wire"
	"bazil.org/bazil/server"
	"bazil.org/bazil/util/grpcedtls"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

func (p *peers) auth(ctx context.Context) (*peer.PublicKey, error) {
	pubEd, ok := grpcedtls.FromContext(ctx)
	if !ok {
		return nil, grpc.Errorf(codes.Unauthenticated, "unauthenticated")
	}
	pub := (*peer.PublicKey)(pubEd)
	getPeer := func(tx *db.Tx) error {
		_, err := tx.Peers().Get(pub)
		return err
	}
	if err := p.app.DB.View(getPeer); err != nil {
		if err == db.ErrPeerNotFound {
			return nil, grpc.Errorf(codes.PermissionDenied, "permission denied")
		}
		return nil, err
	}
	return pub, nil
}

type peers struct {
	app *server.App
}

func New(app *server.App) *grpc.Server {
	auth := &grpcedtls.Authenticator{
		Config: app.GetTLSConfig,
		// TODO Lookup:
	}
	srv := grpc.NewServer(
		grpc.Creds(auth),
	)
	rpc := &peers{app: app}
	wire.RegisterPeerServer(srv, rpc)
	return srv
}
<|endoftext|>


<commit_before>package registry

import (
	"github.com/dotcloud/docker/utils"
	"strings"
	"testing"
)

var (
	IMAGE_ID = "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d"
	TOKEN    = []string{"fake-token"}
	REPO     = "foo42/bar"
)

func spawnTestRegistry(t *testing.T) *Registry {
	authConfig := &AuthConfig{}
	r, err := NewRegistry(authConfig, utils.NewHTTPRequestFactory(), makeURL("/v1/"))
	if err != nil {
		t.Fatal(err)
	}
	return r
}

func TestPingRegistryEndpoint(t *testing.T) {
	standalone, err := pingRegistryEndpoint(makeURL("/v1/"))
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, standalone, true, "Expected standalone to be true (default)")
}

func TestGetRemoteHistory(t *testing.T) {
	r := spawnTestRegistry(t)
	hist, err := r.GetRemoteHistory(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(hist), 2, "Expected 2 images in history")
	assertEqual(t, hist[0], IMAGE_ID, "Expected "+IMAGE_ID+"as first ancestry")
	assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
		"Unexpected second ancestry")
}

func TestLookupRemoteImage(t *testing.T) {
	r := spawnTestRegistry(t)
	found := r.LookupRemoteImage(IMAGE_ID, makeURL("/v1/"), TOKEN)
	assertEqual(t, found, true, "Expected remote lookup to succeed")
	found = r.LookupRemoteImage("abcdef", makeURL("/v1/"), TOKEN)
	assertEqual(t, found, false, "Expected remote lookup to fail")
}

func TestGetRemoteImageJSON(t *testing.T) {
	r := spawnTestRegistry(t)
	json, size, err := r.GetRemoteImageJSON(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, size, 154, "Expected size 154")
	if len(json) <= 0 {
		t.Fatal("Expected non-empty json")
	}

	_, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"), TOKEN)
	if err == nil {
		t.Fatal("Expected image not found error")
	}
}

func TestGetRemoteImageLayer(t *testing.T) {
	r := spawnTestRegistry(t)
	data, err := r.GetRemoteImageLayer(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	if data == nil {
		t.Fatal("Expected non-nil data result")
	}

	_, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), TOKEN)
	if err == nil {
		t.Fatal("Expected image not found error")
	}
}

func TestGetRemoteTags(t *testing.T) {
	r := spawnTestRegistry(t)
	tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO, TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(tags), 1, "Expected one tag")
	assertEqual(t, tags["latest"], IMAGE_ID, "Expected tag latest to map to "+IMAGE_ID)

	_, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz", TOKEN)
	if err == nil {
		t.Fatal("Expected error when fetching tags for bogus repo")
	}
}

func TestGetRepositoryData(t *testing.T) {
	r := spawnTestRegistry(t)
	data, err := r.GetRepositoryData("foo42/bar")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList")
	assertEqual(t, len(data.Endpoints), 1, "Expected one endpoint in Endpoints")
}

func TestPushImageJSONRegistry(t *testing.T) {
	r := spawnTestRegistry(t)
	imgData := &ImgData{
		ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
		Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
	}

	err := r.PushImageJSONRegistry(imgData, []byte{0x42, 0xdf, 0x0}, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
}

func TestPushImageLayerRegistry(t *testing.T) {
	r := spawnTestRegistry(t)
	layer := strings.NewReader("")
	_, _, err := r.PushImageLayerRegistry(IMAGE_ID, layer, makeURL("/v1/"), TOKEN, []byte{})
	if err != nil {
		t.Fatal(err)
	}
}

func TestResolveRepositoryName(t *testing.T) {
	_, _, err := ResolveRepositoryName("https://github.com/dotcloud/docker")
	assertEqual(t, err, ErrInvalidRepositoryName, "Expected error invalid repo name")
	ep, repo, err := ResolveRepositoryName("fooo/bar")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, IndexServerAddress(), "Expected endpoint to be index server address")
	assertEqual(t, repo, "fooo/bar", "Expected resolved repo to be foo/bar")

	u := makeURL("")[7:]
	ep, repo, err = ResolveRepositoryName(u + "/private/moonbase")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, u, "Expected endpoint to be "+u)
	assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase")
}

func TestPushRegistryTag(t *testing.T) {
	r := spawnTestRegistry(t)
	err := r.PushRegistryTag("foo42/bar", IMAGE_ID, "stable", makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
}

func TestPushImageJSONIndex(t *testing.T) {
	r := spawnTestRegistry(t)
	imgData := []*ImgData{
		{
			ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
			Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
		},
		{
			ID:       "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
			Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
		},
	}
	repoData, err := r.PushImageJSONIndex("foo42/bar", imgData, false, nil)
	if err != nil {
		t.Fatal(err)
	}
	if repoData == nil {
		t.Fatal("Expected RepositoryData object")
	}
	repoData, err = r.PushImageJSONIndex("foo42/bar", imgData, true, []string{r.indexEndpoint})
	if err != nil {
		t.Fatal(err)
	}
	if repoData == nil {
		t.Fatal("Expected RepositoryData object")
	}
}

func TestSearchRepositories(t *testing.T) {
	r := spawnTestRegistry(t)
	results, err := r.SearchRepositories("supercalifragilisticepsialidocious")
	if err != nil {
		t.Fatal(err)
	}
	if results == nil {
		t.Fatal("Expected non-nil SearchResults object")
	}
	assertEqual(t, results.NumResults, 0, "Expected 0 search results")
}

func TestValidRepositoryName(t *testing.T) {
	if err := validateRepositoryName("docker/docker"); err != nil {
		t.Fatal(err)
	}
	if err := validateRepositoryName("docker/Docker"); err == nil {
		t.Log("Repository name should be invalid")
		t.Fail()
	}
}
<commit_msg>static_registry: update the test for the new struct<commit_after>package registry

import (
	"github.com/dotcloud/docker/utils"
	"strings"
	"testing"
)

var (
	IMAGE_ID = "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d"
	TOKEN    = []string{"fake-token"}
	REPO     = "foo42/bar"
)

func spawnTestRegistry(t *testing.T) *Registry {
	authConfig := &AuthConfig{}
	r, err := NewRegistry(authConfig, utils.NewHTTPRequestFactory(), makeURL("/v1/"))
	if err != nil {
		t.Fatal(err)
	}
	return r
}

func TestPingRegistryEndpoint(t *testing.T) {
	regInfo, err := pingRegistryEndpoint(makeURL("/v1/"))
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, regInfo.Standalone, true, "Expected standalone to be true (default)")
}

func TestGetRemoteHistory(t *testing.T) {
	r := spawnTestRegistry(t)
	hist, err := r.GetRemoteHistory(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(hist), 2, "Expected 2 images in history")
	assertEqual(t, hist[0], IMAGE_ID, "Expected "+IMAGE_ID+"as first ancestry")
	assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
		"Unexpected second ancestry")
}

func TestLookupRemoteImage(t *testing.T) {
	r := spawnTestRegistry(t)
	found := r.LookupRemoteImage(IMAGE_ID, makeURL("/v1/"), TOKEN)
	assertEqual(t, found, true, "Expected remote lookup to succeed")
	found = r.LookupRemoteImage("abcdef", makeURL("/v1/"), TOKEN)
	assertEqual(t, found, false, "Expected remote lookup to fail")
}

func TestGetRemoteImageJSON(t *testing.T) {
	r := spawnTestRegistry(t)
	json, size, err := r.GetRemoteImageJSON(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, size, 154, "Expected size 154")
	if len(json) <= 0 {
		t.Fatal("Expected non-empty json")
	}

	_, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"), TOKEN)
	if err == nil {
		t.Fatal("Expected image not found error")
	}
}

func TestGetRemoteImageLayer(t *testing.T) {
	r := spawnTestRegistry(t)
	data, err := r.GetRemoteImageLayer(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	if data == nil {
		t.Fatal("Expected non-nil data result")
	}

	_, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), TOKEN)
	if err == nil {
		t.Fatal("Expected image not found error")
	}
}

func TestGetRemoteTags(t *testing.T) {
	r := spawnTestRegistry(t)
	tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO, TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(tags), 1, "Expected one tag")
	assertEqual(t, tags["latest"], IMAGE_ID, "Expected tag latest to map to "+IMAGE_ID)

	_, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz", TOKEN)
	if err == nil {
		t.Fatal("Expected error when fetching tags for bogus repo")
	}
}

func TestGetRepositoryData(t *testing.T) {
	r := spawnTestRegistry(t)
	data, err := r.GetRepositoryData("foo42/bar")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList")
	assertEqual(t, len(data.Endpoints), 1, "Expected one endpoint in Endpoints")
}

func TestPushImageJSONRegistry(t *testing.T) {
	r := spawnTestRegistry(t)
	imgData := &ImgData{
		ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
		Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
	}

	err := r.PushImageJSONRegistry(imgData, []byte{0x42, 0xdf, 0x0}, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
}

func TestPushImageLayerRegistry(t *testing.T) {
	r := spawnTestRegistry(t)
	layer := strings.NewReader("")
	_, _, err := r.PushImageLayerRegistry(IMAGE_ID, layer, makeURL("/v1/"), TOKEN, []byte{})
	if err != nil {
		t.Fatal(err)
	}
}

func TestResolveRepositoryName(t *testing.T) {
	_, _, err := ResolveRepositoryName("https://github.com/dotcloud/docker")
	assertEqual(t, err, ErrInvalidRepositoryName, "Expected error invalid repo name")
	ep, repo, err := ResolveRepositoryName("fooo/bar")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, IndexServerAddress(), "Expected endpoint to be index server address")
	assertEqual(t, repo, "fooo/bar", "Expected resolved repo to be foo/bar")

	u := makeURL("")[7:]
	ep, repo, err = ResolveRepositoryName(u + "/private/moonbase")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, u, "Expected endpoint to be "+u)
	assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase")
}

func TestPushRegistryTag(t *testing.T) {
	r := spawnTestRegistry(t)
	err := r.PushRegistryTag("foo42/bar", IMAGE_ID, "stable", makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
}

func TestPushImageJSONIndex(t *testing.T) {
	r := spawnTestRegistry(t)
	imgData := []*ImgData{
		{
			ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
			Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
		},
		{
			ID:       "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
			Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
		},
	}
	repoData, err := r.PushImageJSONIndex("foo42/bar", imgData, false, nil)
	if err != nil {
		t.Fatal(err)
	}
	if repoData == nil {
		t.Fatal("Expected RepositoryData object")
	}
	repoData, err = r.PushImageJSONIndex("foo42/bar", imgData, true, []string{r.indexEndpoint})
	if err != nil {
		t.Fatal(err)
	}
	if repoData == nil {
		t.Fatal("Expected RepositoryData object")
	}
}

func TestSearchRepositories(t *testing.T) {
	r := spawnTestRegistry(t)
	results, err := r.SearchRepositories("supercalifragilisticepsialidocious")
	if err != nil {
		t.Fatal(err)
	}
	if results == nil {
		t.Fatal("Expected non-nil SearchResults object")
	}
	assertEqual(t, results.NumResults, 0, "Expected 0 search results")
}

func TestValidRepositoryName(t *testing.T) {
	if err := validateRepositoryName("docker/docker"); err != nil {
		t.Fatal(err)
	}
	if err := validateRepositoryName("docker/Docker"); err == nil {
		t.Log("Repository name should be invalid")
		t.Fail()
	}
}
<|endoftext|>


<commit_before>// This file is part of Ringot.
/*
Copyright 2016 tSU-RooT <tsu.root@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"github.com/ChimeraCoder/anaconda"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"strings"
	"time"
)

type tweetview struct {
	tweets         []tweetstatus
	cursorPosition int
	scroll         int
	scrollOffset   int
}

func newTweetview() *tweetview {
	return &tweetview{
		tweets: []tweetstatus{tweetstatus{ReloadMark: true}},
	}
}

func (tv *tweetview) isEmpty() bool {
	if len(tv.tweets) == 0 {
		return true
	} else if (tv.tweets[0].ReloadMark || tv.tweets[0].Empty) && len(tv.tweets) == 1 {
		return true
	}
	return false
}

func (tv *tweetview) cursorDown() {
	_, h := getTermSize()
	if tv.cursorPosition+1 < len(tv.tweets) {
		tv.cursorPosition++
		sum := 0
		tweets := tv.tweets[:tv.cursorPosition+1]
		for _, t := range tweets {
			sum += t.countLines()
		}
		sub := (sum - (tv.scroll - tv.scrollOffset)) - (h - 2)
		if sub >= 0 {
			tv.scroll += sub
		}
	}
}

func (tv *tweetview) cursorUp() {
	if tv.cursorPosition > 0 {
		tv.cursorPosition--
		sum := 0
		tweets := tv.tweets[:tv.cursorPosition]
		for _, t := range tweets {
			sum += t.countLines()
		}
		sub := sum - tv.scroll
		if sub <= 0 {
			tv.scroll += sub
			if tv.scroll < 0 {
				tv.scroll = 0
			}
		}
	}
}

func (tv *tweetview) cursorMoveToTop() {
	tv.cursorPosition = 0
	tv.scroll = 0
}

func (tv *tweetview) cursorMoveToBottom() {
	_, height := getTermSize()
	tv.cursorPosition = len(tv.tweets) - 1

	sum := 0
	for _, t := range tv.tweets {
		sum += t.countLines()
	}
	tv.scroll = sum - (height - 2 - tv.scrollOffset)
}

func (tv *tweetview) addNewTweet(tss []tweetstatus) {
	if len(tv.tweets) > 1 {
		tv.scroll += sumTweetLines(tss)
		tv.cursorPosition += len(tss)
	}
	tv.tweets = append(tss, tv.tweets...)
}

func (tv *tweetview) addIntervalTweet(tss []tweetstatus) {
	adjustScroll := false
	if tv.tweets[tv.cursorPosition].ReloadMark {
		adjustScroll = true
	}

	i := 0
	for i = range tv.tweets {
		if tv.tweets[i].ReloadMark {
			break
		}
	}
	tweets := tv.tweets[:i]
	if tweets[len(tweets)-1].Content.Id == tss[0].Content.Id {
		tss = tss[1:]
	}
	t := append(tweets, tss...)
	t = append(t, tweetstatus{ReloadMark: true})
	tv.tweets = t
	if adjustScroll {
		tv.cursorPosition--
		tv.cursorDown()
	}
}

const (
	reloadText = " ⟳ Reload"
)

func (tv *tweetview) draw() {
	width, height := getTermSize()
	y := -(tv.scroll - tv.scrollOffset)

	index := 0
	now := time.Now()

	tweets := tv.tweets

	for ; index < len(tweets); index++ {
		tweetstatus := tweets[index]
		countLine := tweetstatus.countLines()
		if y > height {
			break
		} else if y+countLine < 0 {
			y += countLine
			continue
		}
		bgColor := ColorBackground
		cursorColor := ColorBackground
		selected := index == tv.cursorPosition
		if selected {
			cursorColor = ColorGray3
		}

		if tweetstatus.ReloadMark {
			if selected {
				drawText(reloadText, 0, y, ColorWhite, ColorGray1)
			} else {
				drawText(reloadText, 0, y, ColorWhite, bgColor)
			}
			y++
			continue
		}
		tweet := tweetstatus.Content
		favorited := tweet.Favorited
		retweeted := tweet.Retweeted
		retweetedBy := ""
		labelColor := generateLabelColorByUserID(tweet.User.Id)
		var retweetColor termbox.Attribute
		if tweet.RetweetedStatus != nil {
			retweetedBy = tweet.User.ScreenName
			retweetColor = labelColor
			tweet = tweet.RetweetedStatus
			labelColor = ColorPink
		}
		text := tweet.Text

		x := 0
		drawText(" ", x, y, ColorBackground, labelColor)
		// Draw Name
		x = 1
		drawText(" ", x, y, ColorBackground, cursorColor)
		x = 2
		drawText("@"+tweet.User.ScreenName, x, y, labelColor, bgColor)
		x += runewidth.StringWidth("@"+tweet.User.ScreenName) + 1
		drawText(tweet.User.Name, x, y, ColorWhite, bgColor)
		x += runewidth.StringWidth(tweet.User.Name) + 1
		if favorited {
			drawText("★", x, y, ColorYellow, bgColor)
			x += runewidth.StringWidth("★") + 1
		}
		if retweeted {
			drawText("RT", x, y, ColorGreen, ColorLowlight)
			x += runewidth.StringWidth("RT") + 1
		}
		if retweetedBy != "" {
			t := "ReTweeted By "
			drawText(t, x, y, ColorRed, bgColor)
			x += runewidth.StringWidth(t)
			t = "@" + retweetedBy
			drawText(t, x, y, retweetColor, bgColor)
		}
		y++

		lines := strings.Split(runewidth.Wrap(text, width-2), "\n")
		for i, t := range lines {
			drawText(" ", 0, y+i, ColorBackground, labelColor)
			drawText(" ", 1, y+i, ColorWhite, cursorColor)
			drawTextWithAutoNotice(t, 2, y+i, ColorWhite, bgColor)
		}
		y += len(lines)

		// Draw Tweet Detail
		createdAtTime, err := tweet.CreatedAtTime()
		if err != nil {
			continue
		}
		sub := now.Sub(createdAtTime)
		var strTime string
		if sub <= time.Second*30 {
			strTime = "now"
		} else if sub <= time.Minute*5 {
			strTime = "A few minutes ago"
		} else if sub <= time.Hour*2 {
			m := sub / time.Minute
			strTime = fmt.Sprintf("%d minutes ago", m)
		} else if sub <= time.Hour*36 {
			h := sub / time.Hour
			strTime = fmt.Sprintf("%d hours ago", h)
		} else {
			strTime = fmt.Sprintf("%d/%d/%d", createdAtTime.Year(), createdAtTime.Month(), createdAtTime.Day())
		}

		drawText(" ", 0, y, ColorBackground, labelColor)
		x = 1
		drawText(" "+strTime, x, y, ColorGray3, cursorColor)
		x = 2
		drawText(strTime, x, y, ColorGray1, bgColor)
		x += 1 + runewidth.StringWidth(strTime)
		if tweet.RetweetCount > 0 {
			strRT := fmt.Sprintf("RT %d", tweet.RetweetCount)
			drawText(" "+strRT, x, y, ColorGreen, bgColor)
			x += 1 + runewidth.StringWidth(strRT)
		}
		if tweet.FavoriteCount > 0 {
			strFav := fmt.Sprintf("Fav %d", tweet.FavoriteCount)
			drawText(" "+strFav, x, y, ColorYellow, bgColor)
			x += 1 + runewidth.StringWidth(strFav)
		}

		y++

	}
}

func (tv *tweetview) resetScroll() {
	sum := 0
	_, h := getTermSize()
	var tweets []tweetstatus
	tweets = tv.tweets[:tv.cursorPosition]

	for _, t := range tweets {
		sum += t.countLines()
	}
	sub := sum - tv.scroll
	if sub <= 0 {
		tv.scroll = sum
	} else {
		cl := tv.tweets[tv.cursorPosition].countLines()
		sub = (sum + cl - (tv.scroll - tv.scrollOffset)) - (h - 2)
		if sub >= 0 {
			tv.scroll = sum + -(h - 2 - cl)
		}
	}

}

type tweetstatus struct {
	Content    *anaconda.Tweet
	ReloadMark bool
	Empty      bool
}

func (status *tweetstatus) countLines() int {
	if status.Empty {
		return 0
	} else if status.ReloadMark {
		return 1
	}
	w, _ := getTermSize()
	tweet := status.Content
	if tweet.RetweetedStatus != nil {
		tweet = tweet.RetweetedStatus
	}
	text := tweet.Text
	lines := strings.Split(runewidth.Wrap(text, w-2), "\n")
	lineCount := 1 + len(lines) + 1
	return lineCount
}

func (status *tweetstatus) isFavorited() bool {
	if status.Content != nil {
		return status.Content.Favorited
	}
	return false
}
func (status *tweetstatus) setFavorited(b bool) {
	if status.Content != nil {
		status.Content.Favorited = b
	}
}

func (status *tweetstatus) isRetweeted() bool {
	if status.Content != nil {
		return status.Content.Retweeted
	}
	return false
}

func (status *tweetstatus) setRetweeted(b bool) {
	if status.Content != nil {
		status.Content.Retweeted = b
	}
}
<commit_msg>Modify countLines<commit_after>// This file is part of Ringot.
/*
Copyright 2016 tSU-RooT <tsu.root@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"github.com/ChimeraCoder/anaconda"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"strings"
	"time"
)

type tweetview struct {
	tweets         []tweetstatus
	cursorPosition int
	scroll         int
	scrollOffset   int
}

func newTweetview() *tweetview {
	return &tweetview{
		tweets: []tweetstatus{tweetstatus{ReloadMark: true}},
	}
}

func (tv *tweetview) isEmpty() bool {
	if len(tv.tweets) == 0 {
		return true
	} else if (tv.tweets[0].ReloadMark || tv.tweets[0].Empty) && len(tv.tweets) == 1 {
		return true
	}
	return false
}

func (tv *tweetview) cursorDown() {
	_, h := getTermSize()
	if tv.cursorPosition+1 < len(tv.tweets) {
		tv.cursorPosition++
		sum := 0
		tweets := tv.tweets[:tv.cursorPosition+1]
		for _, t := range tweets {
			sum += t.countLines()
		}
		sub := (sum - (tv.scroll - tv.scrollOffset)) - (h - 2)
		if sub >= 0 {
			tv.scroll += sub
		}
	}
}

func (tv *tweetview) cursorUp() {
	if tv.cursorPosition > 0 {
		tv.cursorPosition--
		sum := 0
		tweets := tv.tweets[:tv.cursorPosition]
		for _, t := range tweets {
			sum += t.countLines()
		}
		sub := sum - tv.scroll
		if sub <= 0 {
			tv.scroll += sub
			if tv.scroll < 0 {
				tv.scroll = 0
			}
		}
	}
}

func (tv *tweetview) cursorMoveToTop() {
	tv.cursorPosition = 0
	tv.scroll = 0
}

func (tv *tweetview) cursorMoveToBottom() {
	_, height := getTermSize()
	tv.cursorPosition = len(tv.tweets) - 1

	sum := 0
	for _, t := range tv.tweets {
		sum += t.countLines()
	}
	tv.scroll = sum - (height - 2 - tv.scrollOffset)
}

func (tv *tweetview) addNewTweet(tss []tweetstatus) {
	if len(tv.tweets) > 1 {
		tv.scroll += sumTweetLines(tss)
		tv.cursorPosition += len(tss)
	}
	tv.tweets = append(tss, tv.tweets...)
}

func (tv *tweetview) addIntervalTweet(tss []tweetstatus) {
	adjustScroll := false
	if tv.tweets[tv.cursorPosition].ReloadMark {
		adjustScroll = true
	}

	i := 0
	for i = range tv.tweets {
		if tv.tweets[i].ReloadMark {
			break
		}
	}
	tweets := tv.tweets[:i]
	if tweets[len(tweets)-1].Content.Id == tss[0].Content.Id {
		tss = tss[1:]
	}
	t := append(tweets, tss...)
	t = append(t, tweetstatus{ReloadMark: true})
	tv.tweets = t
	if adjustScroll {
		tv.cursorPosition--
		tv.cursorDown()
	}
}

const (
	reloadText = " ⟳ Reload"
)

func (tv *tweetview) draw() {
	width, height := getTermSize()
	y := -(tv.scroll - tv.scrollOffset)

	index := 0
	now := time.Now()

	tweets := tv.tweets

	for ; index < len(tweets); index++ {
		tweetstatus := tweets[index]
		countLine := tweetstatus.countLines()
		if y > height {
			break
		} else if y+countLine < 0 {
			y += countLine
			continue
		}
		bgColor := ColorBackground
		cursorColor := ColorBackground
		selected := index == tv.cursorPosition
		if selected {
			cursorColor = ColorGray3
		}

		if tweetstatus.ReloadMark {
			if selected {
				drawText(reloadText, 0, y, ColorWhite, ColorGray1)
			} else {
				drawText(reloadText, 0, y, ColorWhite, bgColor)
			}
			y++
			continue
		}
		tweet := tweetstatus.Content
		favorited := tweet.Favorited
		retweeted := tweet.Retweeted
		retweetedBy := ""
		labelColor := generateLabelColorByUserID(tweet.User.Id)
		var retweetColor termbox.Attribute
		if tweet.RetweetedStatus != nil {
			retweetedBy = tweet.User.ScreenName
			retweetColor = labelColor
			tweet = tweet.RetweetedStatus
			labelColor = ColorPink
		}
		text := tweet.Text

		x := 0
		drawText(" ", x, y, ColorBackground, labelColor)
		// Draw Name
		x = 1
		drawText(" ", x, y, ColorBackground, cursorColor)
		x = 2
		drawText("@"+tweet.User.ScreenName, x, y, labelColor, bgColor)
		x += runewidth.StringWidth("@"+tweet.User.ScreenName) + 1
		drawText(tweet.User.Name, x, y, ColorWhite, bgColor)
		x += runewidth.StringWidth(tweet.User.Name) + 1
		if favorited {
			drawText("★", x, y, ColorYellow, bgColor)
			x += runewidth.StringWidth("★") + 1
		}
		if retweeted {
			drawText("RT", x, y, ColorGreen, ColorLowlight)
			x += runewidth.StringWidth("RT") + 1
		}
		if retweetedBy != "" {
			t := "ReTweeted By "
			drawText(t, x, y, ColorRed, bgColor)
			x += runewidth.StringWidth(t)
			t = "@" + retweetedBy
			drawText(t, x, y, retweetColor, bgColor)
		}
		y++

		lines := strings.Split(runewidth.Wrap(text, width-2), "\n")
		for i, t := range lines {
			drawText(" ", 0, y+i, ColorBackground, labelColor)
			drawText(" ", 1, y+i, ColorWhite, cursorColor)
			drawTextWithAutoNotice(t, 2, y+i, ColorWhite, bgColor)
		}
		y += len(lines)

		// Draw Tweet Detail
		createdAtTime, err := tweet.CreatedAtTime()
		if err != nil {
			continue
		}
		sub := now.Sub(createdAtTime)
		var strTime string
		if sub <= time.Second*30 {
			strTime = "now"
		} else if sub <= time.Minute*5 {
			strTime = "A few minutes ago"
		} else if sub <= time.Hour*2 {
			m := sub / time.Minute
			strTime = fmt.Sprintf("%d minutes ago", m)
		} else if sub <= time.Hour*36 {
			h := sub / time.Hour
			strTime = fmt.Sprintf("%d hours ago", h)
		} else {
			strTime = fmt.Sprintf("%d/%d/%d", createdAtTime.Year(), createdAtTime.Month(), createdAtTime.Day())
		}

		drawText(" ", 0, y, ColorBackground, labelColor)
		x = 1
		drawText(" "+strTime, x, y, ColorGray3, cursorColor)
		x = 2
		drawText(strTime, x, y, ColorGray1, bgColor)
		x += 1 + runewidth.StringWidth(strTime)
		if tweet.RetweetCount > 0 {
			strRT := fmt.Sprintf("RT %d", tweet.RetweetCount)
			drawText(" "+strRT, x, y, ColorGreen, bgColor)
			x += 1 + runewidth.StringWidth(strRT)
		}
		if tweet.FavoriteCount > 0 {
			strFav := fmt.Sprintf("Fav %d", tweet.FavoriteCount)
			drawText(" "+strFav, x, y, ColorYellow, bgColor)
			x += 1 + runewidth.StringWidth(strFav)
		}

		y++

	}
}

func (tv *tweetview) resetScroll() {
	sum := 0
	_, h := getTermSize()
	var tweets []tweetstatus
	tweets = tv.tweets[:tv.cursorPosition]

	for _, t := range tweets {
		sum += t.countLines()
	}
	sub := sum - tv.scroll
	if sub <= 0 {
		tv.scroll = sum
	} else {
		cl := tv.tweets[tv.cursorPosition].countLines()
		sub = (sum + cl - (tv.scroll - tv.scrollOffset)) - (h - 2)
		if sub >= 0 {
			tv.scroll = sum + -(h - 2 - cl)
		}
	}

}

type tweetstatus struct {
	Content    *anaconda.Tweet
	ReloadMark bool
	Empty      bool

	pWidth     int
	cacheCount int
}

func (status *tweetstatus) countLines() int {
	if status.Empty {
		return 0
	} else if status.ReloadMark {
		return 1
	}
	w, _ := getTermSize()
	if w == status.pWidth {
		return status.cacheCount
	}
	tweet := status.Content
	if tweet.RetweetedStatus != nil {
		tweet = tweet.RetweetedStatus
	}
	text := tweet.Text
	lines := strings.Split(runewidth.Wrap(text, w-2), "\n")
	lineCount := 1 + len(lines) + 1

	// Caching
	status.pWidth = w
	status.cacheCount = lineCount
	return lineCount
}

func (status *tweetstatus) isFavorited() bool {
	if status.Content != nil {
		return status.Content.Favorited
	}
	return false
}
func (status *tweetstatus) setFavorited(b bool) {
	if status.Content != nil {
		status.Content.Favorited = b
	}
}

func (status *tweetstatus) isRetweeted() bool {
	if status.Content != nil {
		return status.Content.Retweeted
	}
	return false
}

func (status *tweetstatus) setRetweeted(b bool) {
	if status.Content != nil {
		status.Content.Retweeted = b
	}
}
<|endoftext|>


<commit_before>package golibxml

/*
#cgo pkg-config: libxml-2.0
#include <libxml/tree.h>

static inline void free_string(char* s) { free(s); }
static inline xmlChar *to_xmlcharptr(const char *s) { return (xmlChar *)s; }
static inline char *to_charptr(const xmlChar *s) { return (char *)s; }
*/
import "C"
import "unsafe"

func (doc *Document) String() string {
	buf := NewBuffer()
	defer buf.Free()
	doc.NodeDump(buf, doc.Node, 0, 0)
	return buf.Content()
}

func (node *Node) Document() *Document {
	return makeDoc(_Ctype_xmlDocPtr(unsafe.Pointer(node.Ptr.doc)))
}

func (node *Node) String() string {
	buf := NewBuffer()
	defer buf.Free()
	node.Document().NodeDump(buf, node, 0, 0)
	return buf.Content()
}

func (node *Node) Children() *Node {
	return makeNode(_Ctype_xmlNodePtr(unsafe.Pointer(node.Ptr.children)))
}

func (node *Node) Type() ElementType {
	return ElementType(node.Ptr._type)
}

func (node *Node) Name() string {
	return C.GoString(C.to_charptr(node.Ptr.name))
}

func (node *Node) Next() *Node {
	return makeNode(_Ctype_xmlNodePtr(unsafe.Pointer(node.Ptr.next)))
}

func (elem ElementType) String() string {
	switch (elem) {
		case XML_ELEMENT_NODE:
			return "Node"
		case XML_ATTRIBUTE_NODE:
			return "Attribute"
		case XML_TEXT_NODE:
			return "Text"
	}
	return "Unknown Type"
}

<commit_msg>GoString wrapper<commit_after>package golibxml

/*
#cgo pkg-config: libxml-2.0
#include <libxml/tree.h>

static inline void free_string(char* s) { free(s); }
static inline xmlChar *to_xmlcharptr(const char *s) { return (xmlChar *)s; }
static inline char *to_charptr(const xmlChar *s) { return (char *)s; }
*/
import "C"
import "unsafe"

func (doc *Document) String() string {
	buf := NewBuffer()
	defer buf.Free()
	doc.NodeDump(buf, doc.Node, 0, 0)
	return buf.Content()
}

func (node *Node) Document() *Document {
	return makeDoc(_Ctype_xmlDocPtr(unsafe.Pointer(node.Ptr.doc)))
}

func (node *Node) String() string {
	buf := NewBuffer()
	defer buf.Free()
	node.Document().NodeDump(buf, node, 0, 0)
	return buf.Content()
}

func (node *Node) Children() *Node {
	return makeNode(_Ctype_xmlNodePtr(unsafe.Pointer(node.Ptr.children)))
}

func (node *Node) Type() ElementType {
	return ElementType(node.Ptr._type)
}

func (node *Node) Name() string {
	return C.GoString(C.to_charptr(node.Ptr.name))
}

func (node *Node) Next() *Node {
	return makeNode(_Ctype_xmlNodePtr(unsafe.Pointer(node.Ptr.next)))
}

func (elem ElementType) GoString() string {
	return elem.String()
}

func (elem ElementType) String() string {
	switch (elem) {
		case XML_ELEMENT_NODE:
			return "Node"
		case XML_ATTRIBUTE_NODE:
			return "Attribute"
		case XML_TEXT_NODE:
			return "Text"
	}
	return "Unknown Type"
}

<|endoftext|>


<commit_before>// Command line interface to the xxHash32 and xxHash64 packages.
// Usage:
// 	xxHash [-mode 0] [-seed 123] filename1 [filename2...]
// where
//  mode: hash mode (0=32bits, 1=64bits) (default=1)
//  seed: seed to be used (default=0)
package main

import (
	"flag"
	"fmt"
	"hash"
	"io"
	"os"

	"github.com/pierrec/xxHash/xxHash32"
	"github.com/pierrec/xxHash/xxHash64"
)

func main() {
	seed := flag.Uint64("seed", 0, "uint32 or uint64 `seed` based on the selected mode (default 0)")
	mode := flag.Int("mode", 1, "hash mode: 0=32bits, 1=64bits")
	flag.Parse()

	var xxh hash.Hash
	if *mode == 0 {
		xxh = xxHash32.New(uint32(*seed))
	} else {
		xxh = xxHash64.New(*seed)
	}

	// Process each file in sequence
	for _, filename := range flag.Args() {
		inputFile, err := os.Open(filename)
		if err != nil {
			continue
		}
		if _, err := io.Copy(xxh, inputFile); err == nil {
			fmt.Printf("%x %s\n", xxh.Sum(nil), filename)
		}
		inputFile.Close()
		xxh.Reset()
	}
}
<commit_msg>Added lost stdin processing<commit_after>// Command line interface to the xxHash32 and xxHash64 packages.
// Usage:
// 	xxHash [-mode 0] [-seed 123] filename1 [filename2...]
// where
//  mode: hash mode (0=32bits, 1=64bits) (default=1)
//  seed: seed to be used (default=0)
package main

import (
	"flag"
	"fmt"
	"hash"
	"io"
	"os"

	"github.com/pierrec/xxHash/xxHash32"
	"github.com/pierrec/xxHash/xxHash64"
)

func main() {
	seed := flag.Uint64("seed", 0, "uint32 or uint64 `seed` based on the selected mode (default 0)")
	mode := flag.Int("mode", 1, "hash mode: 0=32bits, 1=64bits")
	flag.Parse()

	var xxh hash.Hash
	if *mode == 0 {
		xxh = xxHash32.New(uint32(*seed))
	} else {
		xxh = xxHash64.New(*seed)
	}

	print := func(s string) {
		h := xxh.Sum(nil)
		n := len(h)
		j := n - 1
		for i := 0; i < n/2; {
			h[i], h[j] = h[j], h[i]
			i++
			j--
		}
		fmt.Printf("%x %s\n", h, s)
	}

	if len(flag.Args()) == 0 {
		if _, err := io.Copy(xxh, os.Stdin); err == nil {
			print("stdin")
		}
		return
	}

	// Process each file in sequence
	for _, filename := range flag.Args() {
		inputFile, err := os.Open(filename)
		if err != nil {
			continue
		}
		if _, err := io.Copy(xxh, inputFile); err == nil {
			fmt.Printf("%x %s\n", xxh.Sum(nil), filename)
		}
		inputFile.Close()
		xxh.Reset()
	}
}
<|endoftext|>


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

package drive

import (
	"fmt"
	drive "github.com/odeke-em/google-api-go-client/drive/v2"
)

const Version = "0.0.9"

const (
	Barely = iota
	AlmostExceeded
	HalfwayExceeded
	Exceeded
	Unknown
)

const (
	AboutNone = 1 << iota
	AboutQuota
	AboutFileSizes
	AboutFeatures
)

func (g *Commands) About(mask int) (err error) {
	defer PrintVersion()
	if mask == AboutNone {
		return nil
	}

	about, err := g.rem.About()
	if err != nil {
		return err
	}
	printSummary(about, mask)

	return nil
}

func quotaRequested(mask int) bool {
	return (mask & AboutQuota) != 0
}

func fileSizesRequested(mask int) bool {
	return (mask & AboutFileSizes) != 0
}

func featuresRequested(mask int) bool {
	return (mask & AboutFeatures) != 0
}

func printSummary(about *drive.About, mask int) {
	if quotaRequested(mask) {
		quotaInformation(about)
	}
	if fileSizesRequested(mask) {
		fileSizesInfo(about)
	}

	if featuresRequested(mask) {
		featuresInformation(about)
	}
}

func fileSizesInfo(about *drive.About) {
	if len(about.MaxUploadSizes) >= 1 {
		fmt.Println("\n* Maximum upload sizes per file type *")
		fmt.Printf("%-36s %-36s\n", "FileType", "Size")
		for _, uploadInfo := range about.MaxUploadSizes {
			fmt.Printf("%-36s %-36s\n", uploadInfo.Type, prettyBytes(uploadInfo.Size))
		}
		fmt.Println()
	}
	return
}

func featuresInformation(about *drive.About) {
	if len(about.Features) >= 1 {
		fmt.Printf("%-30s %-30s\n", "Feature", "Request limit (queries/second)")
		for _, feature := range about.Features {
			if feature.FeatureName == "" {
				continue
			}
			fmt.Printf("%-30s %-30f\n", feature.FeatureName, feature.FeatureRate)
		}
		fmt.Println()
	}
}

func quotaInformation(about *drive.About) {
	freeBytes := about.QuotaBytesTotal - about.QuotaBytesUsed

	fmt.Printf(
		"Name: %s\nAccount type:\t%s\nBytes Used:\t%-20d (%s)\n"+
			"Bytes Free:\t%-20d (%s)\nBytes InTrash:\t%-20d (%s)\n"+
			"Total Bytes:\t%-20d (%s)\n",
		about.Name, about.QuotaType,
		about.QuotaBytesUsed, prettyBytes(about.QuotaBytesUsed),
		freeBytes, prettyBytes(freeBytes),
		about.QuotaBytesUsedInTrash, prettyBytes(about.QuotaBytesUsedInTrash),
		about.QuotaBytesTotal, prettyBytes(about.QuotaBytesTotal))

	if len(about.QuotaBytesByService) >= 1 {
		fmt.Println("\n* Space used by Google Services *")
		fmt.Printf("%-36s %-36s\n", "Service", "Bytes")
		for _, quotaService := range about.QuotaBytesByService {
			fmt.Printf("%-36s %-36s\n", quotaService.ServiceName, prettyBytes(quotaService.BytesUsed))
		}
		fmt.Printf("%-36s %-36s\n", "Space used by all Google Apps",
			prettyBytes(about.QuotaBytesUsedAggregate))
	}
	fmt.Println()
}

func (g *Commands) QuotaStatus(query int64) (status int, err error) {
	if query < 0 {
		return Unknown, err
	}

	about, err := g.rem.About()
	if err != nil {
		return Unknown, err
	}

	// Sanity check
	if about.QuotaBytesTotal < 1 {
		return Unknown, fmt.Errorf("QuotaBytesTotal < 1")
	}

	toBeUsed := query + about.QuotaBytesUsed
	if toBeUsed >= about.QuotaBytesTotal {
		return Exceeded, nil
	}

	percentage := float64(toBeUsed) / float64(about.QuotaBytesTotal)
	if percentage < 0.5 {
		return Barely, nil
	}
	if percentage < 0.8 {
		return HalfwayExceeded, nil
	}
	return AlmostExceeded, nil
}
<commit_msg>version bump to v0.1.0!<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package drive

import (
	"fmt"
	drive "github.com/odeke-em/google-api-go-client/drive/v2"
)

const Version = "0.1.0"

const (
	Barely = iota
	AlmostExceeded
	HalfwayExceeded
	Exceeded
	Unknown
)

const (
	AboutNone = 1 << iota
	AboutQuota
	AboutFileSizes
	AboutFeatures
)

func (g *Commands) About(mask int) (err error) {
	defer PrintVersion()
	if mask == AboutNone {
		return nil
	}

	about, err := g.rem.About()
	if err != nil {
		return err
	}
	printSummary(about, mask)

	return nil
}

func quotaRequested(mask int) bool {
	return (mask & AboutQuota) != 0
}

func fileSizesRequested(mask int) bool {
	return (mask & AboutFileSizes) != 0
}

func featuresRequested(mask int) bool {
	return (mask & AboutFeatures) != 0
}

func printSummary(about *drive.About, mask int) {
	if quotaRequested(mask) {
		quotaInformation(about)
	}
	if fileSizesRequested(mask) {
		fileSizesInfo(about)
	}

	if featuresRequested(mask) {
		featuresInformation(about)
	}
}

func fileSizesInfo(about *drive.About) {
	if len(about.MaxUploadSizes) >= 1 {
		fmt.Println("\n* Maximum upload sizes per file type *")
		fmt.Printf("%-36s %-36s\n", "FileType", "Size")
		for _, uploadInfo := range about.MaxUploadSizes {
			fmt.Printf("%-36s %-36s\n", uploadInfo.Type, prettyBytes(uploadInfo.Size))
		}
		fmt.Println()
	}
	return
}

func featuresInformation(about *drive.About) {
	if len(about.Features) >= 1 {
		fmt.Printf("%-30s %-30s\n", "Feature", "Request limit (queries/second)")
		for _, feature := range about.Features {
			if feature.FeatureName == "" {
				continue
			}
			fmt.Printf("%-30s %-30f\n", feature.FeatureName, feature.FeatureRate)
		}
		fmt.Println()
	}
}

func quotaInformation(about *drive.About) {
	freeBytes := about.QuotaBytesTotal - about.QuotaBytesUsed

	fmt.Printf(
		"Name: %s\nAccount type:\t%s\nBytes Used:\t%-20d (%s)\n"+
			"Bytes Free:\t%-20d (%s)\nBytes InTrash:\t%-20d (%s)\n"+
			"Total Bytes:\t%-20d (%s)\n",
		about.Name, about.QuotaType,
		about.QuotaBytesUsed, prettyBytes(about.QuotaBytesUsed),
		freeBytes, prettyBytes(freeBytes),
		about.QuotaBytesUsedInTrash, prettyBytes(about.QuotaBytesUsedInTrash),
		about.QuotaBytesTotal, prettyBytes(about.QuotaBytesTotal))

	if len(about.QuotaBytesByService) >= 1 {
		fmt.Println("\n* Space used by Google Services *")
		fmt.Printf("%-36s %-36s\n", "Service", "Bytes")
		for _, quotaService := range about.QuotaBytesByService {
			fmt.Printf("%-36s %-36s\n", quotaService.ServiceName, prettyBytes(quotaService.BytesUsed))
		}
		fmt.Printf("%-36s %-36s\n", "Space used by all Google Apps",
			prettyBytes(about.QuotaBytesUsedAggregate))
	}
	fmt.Println()
}

func (g *Commands) QuotaStatus(query int64) (status int, err error) {
	if query < 0 {
		return Unknown, err
	}

	about, err := g.rem.About()
	if err != nil {
		return Unknown, err
	}

	// Sanity check
	if about.QuotaBytesTotal < 1 {
		return Unknown, fmt.Errorf("QuotaBytesTotal < 1")
	}

	toBeUsed := query + about.QuotaBytesUsed
	if toBeUsed >= about.QuotaBytesTotal {
		return Exceeded, nil
	}

	percentage := float64(toBeUsed) / float64(about.QuotaBytesTotal)
	if percentage < 0.5 {
		return Barely, nil
	}
	if percentage < 0.8 {
		return HalfwayExceeded, nil
	}
	return AlmostExceeded, nil
}
<|endoftext|>


<commit_before>package bucketer

import (
  "github.com/CapillarySoftware/gostat/stat"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"fmt"
	"time"
)

var _ = Describe("Bucketer", func() {

	var stats         <-chan *stat.Stat
	var bucketedStats chan<- []*stat.Stat
	var shutdown      <-chan bool

	JustBeforeEach(func() {
		stats         = make(chan *stat.Stat)
		bucketedStats = make(chan []*stat.Stat)
		shutdown      = make(chan bool)
	})

	Describe("Construction", func() {
		It("should return a properly initialized Bucketer", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			// a newly constructed Bucketer has nothing in it's buckets
			Expect(len(x.currentBuckets)).To(Equal(0))
			Expect(len(x.previousBuckets)).To(Equal(0))

			// the current bucket min time is rounded down to the minute boundary
			// so it should not have any 'seconds' or 'nanoseconds' part
			Expect(x.currentBucketMinTime.Second()).To(Equal(0))
			Expect(x.currentBucketMinTime.Nanosecond()).To(Equal(0))

			// the previous bucket's min time is exactly one minute less than the current bucket's min time
			Expect(x.currentBucketMinTime.Sub(x.previousBucketMinTime)).To(Equal(time.Duration(time.Minute)))

			// verify the input channels
			Expect(x.input).NotTo(BeClosed())
			Expect(x.shutdown).NotTo(BeClosed())
		})
	})

	Describe("Insert", func() {
		It("should return an error if a nil stat is inserted", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			Expect(x.insert(nil)).To(Equal(fmt.Errorf("dropping nil stat")))
		})

		It("should insert the stat in the current bucket if the Timestamp is after the current bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.currentBucketMinTime.Add(time.Duration(time.Second)), Value : 1}
			Expect(s.Timestamp).To(BeTemporally(">", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally(">", x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(BeNil())

			Expect(x.currentBuckets[s.Name][0]).To(Equal(&s))
			Expect(x.previousBuckets[s.Name]).To(BeNil())
		})

		It("should insert the stat in the current bucket if the Timestamp is the same as the current bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.currentBucketMinTime, Value : 1}
			Expect(s.Timestamp).To(BeTemporally("==", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally(">",  x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(BeNil())

			Expect(x.currentBuckets[s.Name][0]).To(Equal(&s))
			Expect(x.previousBuckets[s.Name]).To(BeNil())
		})

		It("should insert the stat in the previous bucket if the Timestamp is less than the current bucket's min time and greater than the previous bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.currentBucketMinTime.Add(time.Duration(time.Second * -1)), Value : 1}
			Expect(s.Timestamp).To(BeTemporally("<", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally(">", x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(BeNil())

			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name][0]).To(Equal(&s))
		})

		It("should insert the stat in the previous bucket if the Timestamp is less than the current bucket's min time and equal to the previous bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.previousBucketMinTime, Value : 1}
			Expect(s.Timestamp).To(BeTemporally("<", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally("==", x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(BeNil())

			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name][0]).To(Equal(&s))
		})

		It("should NOT insert the stat if the Timestamp is less than the previous bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.previousBucketMinTime.Add(time.Duration(time.Second * -1)), Value : 1}
			Expect(s.Timestamp).To(BeTemporally("<", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally("<", x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(Equal(fmt.Errorf("Bucketer: dropping stat older than %v: %+v", x.previousBucketMinTime, s)))

			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())
		})
	})
})
<commit_msg>added insert() test for the case when the same stat is inserted multiple times<commit_after>package bucketer

import (
  "github.com/CapillarySoftware/gostat/stat"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"fmt"
	"time"
)

var _ = Describe("Bucketer", func() {

	var stats         <-chan *stat.Stat
	var bucketedStats chan<- []*stat.Stat
	var shutdown      <-chan bool

	JustBeforeEach(func() {
		stats         = make(chan *stat.Stat)
		bucketedStats = make(chan []*stat.Stat)
		shutdown      = make(chan bool)
	})

	Describe("Construction", func() {
		It("should return a properly initialized Bucketer", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			// a newly constructed Bucketer has nothing in it's buckets
			Expect(len(x.currentBuckets)).To(Equal(0))
			Expect(len(x.previousBuckets)).To(Equal(0))

			// the current bucket min time is rounded down to the minute boundary
			// so it should not have any 'seconds' or 'nanoseconds' part
			Expect(x.currentBucketMinTime.Second()).To(Equal(0))
			Expect(x.currentBucketMinTime.Nanosecond()).To(Equal(0))

			// the previous bucket's min time is exactly one minute less than the current bucket's min time
			Expect(x.currentBucketMinTime.Sub(x.previousBucketMinTime)).To(Equal(time.Duration(time.Minute)))

			// verify the input channels
			Expect(x.input).NotTo(BeClosed())
			Expect(x.shutdown).NotTo(BeClosed())
		})
	})

	Describe("Insert", func() {
		It("should return an error if a nil stat is inserted", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			Expect(x.insert(nil)).To(Equal(fmt.Errorf("dropping nil stat")))
		})

		It("should insert the stat in the current bucket if the Timestamp is after the current bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.currentBucketMinTime.Add(time.Duration(time.Second)), Value : 1}
			Expect(s.Timestamp).To(BeTemporally(">", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally(">", x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(BeNil())

			Expect(x.currentBuckets[s.Name][0]).To(Equal(&s))
			Expect(x.previousBuckets[s.Name]).To(BeNil())
		})

		It("should insert the stat in the current bucket if the Timestamp is the same as the current bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.currentBucketMinTime, Value : 1}
			Expect(s.Timestamp).To(BeTemporally("==", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally(">",  x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(BeNil())

			Expect(x.currentBuckets[s.Name][0]).To(Equal(&s))
			Expect(x.previousBuckets[s.Name]).To(BeNil())
		})

		It("should insert the stat in the previous bucket if the Timestamp is less than the current bucket's min time and greater than the previous bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.currentBucketMinTime.Add(time.Duration(time.Second * -1)), Value : 1}
			Expect(s.Timestamp).To(BeTemporally("<", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally(">", x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(BeNil())

			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name][0]).To(Equal(&s))
		})

		It("should insert the stat in the previous bucket if the Timestamp is less than the current bucket's min time and equal to the previous bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.previousBucketMinTime, Value : 1}
			Expect(s.Timestamp).To(BeTemporally("<", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally("==", x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(BeNil())

			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name][0]).To(Equal(&s))
		})

		It("should NOT insert the stat if the Timestamp is less than the previous bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.previousBucketMinTime.Add(time.Duration(time.Second * -1)), Value : 1}
			Expect(s.Timestamp).To(BeTemporally("<", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally("<", x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(Equal(fmt.Errorf("Bucketer: dropping stat older than %v: %+v", x.previousBucketMinTime, s)))

			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())
		})

		It("should insert the same stat in the current bucket TWICE we call insert() on the same stat twice and the Timestamp is after the current bucket's min time", func() {
			x := NewBucketer(stats, bucketedStats, shutdown)

			s := stat.Stat{Name : "foo", Timestamp : x.currentBucketMinTime.Add(time.Duration(time.Second)), Value : 1}
			Expect(s.Timestamp).To(BeTemporally(">", x.currentBucketMinTime))
			Expect(s.Timestamp).To(BeTemporally(">", x.previousBucketMinTime))
			Expect(x.currentBuckets[s.Name]).To(BeNil())
			Expect(x.previousBuckets[s.Name]).To(BeNil())

			Expect(x.insert(&s)).To(BeNil())
			Expect(x.insert(&s)).To(BeNil())

			Expect(x.currentBuckets[s.Name]).To(ConsistOf(&s, &s))
			Expect(x.previousBuckets[s.Name]).To(BeNil())
		})
	})
})
<|endoftext|>


<commit_before>package input

//input manages modes

import (
	tm "github.com/jonvaldes/termo"
	gv "github.com/Virepri/Shoraldele/GlobalVars"
	"github.com/Virepri/Shoraldele/Buffer"
	"github.com/Virepri/Shoraldele/Codes"
	"reflect"
	"strings"
)

//http://stackoverflow.com/questions/14426366/what-is-an-idiomatic-way-of-representing-enums-in-go

type ModeType uint8

const (
	Command ModeType = iota
	Insert
	Select
)

var CurrentMode ModeType //Defaults to 0, which is Command mode

//Append to this array if you want to be notified when the mode changes
var ModeChangeNotifiers [](chan<- ModeType)

var HasSelection bool

//If your file is more than 18.45 exabytes, you're fucked for so many other reasons besides the bitwidth of the cursor position
var selection struct{start,end uint64}

func Setup(_ string) {
	return
}

func Routine() {
	defer gv.WaitGroup.Done()

	keychan := make(chan tm.ScanCode)
	errchan := make(chan error)

	tm.StartKeyReadLoop(keychan, errchan)

	for {
		handleKey(<-keychan)
	}
	return
}

func changeMode (new_mode ModeType) {
	if new_mode == CurrentMode {
		// do nothing!
		return
	} else {
		CurrentMode = new_mode
		// TODO: This should probably dispatch threads so that someone adding a chan but not listening does not block
		for _, chn := range ModeChangeNotifiers {
			chn <- new_mode
		}
	}
}

func handleKey (keycode tm.ScanCode) {
	if s(keycode, codes.ESC) { //ESC
		changeMode(Command)
		return
	}
	switch {
	case CurrentMode == Insert:
		if s(keycode, codes.ESC) {
			changeMode(Command)
		} else {
			buffer.Overwrite(int(buffer.GetCursorPosition()),string(keycode.Rune()))
		}
	case s(keycode, codes.Ci): //i
		if CurrentMode == Select && HasSelection {
			buffer.Delete(int(selection.start),int(selection.end - selection.start))
			HasSelection = false
			selection = struct{ start, end uint64 }{start:0, end:0}
		}
		changeMode(Insert)
	case s(keycode, codes.Cs): //s
		changeMode(Select)
    selection.start, selection.end = buffer.GetCursorPosition(), buffer.GetCursorPosition()
		HasSelection = true
	//case s(keycode, codes.Cc): //c
	//	changeMode(Command)

	case s(keycode, codes.ESC):
		changeMode(Command)
		selection.start, selection.end = 0,0
		HasSelection = false
  case s(keycode, codes.LEFT):
		if buffer.GetCursorPosition() > 0 {
			buffer.SetCursorPosition(buffer.GetCursorPosition() + 1)
      if CurrentMode == Select {
				selection.start--
			}
		}
	case s(keycode, codes.RIGHT):
		if buffer.GetCursorPosition() < buffer.GetBufferSize() {
			buffer.SetCursorPosition(buffer.GetCursorPosition() - 1)
      if CurrentMode == Select {
				selection.end++
			}
		}
	case s(keycode, codes.UP):
		line, char, lines := buffer.GetCursorLinePosition()
		if line > 0 {
			prevline := lines[line - 1]
			buffer.SetCursorPosition(prevline[0] + min(prevline[1], char))
      if CurrentMode == Select {
			selection.start = uint64(prevline[0] + min(prevline[1], char))
		  }
		}
	}
}

func min (a, b int) int {
	if (a < b) {
		return a
	} else {
		return b
	}
}

func s (a tm.ScanCode, b tm.ScanCode) bool {
	return reflect.DeepEqual(a, b)
}
<commit_msg>fixed things<commit_after>package input

//input manages modes

import (
	tm "github.com/jonvaldes/termo"
	gv "github.com/Virepri/Shoraldele/GlobalVars"
	"github.com/Virepri/Shoraldele/Buffer"
	"github.com/Virepri/Shoraldele/Codes"
	"reflect"
)

//http://stackoverflow.com/questions/14426366/what-is-an-idiomatic-way-of-representing-enums-in-go

type ModeType uint8

const (
	Command ModeType = iota
	Insert
	Select
)

var CurrentMode ModeType //Defaults to 0, which is Command mode

//Append to this array if you want to be notified when the mode changes
var ModeChangeNotifiers [](chan<- ModeType)

var HasSelection bool

//If your file is more than 18.45 exabytes, you're fucked for so many other reasons besides the bitwidth of the cursor position
var selection struct{start,end int}

func Setup(_ string) {
	return
}

func Routine() {
	defer gv.WaitGroup.Done()

	keychan := make(chan tm.ScanCode)
	errchan := make(chan error)

	tm.StartKeyReadLoop(keychan, errchan)

	for {
		handleKey(<-keychan)
	}
	return
}

func changeMode (new_mode ModeType) {
	if new_mode == CurrentMode {
		// do nothing!
		return
	} else {
		CurrentMode = new_mode
		// TODO: This should probably dispatch threads so that someone adding a chan but not listening does not block
		for _, chn := range ModeChangeNotifiers {
			chn <- new_mode
		}
	}
}

func handleKey (keycode tm.ScanCode) {
	if s(keycode, codes.ESC) { //ESC
		changeMode(Command)
		return
	}
	switch {
	case CurrentMode == Insert:
		if s(keycode, codes.ESC) {
			changeMode(Command)
		} else {
			buffer.Overwrite(int(buffer.GetCursorPosition()),string(keycode.Rune()))
		}
	case s(keycode, codes.Ci): //i
		if CurrentMode == Select && HasSelection {
			buffer.Delete(int(selection.start),int(selection.end - selection.start))
			HasSelection = false
			selection = struct{ start, end int }{start:0, end:0}
		}
		changeMode(Insert)
	case s(keycode, codes.Cs): //s
		changeMode(Select)
    selection.start, selection.end = buffer.GetCursorPosition(), buffer.GetCursorPosition()
		HasSelection = true
	//case s(keycode, codes.Cc): //c
	//	changeMode(Command)

	case s(keycode, codes.ESC):
		changeMode(Command)
		selection.start, selection.end = 0,0
		HasSelection = false
  case s(keycode, codes.LEFT):
		if buffer.GetCursorPosition() > 0 {
			buffer.SetCursorPosition(buffer.GetCursorPosition() + 1)
      if CurrentMode == Select {
				selection.start--
			}
		}
	case s(keycode, codes.RIGHT):
		if buffer.GetCursorPosition() < buffer.GetBufferSize() {
			buffer.SetCursorPosition(buffer.GetCursorPosition() - 1)
      if CurrentMode == Select {
				selection.end++
			}
		}
	case s(keycode, codes.UP):
		line, char, lines := buffer.GetCursorLinePosition()
		if line > 0 {
			prevline := lines[line - 1]
			buffer.SetCursorPosition(prevline[0] + min(prevline[1], char))
      if CurrentMode == Select {
			selection.start = prevline[0] + min(prevline[1], char)
		  }
		}
	}
}

func min (a, b int) int {
	if (a < b) {
		return a
	} else {
		return b
	}
}

func s (a tm.ScanCode, b tm.ScanCode) bool {
	return reflect.DeepEqual(a, b)
}
<|endoftext|>


<commit_before>package updaters

import (
	"encoding/json"
	"github.com/robmerrell/btbboard/models"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
)

var coinbaseUrl = "https://coinbase.com/api/v1/currencies/exchange_rates"
var cryptsyUrl = "http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=151"

type CoinPrice struct{}

// Update retrieves VTC buy prices in both USD and BTC and saves
// the prices to the database.
func (c *CoinPrice) Update() error {
	usd, err := coinbaseQuote()
	if err != nil {
		return err
	}

	cryptsyBtc, err := cryptsyQuote()
	if err != nil {
		return err
	}

	conn := models.CloneConnection()
	defer conn.Close()

	price := &models.Price{
		UsdPerBtc:   usd,
		Cryptsy:     &models.ExchangePrice{Btc: cryptsyBtc, Usd: usd * cryptsyBtc},
		GeneratedAt: time.Now().UTC().Truncate(time.Minute),
	}
	if err := price.SetPercentChange(conn); err != nil {
		return err
	}

	return price.Insert(conn)
}

// coinbaseQuote gets the current USD value for 1 BTC from coinbase.
func coinbaseQuote() (float64, error) {
	resp, err := http.Get(coinbaseUrl)
	if err != nil {
		return 0.0, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	var value struct {
		Btc string `json:"btc_to_usd"`
	}
	if err := json.Unmarshal(body, &value); err != nil {
		return 0.0, err
	}

	return strconv.ParseFloat(value.Btc, 64)
}

// cryptsyQuote gets the current VTC/BTC value from cryptsy.
func cryptsyQuote() (float64, error) {
	resp, err := http.Get(cryptsyUrl)
	if err != nil {
		return 0.0, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	var value struct {
		Return struct {
			Markets struct {
				VTC struct {
					RecentTrades []map[string]string
				}
			}
		}
	}
	if err := json.Unmarshal(body, &value); err != nil {
		return 0.0, err
	}

	return strconv.ParseFloat(value.Return.Markets.VTC.RecentTrades[0]["price"], 64)
}
<commit_msg>Use the cryptsy full market api to get the current prices, because calling the api for only the bitbar market is doesn't work.<commit_after>package updaters

import (
	"encoding/json"
	"github.com/robmerrell/btbboard/models"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
)

var coinbaseUrl = "https://coinbase.com/api/v1/currencies/exchange_rates"

// the cryptsy API is currenty broken for BTB, so get prices from the full market data.
var cryptsyUrl = "http://pubapi.cryptsy.com/api.php?method=marketdatav2"

type CoinPrice struct{}

// Update retrieves BTB buy prices in both USD and BTC and saves
// the prices to the database.
func (c *CoinPrice) Update() error {
	usd, err := coinbaseQuote()
	if err != nil {
		return err
	}

	cryptsyBtc, err := cryptsyQuote()
	if err != nil {
		return err
	}

	conn := models.CloneConnection()
	defer conn.Close()

	price := &models.Price{
		UsdPerBtc:   usd,
		Cryptsy:     &models.ExchangePrice{Btc: cryptsyBtc, Usd: usd * cryptsyBtc},
		GeneratedAt: time.Now().UTC().Truncate(time.Minute),
	}
	if err := price.SetPercentChange(conn); err != nil {
		return err
	}

	return price.Insert(conn)
}

// coinbaseQuote gets the current USD value for 1 BTC from coinbase.
func coinbaseQuote() (float64, error) {
	resp, err := http.Get(coinbaseUrl)
	if err != nil {
		return 0.0, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	var value struct {
		Btc string `json:"btc_to_usd"`
	}
	if err := json.Unmarshal(body, &value); err != nil {
		return 0.0, err
	}

	return strconv.ParseFloat(value.Btc, 64)
}

// cryptsyQuote gets the current BTB/BTC value from cryptsy.
func cryptsyQuote() (float64, error) {
	resp, err := http.Get(cryptsyUrl)
	if err != nil {
		return 0.0, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	var value struct {
		Return struct {
			Markets map[string]interface{}
		}
	}
	if err := json.Unmarshal(body, &value); err != nil {
		return 0.0, err
	}

	market := value.Return.Markets["BTB/BTC"].(map[string]interface{})
	recentTrades := market["recenttrades"].([]interface{})
	price := recentTrades[0].(map[string]interface{})["price"].(string)

	return strconv.ParseFloat(price, 64)
}
<|endoftext|>


<commit_before><commit_msg>Working on notifications<commit_after><|endoftext|>


<commit_before>package irma

import (
	"crypto/sha256"
	"encoding/binary"
	"encoding/hex"
	"time"

	"github.com/privacybydesign/gabi"
	"github.com/privacybydesign/gabi/big"

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

const (
	// ExpiryFactor is the precision for the expiry attribute. Value is one week.
	ExpiryFactor   = 60 * 60 * 24 * 7
	metadataLength = 1 + 3 + 2 + 2 + 16
)

var (
	versionField     = metadataField{1, 0}
	signingDateField = metadataField{3, 1}
	validityField    = metadataField{2, 4}
	keyCounterField  = metadataField{2, 6}
	credentialID     = metadataField{16, 8}
)

// metadataField contains the length and offset of a field within a metadata attribute.
type metadataField struct {
	length int
	offset int
}

// metadataAttribute represents a metadata attribute. Contains the credential type, signing date, validity, and the public key counter.
type MetadataAttribute struct {
	Int  *big.Int
	pk   *gabi.PublicKey
	Conf *Configuration
}

// AttributeList contains attributes, excluding the secret key,
// providing convenient access to the metadata attribute.
type AttributeList struct {
	*MetadataAttribute  `json:"-"`
	Ints                []*big.Int
	Revoked             bool `json:",omitempty"`
	RevocationSupported bool `json:,omitempty`
	strings             []TranslatedString
	attrMap             map[AttributeTypeIdentifier]TranslatedString
	info                *CredentialInfo
	h                   string
}

// NewAttributeListFromInts initializes a new AttributeList from a list of bigints.
func NewAttributeListFromInts(ints []*big.Int, conf *Configuration) *AttributeList {
	metadata := MetadataFromInt(ints[0], conf)
	credtype := metadata.CredentialType()
	idx := credtype.RevocationIndex + 1
	var rev bool
	if credtype != nil {
		rev = len(ints) > idx && ints[idx] != nil && ints[idx].Cmp(bigZero) != 0
	}
	return &AttributeList{
		Ints:                ints,
		MetadataAttribute:   metadata,
		RevocationSupported: rev,
	}
}

func (al *AttributeList) Info() *CredentialInfo {
	if al.info == nil {
		al.info = al.CredentialInfo()
	}
	al.info.Revoked = al.Revoked
	return al.info
}

// EqualsExceptMetadata checks whether two AttributeLists have the same attribute values.
// The attribute containing the metadata information is skipped in this check.
func (al *AttributeList) EqualsExceptMetadata(ol *AttributeList) bool {
	if len(al.Ints) != len(ol.Ints) {
		return false
	}

	// Check whether value of all attributes, except for metadata attribute, is equal
	for i := 1; i < len(al.Ints); i++ {
		if al.Ints[i].Cmp(ol.Ints[i]) != 0 {
			return false
		}
	}
	return true
}

func (al *AttributeList) Hash() string {
	if al.h == "" {
		bytes := []byte{}
		for _, i := range al.Ints {
			bytes = append(bytes, i.Bytes()...)
		}
		shasum := sha256.Sum256(bytes)
		al.h = hex.EncodeToString(shasum[:])
	}
	return al.h
}

func (al *AttributeList) Map() map[AttributeTypeIdentifier]TranslatedString {
	if al.attrMap == nil {
		al.attrMap = make(map[AttributeTypeIdentifier]TranslatedString)
		ctid := al.CredentialType().Identifier()
		attrTypes := al.Conf.CredentialTypes[ctid].AttributeTypes
		for i, val := range al.Strings() {
			if attrTypes[i].RevocationAttribute {
				continue
			}
			al.attrMap[attrTypes[i].GetAttributeTypeIdentifier()] = val
		}
	}
	return al.attrMap
}

// Strings converts the current instance to human-readable strings.
func (al *AttributeList) Strings() []TranslatedString {
	if al.strings == nil {
		al.strings = make([]TranslatedString, len(al.Ints)-1)
		for i := range al.Ints[1:] { // skip metadata
			val := al.decode(i)
			if val == nil {
				continue
			}
			al.strings[i] = NewTranslatedString(val)
		}
	}
	return al.strings
}

// NewTranslatedString returns a TranslatedString containing the specified string for each supported language,
// or nil when attr is nil.
func NewTranslatedString(attr *string) TranslatedString {
	if attr == nil {
		return nil
	}
	return map[string]string{
		"":   *attr, // raw value
		"en": *attr,
		"nl": *attr,
	}
}

func (al *AttributeList) decode(i int) *string {
	attr := al.Ints[i+1]
	metadataVersion := al.MetadataAttribute.Version()
	return decodeAttribute(attr, metadataVersion)
}

// Decode attribute value into string according to metadataVersion
func decodeAttribute(attr *big.Int, metadataVersion byte) *string {
	bi := new(big.Int).Set(attr)
	if metadataVersion >= 3 {
		if bi.Bit(0) == 0 { // attribute does not exist
			return nil
		}
		bi.Rsh(bi, 1)
	}
	str := string(bi.Bytes())
	return &str
}

// UntranslatedAttribute decodes the bigint corresponding to the specified attribute.
func (al *AttributeList) UntranslatedAttribute(identifier AttributeTypeIdentifier) *string {
	if al.CredentialType().Identifier() != identifier.CredentialTypeIdentifier() {
		return nil
	}
	for i, desc := range al.CredentialType().AttributeTypes {
		if desc.ID == string(identifier.Name()) {
			return al.decode(i)
		}
	}
	return nil
}

// Attribute returns the content of the specified attribute, or nil if not present in this attribute list.
func (al *AttributeList) Attribute(identifier AttributeTypeIdentifier) TranslatedString {
	if al.CredentialType().Identifier() != identifier.CredentialTypeIdentifier() {
		return nil
	}

	for i, val := range al.Strings() {
		if al.CredentialType().AttributeTypes[i].ID == string(identifier.Name()) {
			return val
		}
	}

	return nil
}

// MetadataFromInt wraps the given Int
func MetadataFromInt(i *big.Int, conf *Configuration) *MetadataAttribute {
	return &MetadataAttribute{Int: i, Conf: conf}
}

// NewMetadataAttribute constructs a new instance containing the default values:
// provided version as versionField
// now as signing date
// 0 as keycounter
// ValidityDefault (half a year) as default validity.
func NewMetadataAttribute(version byte) *MetadataAttribute {
	val := MetadataAttribute{new(big.Int), nil, nil}
	val.setField(versionField, []byte{version})
	val.setSigningDate()
	val.setKeyCounter(0)
	val.setDefaultValidityDuration()
	return &val
}

// Bytes returns this metadata attribute as a byte slice.
// Bigint's Bytes() method returns a big-endian byte slice, so add padding at begin.
func (attr *MetadataAttribute) Bytes() []byte {
	bytes := attr.Int.Bytes()
	if len(bytes) < metadataLength {
		bytes = append(make([]byte, metadataLength-len(bytes)), bytes...)
	}
	return bytes
}

// PublicKey extracts identifier of the Idemix public key with which this instance was signed,
// and returns this public key.
func (attr *MetadataAttribute) PublicKey() (*gabi.PublicKey, error) {
	if attr.pk == nil {
		var err error
		attr.pk, err = attr.Conf.PublicKey(attr.CredentialType().IssuerIdentifier(), attr.KeyCounter())
		if err != nil {
			return nil, err
		}
	}
	return attr.pk, nil
}

// Version returns the metadata version of this instance
func (attr *MetadataAttribute) Version() byte {
	return attr.field(versionField)[0]
}

// SigningDate returns the time at which this instance was signed
func (attr *MetadataAttribute) SigningDate() time.Time {
	bytes := attr.field(signingDateField)
	bytes = bytes[1:] // The signing date field is one byte too long
	timestamp := int64(binary.BigEndian.Uint16(bytes)) * ExpiryFactor
	return time.Unix(timestamp, 0)
}

func (attr *MetadataAttribute) setSigningDate() {
	attr.setField(signingDateField, shortToByte(uint(time.Now().Unix()/ExpiryFactor)))
}

// KeyCounter return the public key counter of the metadata attribute
func (attr *MetadataAttribute) KeyCounter() uint {
	return uint(binary.BigEndian.Uint16(attr.field(keyCounterField)))
}

func (attr *MetadataAttribute) setKeyCounter(i uint) {
	attr.setField(keyCounterField, shortToByte(i))
}

// ValidityDuration returns the amount of epochs during which this instance is valid
func (attr *MetadataAttribute) ValidityDuration() int {
	return int(binary.BigEndian.Uint16(attr.field(validityField)))
}

func (attr *MetadataAttribute) setValidityDuration(weeks uint) {
	attr.setField(validityField, shortToByte(weeks))
}

func (attr *MetadataAttribute) setDefaultValidityDuration() {
	// setExpiryDate only errors if setting the expiry date before the signing date,
	// which never happens here
	_ = attr.setExpiryDate(nil)
}

func (attr *MetadataAttribute) setExpiryDate(timestamp *Timestamp) error {
	signingTimestamp := attr.SigningDate()
	var expiry int64
	if timestamp == nil {
		expiry = signingTimestamp.AddDate(0, 6, 0).Unix()
	} else {
		expiry = time.Time(*timestamp).Unix()
	}
	signing := signingTimestamp.Unix()
	if expiry-signing < 0 {
		return errors.New("cannot set expired date")
	}
	attr.setValidityDuration(uint((expiry - signing) / ExpiryFactor))
	return nil
}

// CredentialType returns the credential type of the current instance
// using the Configuration.
func (attr *MetadataAttribute) CredentialType() *CredentialType {
	return attr.Conf.hashToCredentialType(attr.field(credentialID))
}

func (attr *MetadataAttribute) setCredentialTypeIdentifier(id string) {
	bytes := sha256.Sum256([]byte(id))
	attr.setField(credentialID, bytes[:16])
}

func (attr *MetadataAttribute) CredentialTypeHash() []byte {
	return attr.field(credentialID)
}

// Expiry returns the expiry date of this instance
func (attr *MetadataAttribute) Expiry() time.Time {
	expiry := attr.SigningDate().Unix() + int64(attr.ValidityDuration()*ExpiryFactor)
	return time.Unix(expiry, 0)
}

// IsValidOn returns whether this instance is still valid at the given time
func (attr *MetadataAttribute) IsValidOn(t time.Time) bool {
	return attr.Expiry().After(t)
}

// IsValid returns whether this instance is valid.
func (attr *MetadataAttribute) IsValid() bool {
	return attr.IsValidOn(time.Now())
}

// FloorToEpochBoundary returns the greatest time not greater than the argument
// that falls on the boundary of an epoch for attribute validity or expiry,
// of which the value is defined by ExpiryFactor (one week).
func FloorToEpochBoundary(t time.Time) time.Time {
	return time.Unix((t.Unix()/ExpiryFactor)*ExpiryFactor, 0)
}

func (attr *MetadataAttribute) field(field metadataField) []byte {
	return attr.Bytes()[field.offset : field.offset+field.length]
}

func (attr *MetadataAttribute) setField(field metadataField, value []byte) {
	if len(value) > field.length {
		panic("Specified metadata field too large")
	}

	bytes := attr.Bytes()

	// Push the value to the right within the field. Graphical representation:
	// --xxxXXX----
	// "-" indicates a byte of another field
	// "X" is a byte of the value and "x" of our field
	// In this example, our field has offset 2, length 6,
	// but the specified value is only 3 bytes long.
	startindex := field.length - len(value)
	for i := 0; i < field.length; i++ {
		if i < startindex {
			bytes[i+field.offset] = 0
		} else {
			bytes[i+field.offset] = value[i-startindex]
		}
	}

	attr.Int.SetBytes(bytes)
}

func shortToByte(x uint) []byte {
	bytes := make([]byte, 2)
	if x > 1<<16 {
		panic("overflow uint16")
	}
	binary.BigEndian.PutUint16(bytes, uint16(x))
	return bytes
}
<commit_msg>Fixed bad syntax in JSON struct tag<commit_after>package irma

import (
	"crypto/sha256"
	"encoding/binary"
	"encoding/hex"
	"time"

	"github.com/privacybydesign/gabi"
	"github.com/privacybydesign/gabi/big"

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

const (
	// ExpiryFactor is the precision for the expiry attribute. Value is one week.
	ExpiryFactor   = 60 * 60 * 24 * 7
	metadataLength = 1 + 3 + 2 + 2 + 16
)

var (
	versionField     = metadataField{1, 0}
	signingDateField = metadataField{3, 1}
	validityField    = metadataField{2, 4}
	keyCounterField  = metadataField{2, 6}
	credentialID     = metadataField{16, 8}
)

// metadataField contains the length and offset of a field within a metadata attribute.
type metadataField struct {
	length int
	offset int
}

// metadataAttribute represents a metadata attribute. Contains the credential type, signing date, validity, and the public key counter.
type MetadataAttribute struct {
	Int  *big.Int
	pk   *gabi.PublicKey
	Conf *Configuration
}

// AttributeList contains attributes, excluding the secret key,
// providing convenient access to the metadata attribute.
type AttributeList struct {
	*MetadataAttribute  `json:"-"`
	Ints                []*big.Int
	Revoked             bool `json:",omitempty"`
	RevocationSupported bool `json:",omitempty"`
	strings             []TranslatedString
	attrMap             map[AttributeTypeIdentifier]TranslatedString
	info                *CredentialInfo
	h                   string
}

// NewAttributeListFromInts initializes a new AttributeList from a list of bigints.
func NewAttributeListFromInts(ints []*big.Int, conf *Configuration) *AttributeList {
	metadata := MetadataFromInt(ints[0], conf)
	credtype := metadata.CredentialType()
	idx := credtype.RevocationIndex + 1
	var rev bool
	if credtype != nil {
		rev = len(ints) > idx && ints[idx] != nil && ints[idx].Cmp(bigZero) != 0
	}
	return &AttributeList{
		Ints:                ints,
		MetadataAttribute:   metadata,
		RevocationSupported: rev,
	}
}

func (al *AttributeList) Info() *CredentialInfo {
	if al.info == nil {
		al.info = al.CredentialInfo()
	}
	al.info.Revoked = al.Revoked
	return al.info
}

// EqualsExceptMetadata checks whether two AttributeLists have the same attribute values.
// The attribute containing the metadata information is skipped in this check.
func (al *AttributeList) EqualsExceptMetadata(ol *AttributeList) bool {
	if len(al.Ints) != len(ol.Ints) {
		return false
	}

	// Check whether value of all attributes, except for metadata attribute, is equal
	for i := 1; i < len(al.Ints); i++ {
		if al.Ints[i].Cmp(ol.Ints[i]) != 0 {
			return false
		}
	}
	return true
}

func (al *AttributeList) Hash() string {
	if al.h == "" {
		bytes := []byte{}
		for _, i := range al.Ints {
			bytes = append(bytes, i.Bytes()...)
		}
		shasum := sha256.Sum256(bytes)
		al.h = hex.EncodeToString(shasum[:])
	}
	return al.h
}

func (al *AttributeList) Map() map[AttributeTypeIdentifier]TranslatedString {
	if al.attrMap == nil {
		al.attrMap = make(map[AttributeTypeIdentifier]TranslatedString)
		ctid := al.CredentialType().Identifier()
		attrTypes := al.Conf.CredentialTypes[ctid].AttributeTypes
		for i, val := range al.Strings() {
			if attrTypes[i].RevocationAttribute {
				continue
			}
			al.attrMap[attrTypes[i].GetAttributeTypeIdentifier()] = val
		}
	}
	return al.attrMap
}

// Strings converts the current instance to human-readable strings.
func (al *AttributeList) Strings() []TranslatedString {
	if al.strings == nil {
		al.strings = make([]TranslatedString, len(al.Ints)-1)
		for i := range al.Ints[1:] { // skip metadata
			val := al.decode(i)
			if val == nil {
				continue
			}
			al.strings[i] = NewTranslatedString(val)
		}
	}
	return al.strings
}

// NewTranslatedString returns a TranslatedString containing the specified string for each supported language,
// or nil when attr is nil.
func NewTranslatedString(attr *string) TranslatedString {
	if attr == nil {
		return nil
	}
	return map[string]string{
		"":   *attr, // raw value
		"en": *attr,
		"nl": *attr,
	}
}

func (al *AttributeList) decode(i int) *string {
	attr := al.Ints[i+1]
	metadataVersion := al.MetadataAttribute.Version()
	return decodeAttribute(attr, metadataVersion)
}

// Decode attribute value into string according to metadataVersion
func decodeAttribute(attr *big.Int, metadataVersion byte) *string {
	bi := new(big.Int).Set(attr)
	if metadataVersion >= 3 {
		if bi.Bit(0) == 0 { // attribute does not exist
			return nil
		}
		bi.Rsh(bi, 1)
	}
	str := string(bi.Bytes())
	return &str
}

// UntranslatedAttribute decodes the bigint corresponding to the specified attribute.
func (al *AttributeList) UntranslatedAttribute(identifier AttributeTypeIdentifier) *string {
	if al.CredentialType().Identifier() != identifier.CredentialTypeIdentifier() {
		return nil
	}
	for i, desc := range al.CredentialType().AttributeTypes {
		if desc.ID == string(identifier.Name()) {
			return al.decode(i)
		}
	}
	return nil
}

// Attribute returns the content of the specified attribute, or nil if not present in this attribute list.
func (al *AttributeList) Attribute(identifier AttributeTypeIdentifier) TranslatedString {
	if al.CredentialType().Identifier() != identifier.CredentialTypeIdentifier() {
		return nil
	}

	for i, val := range al.Strings() {
		if al.CredentialType().AttributeTypes[i].ID == string(identifier.Name()) {
			return val
		}
	}

	return nil
}

// MetadataFromInt wraps the given Int
func MetadataFromInt(i *big.Int, conf *Configuration) *MetadataAttribute {
	return &MetadataAttribute{Int: i, Conf: conf}
}

// NewMetadataAttribute constructs a new instance containing the default values:
// provided version as versionField
// now as signing date
// 0 as keycounter
// ValidityDefault (half a year) as default validity.
func NewMetadataAttribute(version byte) *MetadataAttribute {
	val := MetadataAttribute{new(big.Int), nil, nil}
	val.setField(versionField, []byte{version})
	val.setSigningDate()
	val.setKeyCounter(0)
	val.setDefaultValidityDuration()
	return &val
}

// Bytes returns this metadata attribute as a byte slice.
// Bigint's Bytes() method returns a big-endian byte slice, so add padding at begin.
func (attr *MetadataAttribute) Bytes() []byte {
	bytes := attr.Int.Bytes()
	if len(bytes) < metadataLength {
		bytes = append(make([]byte, metadataLength-len(bytes)), bytes...)
	}
	return bytes
}

// PublicKey extracts identifier of the Idemix public key with which this instance was signed,
// and returns this public key.
func (attr *MetadataAttribute) PublicKey() (*gabi.PublicKey, error) {
	if attr.pk == nil {
		var err error
		attr.pk, err = attr.Conf.PublicKey(attr.CredentialType().IssuerIdentifier(), attr.KeyCounter())
		if err != nil {
			return nil, err
		}
	}
	return attr.pk, nil
}

// Version returns the metadata version of this instance
func (attr *MetadataAttribute) Version() byte {
	return attr.field(versionField)[0]
}

// SigningDate returns the time at which this instance was signed
func (attr *MetadataAttribute) SigningDate() time.Time {
	bytes := attr.field(signingDateField)
	bytes = bytes[1:] // The signing date field is one byte too long
	timestamp := int64(binary.BigEndian.Uint16(bytes)) * ExpiryFactor
	return time.Unix(timestamp, 0)
}

func (attr *MetadataAttribute) setSigningDate() {
	attr.setField(signingDateField, shortToByte(uint(time.Now().Unix()/ExpiryFactor)))
}

// KeyCounter return the public key counter of the metadata attribute
func (attr *MetadataAttribute) KeyCounter() uint {
	return uint(binary.BigEndian.Uint16(attr.field(keyCounterField)))
}

func (attr *MetadataAttribute) setKeyCounter(i uint) {
	attr.setField(keyCounterField, shortToByte(i))
}

// ValidityDuration returns the amount of epochs during which this instance is valid
func (attr *MetadataAttribute) ValidityDuration() int {
	return int(binary.BigEndian.Uint16(attr.field(validityField)))
}

func (attr *MetadataAttribute) setValidityDuration(weeks uint) {
	attr.setField(validityField, shortToByte(weeks))
}

func (attr *MetadataAttribute) setDefaultValidityDuration() {
	// setExpiryDate only errors if setting the expiry date before the signing date,
	// which never happens here
	_ = attr.setExpiryDate(nil)
}

func (attr *MetadataAttribute) setExpiryDate(timestamp *Timestamp) error {
	signingTimestamp := attr.SigningDate()
	var expiry int64
	if timestamp == nil {
		expiry = signingTimestamp.AddDate(0, 6, 0).Unix()
	} else {
		expiry = time.Time(*timestamp).Unix()
	}
	signing := signingTimestamp.Unix()
	if expiry-signing < 0 {
		return errors.New("cannot set expired date")
	}
	attr.setValidityDuration(uint((expiry - signing) / ExpiryFactor))
	return nil
}

// CredentialType returns the credential type of the current instance
// using the Configuration.
func (attr *MetadataAttribute) CredentialType() *CredentialType {
	return attr.Conf.hashToCredentialType(attr.field(credentialID))
}

func (attr *MetadataAttribute) setCredentialTypeIdentifier(id string) {
	bytes := sha256.Sum256([]byte(id))
	attr.setField(credentialID, bytes[:16])
}

func (attr *MetadataAttribute) CredentialTypeHash() []byte {
	return attr.field(credentialID)
}

// Expiry returns the expiry date of this instance
func (attr *MetadataAttribute) Expiry() time.Time {
	expiry := attr.SigningDate().Unix() + int64(attr.ValidityDuration()*ExpiryFactor)
	return time.Unix(expiry, 0)
}

// IsValidOn returns whether this instance is still valid at the given time
func (attr *MetadataAttribute) IsValidOn(t time.Time) bool {
	return attr.Expiry().After(t)
}

// IsValid returns whether this instance is valid.
func (attr *MetadataAttribute) IsValid() bool {
	return attr.IsValidOn(time.Now())
}

// FloorToEpochBoundary returns the greatest time not greater than the argument
// that falls on the boundary of an epoch for attribute validity or expiry,
// of which the value is defined by ExpiryFactor (one week).
func FloorToEpochBoundary(t time.Time) time.Time {
	return time.Unix((t.Unix()/ExpiryFactor)*ExpiryFactor, 0)
}

func (attr *MetadataAttribute) field(field metadataField) []byte {
	return attr.Bytes()[field.offset : field.offset+field.length]
}

func (attr *MetadataAttribute) setField(field metadataField, value []byte) {
	if len(value) > field.length {
		panic("Specified metadata field too large")
	}

	bytes := attr.Bytes()

	// Push the value to the right within the field. Graphical representation:
	// --xxxXXX----
	// "-" indicates a byte of another field
	// "X" is a byte of the value and "x" of our field
	// In this example, our field has offset 2, length 6,
	// but the specified value is only 3 bytes long.
	startindex := field.length - len(value)
	for i := 0; i < field.length; i++ {
		if i < startindex {
			bytes[i+field.offset] = 0
		} else {
			bytes[i+field.offset] = value[i-startindex]
		}
	}

	attr.Int.SetBytes(bytes)
}

func shortToByte(x uint) []byte {
	bytes := make([]byte, 2)
	if x > 1<<16 {
		panic("overflow uint16")
	}
	binary.BigEndian.PutUint16(bytes, uint16(x))
	return bytes
}
<|endoftext|>