<commit_before>package wallet

import (
	"os"
	"path/filepath"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/persist"
	"github.com/NebulousLabs/Sia/types"
)

type savedKey struct {
	SecretKey        crypto.SecretKey
	UnlockConditions types.UnlockConditions
	Visible          bool
}

// legacySavedKey preserves compatibility with the other beta wallets. After
// the full currency is launched, this struct and the related code can be
// discarded.
type legacySavedKey struct {
	SecretKey        crypto.SecretKey
	UnlockConditions types.UnlockConditions
}

// save writes the contents of a wallet to a file.
func (w *Wallet) save() error {
	// Convert the key map to a slice.
	keySlice := make([]savedKey, 0, len(w.keys))
	for _, key := range w.keys {
		_, exists := w.visibleAddresses[key.unlockConditions.UnlockHash()]
		keySlice = append(keySlice, savedKey{key.secretKey, key.unlockConditions, exists})
	}
	// Write the wallet data to a backup file, in case something goes wrong
	err := encoding.WriteFile(filepath.Join(w.saveDir, "wallet.backup"), keySlice)
	if err != nil {
		return err
	}
	// Overwrite the wallet file.
	err = encoding.WriteFile(filepath.Join(w.saveDir, "wallet.dat"), keySlice)
	if err != nil {
		// TODO: instruct user to recover wallet from the backup file
		return err
	}
	// Save to home.
	err = encoding.WriteFile(filepath.Join(persist.HomeFolder, modules.WalletDir, "wallet.dat"), keySlice)
	if err != nil {
		return err
	}

	// Create a second file for the siafunds. This is another
	// deprecated-on-arrival file.
	siafundSlice := make([]types.UnlockHash, 0, len(w.siafundAddresses))
	for sa, _ := range w.siafundAddresses {
		siafundSlice = append(siafundSlice, sa)
	}
	// outputs.dat is intentionally a bit of a misleading name. If I called it
	// 'siafunds.dat' or something similar, people might think it's okay to
	// delete their siafund keys, which is NOT okay. Instead of potentially
	// having this confusion, I chose a less suggestive name.
	err = encoding.WriteFile(filepath.Join(w.saveDir, "outputs.backup"), siafundSlice)
	if err != nil {
		return err
	}
	err = encoding.WriteFile(filepath.Join(w.saveDir, "outputs.dat"), siafundSlice)
	if err != nil {
		return err
	}
	// Save to home.
	err = encoding.WriteFile(filepath.Join(persist.HomeFolder, modules.WalletDir, "outputs.dat"), siafundSlice)
	if err != nil {
		return err
	}

	return nil
}

// loadKeys takes a set of keys and loads them into the wallet.
func (w *Wallet) loadKeys(savedKeys []savedKey) error {
	height := w.consensusHeight
	for _, skey := range savedKeys {
		// Create an entry in w.keys for each savedKey.
		w.keys[skey.UnlockConditions.UnlockHash()] = &key{
			spendable:        height >= skey.UnlockConditions.Timelock,
			unlockConditions: skey.UnlockConditions,
			secretKey:        skey.SecretKey,
			outputs:          make(map[types.SiacoinOutputID]*knownOutput),
		}

		// If Timelock != 0, also add to set of timelockedKeys.
		if tl := skey.UnlockConditions.Timelock; tl != 0 {
			w.timelockedKeys[tl] = append(w.timelockedKeys[tl], skey.UnlockConditions.UnlockHash())
		}

		if skey.Visible {
			w.visibleAddresses[skey.UnlockConditions.UnlockHash()] = struct{}{}
		}
	}

	// If there are no visible addresses, create one.
	if len(w.visibleAddresses) == 0 {
		_, _, err := w.coinAddress(true)
		if err != nil {
			return err
		}
	}

	return nil
}

// load reads the contents of a wallet from a file.
func (w *Wallet) load() error {
	// Check if 'wallet.dat' exists. If not, check for it in the homedir.
	var savedKeys []savedKey
	walletFile := filepath.Join(w.saveDir, "wallet.dat")
	_, err := os.Stat(walletFile)
	if os.IsNotExist(err) {
		// Check the homedir file.
		homedirFile := filepath.Join(persist.HomeFolder, modules.WalletDir, "wallet.dat")
		_, err := os.Stat(homedirFile)
		if err != nil {
			return err
		}
		err = encoding.ReadFile(homedirFile, &savedKeys)
		if err != nil {
			return err
		}
		return w.loadKeys(savedKeys)
	}

	// Load the standard file.
	err = encoding.ReadFile(walletFile, &savedKeys)
	if err != nil {
		var legacyKeys []legacySavedKey
		err = encoding.ReadFile(walletFile, &legacyKeys)
		if err != nil {
			return err
		}

		for _, key := range legacyKeys {
			savedKeys = append(savedKeys, savedKey{key.SecretKey, key.UnlockConditions, false})
		}
	}
	err = w.loadKeys(savedKeys)
	if err != nil {
		return err
	}

	// Load the siafunds file, which is intentionally called 'outputs.dat'.
	var siafundAddresses []types.UnlockHash
	err = encoding.ReadFile(filepath.Join(w.saveDir, "outputs.dat"), &siafundAddresses)
	if err != nil {
		return err
	}
	for _, sa := range siafundAddresses {
		w.siafundAddresses[sa] = struct{}{}
	}
	return nil
}
<commit_msg>saner wallet loading<commit_after>package wallet

import (
	"path/filepath"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/persist"
	"github.com/NebulousLabs/Sia/types"
)

type savedKey struct {
	SecretKey        crypto.SecretKey
	UnlockConditions types.UnlockConditions
	Visible          bool
}

// legacySavedKey preserves compatibility with the other beta wallets. After
// the full currency is launched, this struct and the related code can be
// discarded.
type legacySavedKey struct {
	SecretKey        crypto.SecretKey
	UnlockConditions types.UnlockConditions
}

// save writes the contents of a wallet to a file.
func (w *Wallet) save() error {
	// Convert the key map to a slice.
	keySlice := make([]savedKey, 0, len(w.keys))
	for _, key := range w.keys {
		_, exists := w.visibleAddresses[key.unlockConditions.UnlockHash()]
		keySlice = append(keySlice, savedKey{key.secretKey, key.unlockConditions, exists})
	}
	// Write the wallet data to a backup file, in case something goes wrong
	err := encoding.WriteFile(filepath.Join(w.saveDir, "wallet.backup"), keySlice)
	if err != nil {
		return err
	}
	// Save to home.
	err = encoding.WriteFile(filepath.Join(persist.HomeFolder, modules.WalletDir, "wallet.dat"), keySlice)
	if err != nil {
		// TODO: instruct user to recover wallet from the backup file
		return err
	}

	// Create a second file for the siafunds. This is another
	// deprecated-on-arrival file.
	siafundSlice := make([]types.UnlockHash, 0, len(w.siafundAddresses))
	for sa, _ := range w.siafundAddresses {
		siafundSlice = append(siafundSlice, sa)
	}
	// outputs.dat is intentionally a bit of a misleading name. If I called it
	// 'siafunds.dat' or something similar, people might think it's okay to
	// delete their siafund keys, which is NOT okay. Instead of potentially
	// having this confusion, I chose a less suggestive name.
	err = encoding.WriteFile(filepath.Join(w.saveDir, "outputs.backup"), siafundSlice)
	if err != nil {
		return err
	}
	// Save to home.
	err = encoding.WriteFile(filepath.Join(persist.HomeFolder, modules.WalletDir, "outputs.dat"), siafundSlice)
	if err != nil {
		return err
	}

	return nil
}

// loadKeys takes a set of keys and loads them into the wallet.
func (w *Wallet) loadKeys(savedKeys []savedKey) error {
	height := w.consensusHeight
	for _, skey := range savedKeys {
		// Create an entry in w.keys for each savedKey.
		w.keys[skey.UnlockConditions.UnlockHash()] = &key{
			spendable:        height >= skey.UnlockConditions.Timelock,
			unlockConditions: skey.UnlockConditions,
			secretKey:        skey.SecretKey,
			outputs:          make(map[types.SiacoinOutputID]*knownOutput),
		}

		// If Timelock != 0, also add to set of timelockedKeys.
		if tl := skey.UnlockConditions.Timelock; tl != 0 {
			w.timelockedKeys[tl] = append(w.timelockedKeys[tl], skey.UnlockConditions.UnlockHash())
		}

		if skey.Visible {
			w.visibleAddresses[skey.UnlockConditions.UnlockHash()] = struct{}{}
		}
	}

	// If there are no visible addresses, create one.
	if len(w.visibleAddresses) == 0 {
		_, _, err := w.coinAddress(true)
		if err != nil {
			return err
		}
	}

	return nil
}

// load reads the contents of a wallet from a file.
func (w *Wallet) load() error {
	var savedKeys []savedKey
	err := encoding.ReadFile(filepath.Join(persist.HomeFolder, modules.WalletDir, "wallet.dat"), &savedKeys)
	if err != nil {
		// try loading the backup
		// TODO: display/log a warning?
		err = encoding.ReadFile(filepath.Join(w.saveDir, "wallet.backup"), &savedKeys)
		if err != nil {
			return err
		}
	}
	err = w.loadKeys(savedKeys)
	if err != nil {
		return err
	}

	// Load the siafunds file, which is intentionally called 'outputs.dat'.
	var siafundAddresses []types.UnlockHash
	err = encoding.ReadFile(filepath.Join(persist.HomeFolder, modules.WalletDir, "outputs.dat"), &siafundAddresses)
	if err != nil {
		// try loading the backup
		// TODO: display/log a warning?
		err = encoding.ReadFile(filepath.Join(w.saveDir, "outputs.backup"), &siafundAddresses)
		if err != nil {
			return err
		}
	}
	for _, sa := range siafundAddresses {
		w.siafundAddresses[sa] = struct{}{}
	}

	return nil
}
<|endoftext|>


<commit_before>package parsers

import (
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

type VersionQuery struct {
	LatestVersion   bool
	VersionPrefix   string
	SpecificVersion string
	SpecificTag     string
}

func ParseVersionQuery(v string) (*VersionQuery, error) {
	if v == "" {
		return nil, fmt.Errorf("Empty version query")
	}
	if v == "latest" || v == "@" || v == "v@" {
		return &VersionQuery{
			LatestVersion: true,
		}, nil
	} else if strings.HasPrefix(v, "v") {
		vq := maybeParseVersionQuery(v[1:])
		if vq != nil {
			return vq, nil
		}
	} else if unicode.IsDigit(rune(v[0])) {
		vq := maybeParseVersionQuery(v)
		if vq != nil {
			return vq, nil
		}
	}
	return &VersionQuery{
		SpecificTag: v,
	}, nil
}

func maybeParseVersionQuery(versionQuery string) *VersionQuery {
	if versionQuery == "" {
		return nil
	}
	parts := strings.Split(versionQuery, ".")
	if parts[len(parts)-1] == "@" {
		return &VersionQuery{
			VersionPrefix: versionQuery[:len(versionQuery)-1],
		}
	}
	if isSemanticVersion(parts) {
		return &VersionQuery{
			SpecificVersion: versionQuery,
		}
	}
	return nil
}

func isSemanticVersion(parts []string) bool {
	legitVersion := true
	for _, part := range parts {
		i, err := strconv.Atoi(part)
		if err != nil || i < 0 {
			legitVersion = false
			break
		}
	}
	return legitVersion
}
<commit_msg>Pretty printing for version queries<commit_after>package parsers

import (
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

type VersionQuery struct {
	LatestVersion   bool
	VersionPrefix   string
	SpecificVersion string
	SpecificTag     string
}

func ParseVersionQuery(v string) (*VersionQuery, error) {
	if v == "" {
		return nil, fmt.Errorf("Empty version query")
	}
	if v == "latest" || v == "@" || v == "v@" {
		return &VersionQuery{
			LatestVersion: true,
		}, nil
	} else if strings.HasPrefix(v, "v") {
		vq := maybeParseVersionQuery(v[1:])
		if vq != nil {
			return vq, nil
		}
	} else if unicode.IsDigit(rune(v[0])) {
		vq := maybeParseVersionQuery(v)
		if vq != nil {
			return vq, nil
		}
	}
	return &VersionQuery{
		SpecificTag: v,
	}, nil
}

func (v *VersionQuery) ToString() string {
	if v.LatestVersion {
		return "latest"
	} else if v.VersionPrefix != "" {
		return "v" + v.VersionPrefix + "@"
	} else if v.SpecificVersion != "" {
		return "v" + v.SpecificVersion
	}
	return v.SpecificTag
}

func (v *VersionQuery) ToVersionSuffix() string {
	sep := "-"
	if v.SpecificTag != "" {
		sep = ":"
	}
	return sep + v.ToString()
}

func maybeParseVersionQuery(versionQuery string) *VersionQuery {
	if versionQuery == "" {
		return nil
	}
	parts := strings.Split(versionQuery, ".")
	if parts[len(parts)-1] == "@" {
		return &VersionQuery{
			VersionPrefix: versionQuery[:len(versionQuery)-1],
		}
	}
	if isSemanticVersion(parts) {
		return &VersionQuery{
			SpecificVersion: versionQuery,
		}
	}
	return nil
}

func isSemanticVersion(parts []string) bool {
	legitVersion := true
	for _, part := range parts {
		i, err := strconv.Atoi(part)
		if err != nil || i < 0 {
			legitVersion = false
			break
		}
	}
	return legitVersion
}
<|endoftext|>


<commit_before>package fdcount

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"time"
)

var (
	maxAssertAttempts = uint(7)
)

// Matching returns a count of the file descriptors matching the given string (not a
// regex). Also returns a Counter that can be used to check the delta of file
// descriptors after this point.
//
// Currently only works on systems that have the lsof command available.
//
// see https://groups.google.com/forum/#!topic/golang-nuts/c0AnWXjzNIA
//
func Matching(match string) (int, *Counter, error) {
	c := &Counter{match: match}

	// Count initial file descriptors
	out, err := runLsof()
	if err != nil {
		return 0, nil, err
	}
	c.startingLines, c.startingCount = c.matchingLines(out)
	return c.startingCount, c, nil
}

// WaitUntilNoneMatch waits until no file descriptors match the given string, or
// the timeout is hit.
func WaitUntilNoneMatch(match string, timeout time.Duration) error {
	start := time.Now()
	var out []byte
	var err error
	var count int

	for time.Now().Sub(start) < timeout {
		out, err = runLsof()
		if err != nil {
			return err
		}
		_, count = matchingLines(match, out)
		if count == 0 {
			// Success!
			return nil
		}
		time.Sleep(50 * time.Millisecond)
	}

	return fmt.Errorf("%d lines still match %v\n\n%v", count, match, string(out))
}

// Counter memorizes the number of file descriptors and compare them.
type Counter struct {
	match         string
	startingLines string
	startingCount int
}

// AssertDelta asserts that the number of file descriptors added/removed since Counter was
// created equals the given number.
func (c *Counter) AssertDelta(expected int) error {
	var err error

	for try := uint(0); try < maxAssertAttempts; try++ {
		err = c.doAssertDelta(expected)
		if err == nil {
			return nil
		}
		// Count didn't match, could be we have some lingering descriptors, wait
		// and then try again.
		time.Sleep((50 << try) * time.Millisecond)
	}

	return err
}

func (c *Counter) doAssertDelta(expected int) error {
	out, err := runLsof()
	if err != nil {
		return err
	}
	endingLines, endingCount := c.matchingLines(out)
	actual := endingCount - c.startingCount
	if actual != expected {
		return fmt.Errorf("Unexpected TCP file descriptor count. Expected %d, have %d.\n\n%s",
			expected, actual, lsofDelta(c.startingLines, endingLines))
	}
	return nil
}

func (c *Counter) matchingLines(out []byte) (string, int) {
	return matchingLines(c.match, out)
}

func matchingLines(match string, out []byte) (string, int) {
	var lines []string
	for _, line := range strings.Split(string(out), "\n") {
		if strings.Contains(line, match) {
			lines = append(lines, line)
		}
	}
	return strings.Join(lines, "\n"), len(lines)
}

func runLsof() ([]byte, error) {
	out, err := exec.Command("lsof", "-p", fmt.Sprintf("%v", os.Getpid())).Output()
	if err != nil {
		err = fmt.Errorf("Unable to run lsof: %v", err)
	}
	return out, err
}

func lsofDelta(start string, end string) string {
	startLines := strings.Split(start, "\n")
	endLines := strings.Split(end, "\n")

	added := make(map[string]interface{})
	removed := make(map[string]interface{})

	for _, line := range startLines {
		removed[line] = nil
	}

	for _, line := range endLines {
		added[line] = nil
		delete(removed, line)
	}

	for _, line := range startLines {
		delete(added, line)
	}

	a := make([]string, 0, len(added))
	r := make([]string, 0, len(removed))

	for line := range added {
		a = append(a, line)
	}

	for line := range removed {
		r = append(r, line)
	}

	result := ""
	if len(r) > 0 {
		result = fmt.Sprintf("Removed file descriptors\n-----------------------------\n%v\n",
			strings.Join(r, "\n"))
	}
	if len(a) > 0 {
		if len(r) > 0 {
			result = result + "\n"
		}
		result = fmt.Sprintf("%sNew file descriptors\n-----------------------------\n%v\n",
			result, strings.Join(a, "\n"))
	}
	return result
}
<commit_msg>Using mtime to measure elapsed time<commit_after>package fdcount

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/getlantern/mtime"
)

var (
	maxAssertAttempts = uint(7)
)

// Matching returns a count of the file descriptors matching the given string (not a
// regex). Also returns a Counter that can be used to check the delta of file
// descriptors after this point.
//
// Currently only works on systems that have the lsof command available.
//
// see https://groups.google.com/forum/#!topic/golang-nuts/c0AnWXjzNIA
//
func Matching(match string) (int, *Counter, error) {
	c := &Counter{match: match}

	// Count initial file descriptors
	out, err := runLsof()
	if err != nil {
		return 0, nil, err
	}
	c.startingLines, c.startingCount = c.matchingLines(out)
	return c.startingCount, c, nil
}

// WaitUntilNoneMatch waits until no file descriptors match the given string, or
// the timeout is hit.
func WaitUntilNoneMatch(match string, timeout time.Duration) error {
	elapsed := mtime.Stopwatch()
	var out []byte
	var err error
	var count int

	for elapsed() < timeout {
		out, err = runLsof()
		if err != nil {
			return err
		}
		_, count = matchingLines(match, out)
		if count == 0 {
			// Success!
			return nil
		}
		time.Sleep(50 * time.Millisecond)
	}

	return fmt.Errorf("%d lines still match %v\n\n%v", count, match, string(out))
}

// Counter memorizes the number of file descriptors and compare them.
type Counter struct {
	match         string
	startingLines string
	startingCount int
}

// AssertDelta asserts that the number of file descriptors added/removed since Counter was
// created equals the given number.
func (c *Counter) AssertDelta(expected int) error {
	var err error

	for try := uint(0); try < maxAssertAttempts; try++ {
		err = c.doAssertDelta(expected)
		if err == nil {
			return nil
		}
		// Count didn't match, could be we have some lingering descriptors, wait
		// and then try again.
		time.Sleep((50 << try) * time.Millisecond)
	}

	return err
}

func (c *Counter) doAssertDelta(expected int) error {
	out, err := runLsof()
	if err != nil {
		return err
	}
	endingLines, endingCount := c.matchingLines(out)
	actual := endingCount - c.startingCount
	if actual != expected {
		return fmt.Errorf("Unexpected TCP file descriptor count. Expected %d, have %d.\n\n%s",
			expected, actual, lsofDelta(c.startingLines, endingLines))
	}
	return nil
}

func (c *Counter) matchingLines(out []byte) (string, int) {
	return matchingLines(c.match, out)
}

func matchingLines(match string, out []byte) (string, int) {
	var lines []string
	for _, line := range strings.Split(string(out), "\n") {
		if strings.Contains(line, match) {
			lines = append(lines, line)
		}
	}
	return strings.Join(lines, "\n"), len(lines)
}

func runLsof() ([]byte, error) {
	out, err := exec.Command("lsof", "-p", fmt.Sprintf("%v", os.Getpid())).Output()
	if err != nil {
		err = fmt.Errorf("Unable to run lsof: %v", err)
	}
	return out, err
}

func lsofDelta(start string, end string) string {
	startLines := strings.Split(start, "\n")
	endLines := strings.Split(end, "\n")

	added := make(map[string]interface{})
	removed := make(map[string]interface{})

	for _, line := range startLines {
		removed[line] = nil
	}

	for _, line := range endLines {
		added[line] = nil
		delete(removed, line)
	}

	for _, line := range startLines {
		delete(added, line)
	}

	a := make([]string, 0, len(added))
	r := make([]string, 0, len(removed))

	for line := range added {
		a = append(a, line)
	}

	for line := range removed {
		r = append(r, line)
	}

	result := ""
	if len(r) > 0 {
		result = fmt.Sprintf("Removed file descriptors\n-----------------------------\n%v\n",
			strings.Join(r, "\n"))
	}
	if len(a) > 0 {
		if len(r) > 0 {
			result = result + "\n"
		}
		result = fmt.Sprintf("%sNew file descriptors\n-----------------------------\n%v\n",
			result, strings.Join(a, "\n"))
	}
	return result
}
<|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.

// Write out a file of a certain size, close it, then measure the performance
// of doing the following:
//
// 1.  Open the file.
// 2.  Read it from start to end with a configurable buffer size.
//
package main

import (
	"crypto/rand"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"time"
)

var fDir = flag.String("dir", "", "Directory within which to write the file.")
var fFileSize = flag.Int64("file_size", 1<<20, "Size of file to use.")
var fReadSize = flag.Int("read_size", 1<<14, "Size of each call to read(2).")

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type DurationSlice []time.Duration

func (p DurationSlice) Len() int           { return len(p) }
func (p DurationSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p DurationSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// REQUIRES: vals is sorted.
// REQUIRES: len(vals) > 0
// REQUIRES: 0 <= n <= 100
func percentile(
	vals DurationSlice,
	n int) (x time.Duration) {
	// Special cases.
	switch {
	case n == 0:
		x = vals[0]
		return

	case n == 100:
		x = vals[len(vals)-1]
		return
	}

	// Find the nearest, truncating (why not).
	index := int((float64(n) / 100) * float64(len(vals)))
	x = vals[index]

	return
}

func formatBytes(v float64) string {
	switch {
	case v >= 1<<30:
		return fmt.Sprintf("%.2f GiB", v/(1<<30))

	case v >= 1<<20:
		return fmt.Sprintf("%.2f MiB", v/(1<<20))

	case v >= 1<<10:
		return fmt.Sprintf("%.2f KiB", v/(1<<10))

	default:
		return fmt.Sprintf("%.2f bytes", v)
	}
}

////////////////////////////////////////////////////////////////////////
// main logic
////////////////////////////////////////////////////////////////////////

func run() (err error) {
	if *fDir == "" {
		err = errors.New("You must set --dir.")
		return
	}

	// Create a temporary file.
	log.Printf("Creating a temporary file in %s.", *fDir)

	f, err := ioutil.TempFile(*fDir, "sequential_read")
	if err != nil {
		err = fmt.Errorf("TempFile: %v", err)
		return
	}

	path := f.Name()

	// Make sure we clean it up later.
	defer func() {
		log.Printf("Deleting %s.", path)
		os.Remove(path)
	}()

	// Fill it with random content.
	log.Printf("Writing %d random bytes.", *fFileSize)
	_, err = io.Copy(f, io.LimitReader(rand.Reader, *fFileSize))
	if err != nil {
		err = fmt.Errorf("Copying random bytes: %v", err)
		return
	}

	// Finish off the file.
	err = f.Close()
	if err != nil {
		err = fmt.Errorf("Closing file: %v", err)
		return
	}

	// Run several iterations.
	const duration = 5 * time.Second
	log.Printf("Measuring for %v...", duration)

	var observations DurationSlice
	buf := make([]byte, *fReadSize)

	overallStartTime := time.Now()
	for len(observations) == 0 || time.Since(overallStartTime) < duration {
		// Open the file for reading.
		f, err = os.Open(path)
		if err != nil {
			err = fmt.Errorf("Opening file: %v", err)
			return
		}

		// Read the whole thing.
		readStartTime := time.Now()
		for err == nil {
			_, err = f.Read(buf)
		}

		readDuration := time.Since(readStartTime)
		observations = append(observations, readDuration)

		switch {
		case err == io.EOF:
			err = nil

		case err != nil:
			err = fmt.Errorf("Reading: %v", err)
			return
		}

		// Close the file.
		err = f.Close()
		if err != nil {
			err = fmt.Errorf("Closing file after reading: %v", err)
			return
		}
	}

	sort.Sort(observations)

	// Report.
	fmt.Println("Full-file read times:")

	ptiles := []int{50, 90, 98}
	for _, ptile := range ptiles {
		d := percentile(observations, ptile)
		seconds := float64(d) / float64(time.Second)
		bandwidthBytesPerSec := float64(*fFileSize) / seconds

		fmt.Printf(
			"  %02dth ptile: %10v (%s/s)\n",
			ptile,
			d,
			formatBytes(bandwidthBytesPerSec))
	}

	return
}

func main() {
	log.SetFlags(log.Lmicroseconds | log.Lshortfile)
	flag.Parse()

	err := run()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<commit_msg>Include individual read latencies, too.<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.

// Write out a file of a certain size, close it, then measure the performance
// of doing the following:
//
// 1.  Open the file.
// 2.  Read it from start to end with a configurable buffer size.
//
package main

import (
	"crypto/rand"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"time"
)

var fDir = flag.String("dir", "", "Directory within which to write the file.")
var fFileSize = flag.Int64("file_size", 1<<20, "Size of file to use.")
var fReadSize = flag.Int("read_size", 1<<14, "Size of each call to read(2).")

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type DurationSlice []time.Duration

func (p DurationSlice) Len() int           { return len(p) }
func (p DurationSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p DurationSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// REQUIRES: vals is sorted.
// REQUIRES: len(vals) > 0
// REQUIRES: 0 <= n <= 100
func percentile(
	vals DurationSlice,
	n int) (x time.Duration) {
	// Special cases.
	switch {
	case n == 0:
		x = vals[0]
		return

	case n == 100:
		x = vals[len(vals)-1]
		return
	}

	// Find the nearest, truncating (why not).
	index := int((float64(n) / 100) * float64(len(vals)))
	x = vals[index]

	return
}

func formatBytes(v float64) string {
	switch {
	case v >= 1<<30:
		return fmt.Sprintf("%.2f GiB", v/(1<<30))

	case v >= 1<<20:
		return fmt.Sprintf("%.2f MiB", v/(1<<20))

	case v >= 1<<10:
		return fmt.Sprintf("%.2f KiB", v/(1<<10))

	default:
		return fmt.Sprintf("%.2f bytes", v)
	}
}

////////////////////////////////////////////////////////////////////////
// main logic
////////////////////////////////////////////////////////////////////////

func run() (err error) {
	if *fDir == "" {
		err = errors.New("You must set --dir.")
		return
	}

	// Create a temporary file.
	log.Printf("Creating a temporary file in %s.", *fDir)

	f, err := ioutil.TempFile(*fDir, "sequential_read")
	if err != nil {
		err = fmt.Errorf("TempFile: %v", err)
		return
	}

	path := f.Name()

	// Make sure we clean it up later.
	defer func() {
		log.Printf("Deleting %s.", path)
		os.Remove(path)
	}()

	// Fill it with random content.
	log.Printf("Writing %d random bytes.", *fFileSize)
	_, err = io.Copy(f, io.LimitReader(rand.Reader, *fFileSize))
	if err != nil {
		err = fmt.Errorf("Copying random bytes: %v", err)
		return
	}

	// Finish off the file.
	err = f.Close()
	if err != nil {
		err = fmt.Errorf("Closing file: %v", err)
		return
	}

	// Run several iterations.
	const duration = 5 * time.Second
	log.Printf("Measuring for %v...", duration)

	var fullFileRead DurationSlice
	var singleReadCall DurationSlice
	buf := make([]byte, *fReadSize)

	overallStartTime := time.Now()
	for len(fullFileRead) == 0 || time.Since(overallStartTime) < duration {
		// Open the file for reading.
		f, err = os.Open(path)
		if err != nil {
			err = fmt.Errorf("Opening file: %v", err)
			return
		}

		// Read the whole thing.
		fileStartTime := time.Now()
		for err == nil {
			readStartTime := time.Now()
			_, err = f.Read(buf)
			singleReadCall = append(singleReadCall, time.Since(readStartTime))
		}

		fullFileRead = append(fullFileRead, time.Since(fileStartTime))

		switch {
		case err == io.EOF:
			err = nil

		case err != nil:
			err = fmt.Errorf("Reading: %v", err)
			return
		}

		// Close the file.
		err = f.Close()
		if err != nil {
			err = fmt.Errorf("Closing file after reading: %v", err)
			return
		}
	}

	sort.Sort(fullFileRead)
	sort.Sort(singleReadCall)

	// Report.
	ptiles := []int{50, 90, 98}

	reportSlice := func(name string, observations DurationSlice) {
		fmt.Printf("\n%s:\n", name)
		for _, ptile := range ptiles {
			d := percentile(observations, ptile)
			seconds := float64(d) / float64(time.Second)
			bandwidthBytesPerSec := float64(*fFileSize) / seconds

			fmt.Printf(
				"  %02dth ptile: %10v (%s/s)\n",
				ptile,
				d,
				formatBytes(bandwidthBytesPerSec))
		}
	}

	reportSlice("Full-file read times", fullFileRead)
	reportSlice("read(2) latencies", singleReadCall)

	fmt.Println()

	return
}

func main() {
	log.SetFlags(log.Lmicroseconds | log.Lshortfile)
	flag.Parse()

	err := run()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/ikawaha/kagome/tokenizer"
	"strings"

	"unicode/utf8"
)

type FeatureVector []string

func ExtractNounFeatures(s string, prefix string) FeatureVector {
	var fv FeatureVector
	if s == "" {
		return fv
	}
	t := tokenizer.New()
	tokens := t.Tokenize(s)
	for _, token := range tokens {
		if token.Pos() == "名詞" {
			fv = append(fv, prefix+":"+token.Surface)
		}
	}
	return fv
}

func ExtractFeatures(e Example) FeatureVector {
	var fv FeatureVector

	html := strings.ToLower(strings.Replace(e.RawHTML, " ", "", -1))
	if !utf8.ValidString(html) {
		return fv
	}

	if !utf8.ValidString(e.Title) {
		return fv
	}
	fv = append(fv, ExtractNounFeatures(e.Title, "TITLE")...)

	if !utf8.ValidString(e.Description) {
		return fv
	}
	fv = append(fv, ExtractNounFeatures(e.Description, "DESCRIPTION")...)

	if !utf8.ValidString(e.Body) {
		return fv
	}
	fv = append(fv, ExtractNounFeatures(e.Body, "BODY")...)

	return fv
}
<commit_msg>goimport<commit_after>package main

import (
	"strings"

	"github.com/ikawaha/kagome/tokenizer"

	"unicode/utf8"
)

type FeatureVector []string

func ExtractNounFeatures(s string, prefix string) FeatureVector {
	var fv FeatureVector
	if s == "" {
		return fv
	}
	t := tokenizer.New()
	tokens := t.Tokenize(s)
	for _, token := range tokens {
		if token.Pos() == "名詞" {
			fv = append(fv, prefix+":"+token.Surface)
		}
	}
	return fv
}

func ExtractFeatures(e Example) FeatureVector {
	var fv FeatureVector

	html := strings.ToLower(strings.Replace(e.RawHTML, " ", "", -1))
	if !utf8.ValidString(html) {
		return fv
	}

	if !utf8.ValidString(e.Title) {
		return fv
	}
	fv = append(fv, ExtractNounFeatures(e.Title, "TITLE")...)

	if !utf8.ValidString(e.Description) {
		return fv
	}
	fv = append(fv, ExtractNounFeatures(e.Description, "DESCRIPTION")...)

	if !utf8.ValidString(e.Body) {
		return fv
	}
	fv = append(fv, ExtractNounFeatures(e.Body, "BODY")...)

	return fv
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package fft provides forward and inverse fast Fourier transform functions.
package fft

import (
	"math"
	"sync"

	"github.com/mjibson/go-dsp/dsputils"
)

var (
	radix2Lock    sync.RWMutex
	radix2Factors = map[int][]complex128{
		4: {complex(1, 0), complex(0, -1), complex(-1, 0), complex(0, 1)},
	}
)

var (
	bluesteinLock       sync.RWMutex
	bluesteinFactors    = map[int][]complex128{}
	bluesteinInvFactors = map[int][]complex128{}
)

// EnsureRadix2Factors ensures that all radix 2 factors are computed for inputs
// of length input_len. This is used to precompute needed factors for known
// sizes. Generally should only be used for benchmarks.
func EnsureRadix2Factors(input_len int) {
	getRadix2Factors(input_len)
}

func getRadix2Factors(input_len int) []complex128 {
	radix2Lock.RLock()

	if hasRadix2Factors(input_len) {
		defer radix2Lock.RUnlock()
		return radix2Factors[input_len]
	}

	radix2Lock.RUnlock()
	radix2Lock.Lock()
	defer radix2Lock.Unlock()

	if !hasRadix2Factors(input_len) {
		for i, p := 8, 4; i <= input_len; i, p = i<<1, i {
			if radix2Factors[i] == nil {
				radix2Factors[i] = make([]complex128, i)

				for n, j := 0, 0; n < i; n, j = n+2, j+1 {
					radix2Factors[i][n] = radix2Factors[p][j]
				}

				for n := 1; n < i; n += 2 {
					sin, cos := math.Sincos(-2 * math.Pi / float64(i) * float64(n))
					radix2Factors[i][n] = complex(cos, sin)
				}
			}
		}
	}

	return radix2Factors[input_len]
}

func hasRadix2Factors(idx int) bool {
	return radix2Factors[idx] != nil
}

func getBluesteinFactors(input_len int) ([]complex128, []complex128) {
	bluesteinLock.RLock()

	if hasBluesteinFactors(input_len) {
		defer bluesteinLock.RUnlock()
		return bluesteinFactors[input_len], bluesteinInvFactors[input_len]
	}

	bluesteinLock.RUnlock()
	bluesteinLock.Lock()
	defer bluesteinLock.Unlock()

	if !hasBluesteinFactors(input_len) {
		bluesteinFactors[input_len] = make([]complex128, input_len)
		bluesteinInvFactors[input_len] = make([]complex128, input_len)

		var sin, cos float64
		for i := 0; i < input_len; i++ {
			if i == 0 {
				sin, cos = 0, 1
			} else {
				sin, cos = math.Sincos(math.Pi / float64(input_len) * float64(i*i))
			}
			bluesteinFactors[input_len][i] = complex(cos, sin)
			bluesteinInvFactors[input_len][i] = complex(cos, -sin)
		}
	}

	return bluesteinFactors[input_len], bluesteinInvFactors[input_len]
}

func hasBluesteinFactors(idx int) bool {
	return bluesteinFactors[idx] != nil
}

// FFTReal returns the forward FFT of the real-valued slice.
func FFTReal(x []float64) []complex128 {
	return FFT(dsputils.ToComplex(x))
}

// IFFTReal returns the inverse FFT of the real-valued slice.
func IFFTReal(x []float64) []complex128 {
	return IFFT(dsputils.ToComplex(x))
}

// IFFT returns the inverse FFT of the complex-valued slice.
func IFFT(x []complex128) []complex128 {
	lx := len(x)
	r := make([]complex128, lx)

	// Reverse inputs, which is calculated with modulo N, hence x[0] as an outlier
	r[0] = x[0]
	for i := 1; i < lx; i++ {
		r[i] = x[lx-i]
	}

	r = FFT(r)

	N := complex(float64(lx), 0)
	for n, _ := range r {
		r[n] /= N
	}
	return r
}

// Convolve returns the convolution of x * y.
func Convolve(x, y []complex128) []complex128 {
	if len(x) != len(y) {
		panic("arrays not of equal size")
	}

	fft_x := FFT(x)
	fft_y := FFT(y)

	r := make([]complex128, len(x))
	for i := 0; i < len(r); i++ {
		r[i] = fft_x[i] * fft_y[i]
	}

	return IFFT(r)
}

// FFT returns the forward FFT of the complex-valued slice.
func FFT(x []complex128) []complex128 {
	lx := len(x)

	// todo: non-hack handling length <= 1 cases
	if lx <= 1 {
		r := make([]complex128, lx)
		copy(r, x)
		return r
	}

	if dsputils.IsPowerOf2(lx) {
		return radix2FFT(x)
	}

	return bluesteinFFT(x)
}

var (
	worker_pool_size = 1
)

// SetWorkerPoolSize sets the number of workers during FFT computation on
// multicore systems. This should generally be set to GOMAXPROCS (which must
// also be done by the user).
func SetWorkerPoolSize(n int) {
	worker_pool_size = n
}

type fft_work struct {
	start, end int
}

// radix2FFT returns the FFT calculated using the radix-2 DIT Cooley-Tukey algorithm.
func radix2FFT(x []complex128) []complex128 {
	lx := len(x)
	factors := getRadix2Factors(lx)

	t := make([]complex128, lx) // temp
	r := reorderData(x)

	var blocks, stage, s_2 int

	jobs := make(chan *fft_work, lx)
	results := make(chan bool, lx)

	idx_diff := lx / worker_pool_size
	if idx_diff < 2 {
		idx_diff = 2
	}

	worker := func() {
		for work := range jobs {
			for nb := work.start; nb < work.end; nb += stage {
				if stage != 2 {
					for j := 0; j < s_2; j++ {
						idx := j + nb
						idx2 := idx + s_2
						ridx := r[idx]
						w_n := r[idx2] * factors[blocks*j]
						t[idx] = ridx + w_n
						t[idx2] = ridx - w_n
					}
				} else {
					n1 := nb + 1
					rn := r[nb]
					rn1 := r[n1]
					t[nb] = rn + rn1
					t[n1] = rn - rn1
				}
			}

			results <- true
		}
	}

	for i := 0; i < worker_pool_size; i++ {
		go worker()
	}
	defer close(jobs)

	for stage = 2; stage <= lx; stage <<= 1 {
		blocks = lx / stage
		s_2 = stage / 2
		workers_spawned := 0

		for start, end := 0, stage; ; {
			if end - start >= idx_diff || end == lx {
				workers_spawned++
				jobs <- &fft_work { start, end }

				if end == lx {
					break
				}

				start = end
			}

			end += stage
		}

		for n := 0; n < workers_spawned; n++ {
			<-results
		}

		r, t = t, r
	}

	return r
}

// reorderData returns a copy of x reordered for the DFT.
func reorderData(x []complex128) []complex128 {
	lx := uint(len(x))
	r := make([]complex128, lx)
	s := log2(lx)

	var n uint
	for ; n < lx; n++ {
		r[reverseBits(n, s)] = x[n]
	}

	return r
}

// log2 returns the log base 2 of v
// from: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
func log2(v uint) uint {
	var r uint

	for v >>= 1; v != 0; v >>= 1 {
		r++
	}

	return r
}

// reverseBits returns the first s bits of v in reverse order
// from: http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious
func reverseBits(v, s uint) uint {
	var r uint

	// Since we aren't reversing all the bits in v (just the first s bits),
	// we only need the first bit of v instead of a full copy.
	r = v & 1
	s--

	for v >>= 1; v != 0; v >>= 1 {
		r <<= 1
		r |= v & 1
		s--
	}

	return r << s
}

// bluesteinFFT returns the FFT calculated using the Bluestein algorithm.
func bluesteinFFT(x []complex128) []complex128 {
	lx := len(x)
	a := dsputils.ZeroPad(x, dsputils.NextPowerOf2(lx*2-1))
	la := len(a)
	factors, invFactors := getBluesteinFactors(lx)

	for n, v := range x {
		a[n] = v * invFactors[n]
	}

	b := make([]complex128, la)
	for i := 0; i < lx; i++ {
		b[i] = factors[i]

		if i != 0 {
			b[la-i] = factors[i]
		}
	}

	r := Convolve(a, b)

	for i := 0; i < lx; i++ {
		r[i] *= invFactors[i]
	}

	return r[:lx]
}

// FFT2Real returns the 2-dimensional, forward FFT of the real-valued matrix.
func FFT2Real(x [][]float64) [][]complex128 {
	return FFT2(dsputils.ToComplex2(x))
}

// FFT2 returns the 2-dimensional, forward FFT of the complex-valued matrix.
func FFT2(x [][]complex128) [][]complex128 {
	return computeFFT2(x, FFT)
}

// IFFT2Real returns the 2-dimensional, inverse FFT of the real-valued matrix.
func IFFT2Real(x [][]float64) [][]complex128 {
	return IFFT2(dsputils.ToComplex2(x))
}

// IFFT2 returns the 2-dimensional, inverse FFT of the complex-valued matrix.
func IFFT2(x [][]complex128) [][]complex128 {
	return computeFFT2(x, IFFT)
}

func computeFFT2(x [][]complex128, fftFunc func([]complex128) []complex128) [][]complex128 {
	rows := len(x)
	if rows == 0 {
		panic("empty input array")
	}

	cols := len(x[0])
	r := make([][]complex128, rows)
	for i := 0; i < rows; i++ {
		if len(x[i]) != cols {
			panic("ragged input array")
		}
		r[i] = make([]complex128, cols)
	}

	for i := 0; i < cols; i++ {
		t := make([]complex128, rows)
		for j := 0; j < rows; j++ {
			t[j] = x[j][i]
		}

		for n, v := range fftFunc(t) {
			r[n][i] = v
		}
	}

	for n, v := range r {
		r[n] = fftFunc(v)
	}

	return r
}

// FFTN returns the forward FFT of the matrix m, computed in all N dimensions.
func FFTN(m *dsputils.Matrix) *dsputils.Matrix {
	return computeFFTN(m, FFT)
}

// IFFTN returns the forward FFT of the matrix m, computed in all N dimensions.
func IFFTN(m *dsputils.Matrix) *dsputils.Matrix {
	return computeFFTN(m, IFFT)
}

func computeFFTN(m *dsputils.Matrix, fftFunc func([]complex128) []complex128) *dsputils.Matrix {
	dims := m.Dimensions()
	t := m.Copy()
	r := dsputils.MakeEmptyMatrix(dims)

	for n := range dims {
		dims[n] -= 1
	}

	for n := range dims {
		d := make([]int, len(dims))
		copy(d, dims)
		d[n] = -1

		for {
			r.SetDim(fftFunc(t.Dim(d)), d)

			if !decrDim(d, dims) {
				break
			}
		}

		r, t = t, r
	}

	return t
}

// decrDim decrements an element of x by 1, skipping all -1s, and wrapping up to d.
// If a value is 0, it will be reset to its correspending value in d, and will carry one from the next non -1 value to the right.
// Returns true if decremented, else false.
func decrDim(x, d []int) bool {
	for n, v := range x {
		if v == -1 {
			continue
		} else if v == 0 {
			i := n
			// find the next element to decrement
			for ; i < len(x); i++ {
				if x[i] == -1 {
					continue
				} else if x[i] == 0 {
					x[i] = d[i]
				} else {
					x[i] -= 1
					return true
				}
			}

			// no decrement
			return false
		} else {
			x[n] -= 1
			return true
		}
	}

	return false
}
<commit_msg>go fmt<commit_after>/*
 * Copyright (c) 2011 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package fft provides forward and inverse fast Fourier transform functions.
package fft

import (
	"math"
	"sync"

	"github.com/mjibson/go-dsp/dsputils"
)

var (
	radix2Lock    sync.RWMutex
	radix2Factors = map[int][]complex128{
		4: {complex(1, 0), complex(0, -1), complex(-1, 0), complex(0, 1)},
	}
)

var (
	bluesteinLock       sync.RWMutex
	bluesteinFactors    = map[int][]complex128{}
	bluesteinInvFactors = map[int][]complex128{}
)

// EnsureRadix2Factors ensures that all radix 2 factors are computed for inputs
// of length input_len. This is used to precompute needed factors for known
// sizes. Generally should only be used for benchmarks.
func EnsureRadix2Factors(input_len int) {
	getRadix2Factors(input_len)
}

func getRadix2Factors(input_len int) []complex128 {
	radix2Lock.RLock()

	if hasRadix2Factors(input_len) {
		defer radix2Lock.RUnlock()
		return radix2Factors[input_len]
	}

	radix2Lock.RUnlock()
	radix2Lock.Lock()
	defer radix2Lock.Unlock()

	if !hasRadix2Factors(input_len) {
		for i, p := 8, 4; i <= input_len; i, p = i<<1, i {
			if radix2Factors[i] == nil {
				radix2Factors[i] = make([]complex128, i)

				for n, j := 0, 0; n < i; n, j = n+2, j+1 {
					radix2Factors[i][n] = radix2Factors[p][j]
				}

				for n := 1; n < i; n += 2 {
					sin, cos := math.Sincos(-2 * math.Pi / float64(i) * float64(n))
					radix2Factors[i][n] = complex(cos, sin)
				}
			}
		}
	}

	return radix2Factors[input_len]
}

func hasRadix2Factors(idx int) bool {
	return radix2Factors[idx] != nil
}

func getBluesteinFactors(input_len int) ([]complex128, []complex128) {
	bluesteinLock.RLock()

	if hasBluesteinFactors(input_len) {
		defer bluesteinLock.RUnlock()
		return bluesteinFactors[input_len], bluesteinInvFactors[input_len]
	}

	bluesteinLock.RUnlock()
	bluesteinLock.Lock()
	defer bluesteinLock.Unlock()

	if !hasBluesteinFactors(input_len) {
		bluesteinFactors[input_len] = make([]complex128, input_len)
		bluesteinInvFactors[input_len] = make([]complex128, input_len)

		var sin, cos float64
		for i := 0; i < input_len; i++ {
			if i == 0 {
				sin, cos = 0, 1
			} else {
				sin, cos = math.Sincos(math.Pi / float64(input_len) * float64(i*i))
			}
			bluesteinFactors[input_len][i] = complex(cos, sin)
			bluesteinInvFactors[input_len][i] = complex(cos, -sin)
		}
	}

	return bluesteinFactors[input_len], bluesteinInvFactors[input_len]
}

func hasBluesteinFactors(idx int) bool {
	return bluesteinFactors[idx] != nil
}

// FFTReal returns the forward FFT of the real-valued slice.
func FFTReal(x []float64) []complex128 {
	return FFT(dsputils.ToComplex(x))
}

// IFFTReal returns the inverse FFT of the real-valued slice.
func IFFTReal(x []float64) []complex128 {
	return IFFT(dsputils.ToComplex(x))
}

// IFFT returns the inverse FFT of the complex-valued slice.
func IFFT(x []complex128) []complex128 {
	lx := len(x)
	r := make([]complex128, lx)

	// Reverse inputs, which is calculated with modulo N, hence x[0] as an outlier
	r[0] = x[0]
	for i := 1; i < lx; i++ {
		r[i] = x[lx-i]
	}

	r = FFT(r)

	N := complex(float64(lx), 0)
	for n, _ := range r {
		r[n] /= N
	}
	return r
}

// Convolve returns the convolution of x * y.
func Convolve(x, y []complex128) []complex128 {
	if len(x) != len(y) {
		panic("arrays not of equal size")
	}

	fft_x := FFT(x)
	fft_y := FFT(y)

	r := make([]complex128, len(x))
	for i := 0; i < len(r); i++ {
		r[i] = fft_x[i] * fft_y[i]
	}

	return IFFT(r)
}

// FFT returns the forward FFT of the complex-valued slice.
func FFT(x []complex128) []complex128 {
	lx := len(x)

	// todo: non-hack handling length <= 1 cases
	if lx <= 1 {
		r := make([]complex128, lx)
		copy(r, x)
		return r
	}

	if dsputils.IsPowerOf2(lx) {
		return radix2FFT(x)
	}

	return bluesteinFFT(x)
}

var (
	worker_pool_size = 1
)

// SetWorkerPoolSize sets the number of workers during FFT computation on
// multicore systems. This should generally be set to GOMAXPROCS (which must
// also be done by the user).
func SetWorkerPoolSize(n int) {
	worker_pool_size = n
}

type fft_work struct {
	start, end int
}

// radix2FFT returns the FFT calculated using the radix-2 DIT Cooley-Tukey algorithm.
func radix2FFT(x []complex128) []complex128 {
	lx := len(x)
	factors := getRadix2Factors(lx)

	t := make([]complex128, lx) // temp
	r := reorderData(x)

	var blocks, stage, s_2 int

	jobs := make(chan *fft_work, lx)
	results := make(chan bool, lx)

	idx_diff := lx / worker_pool_size
	if idx_diff < 2 {
		idx_diff = 2
	}

	worker := func() {
		for work := range jobs {
			for nb := work.start; nb < work.end; nb += stage {
				if stage != 2 {
					for j := 0; j < s_2; j++ {
						idx := j + nb
						idx2 := idx + s_2
						ridx := r[idx]
						w_n := r[idx2] * factors[blocks*j]
						t[idx] = ridx + w_n
						t[idx2] = ridx - w_n
					}
				} else {
					n1 := nb + 1
					rn := r[nb]
					rn1 := r[n1]
					t[nb] = rn + rn1
					t[n1] = rn - rn1
				}
			}

			results <- true
		}
	}

	for i := 0; i < worker_pool_size; i++ {
		go worker()
	}
	defer close(jobs)

	for stage = 2; stage <= lx; stage <<= 1 {
		blocks = lx / stage
		s_2 = stage / 2
		workers_spawned := 0

		for start, end := 0, stage; ; {
			if end-start >= idx_diff || end == lx {
				workers_spawned++
				jobs <- &fft_work{start, end}

				if end == lx {
					break
				}

				start = end
			}

			end += stage
		}

		for n := 0; n < workers_spawned; n++ {
			<-results
		}

		r, t = t, r
	}

	return r
}

// reorderData returns a copy of x reordered for the DFT.
func reorderData(x []complex128) []complex128 {
	lx := uint(len(x))
	r := make([]complex128, lx)
	s := log2(lx)

	var n uint
	for ; n < lx; n++ {
		r[reverseBits(n, s)] = x[n]
	}

	return r
}

// log2 returns the log base 2 of v
// from: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
func log2(v uint) uint {
	var r uint

	for v >>= 1; v != 0; v >>= 1 {
		r++
	}

	return r
}

// reverseBits returns the first s bits of v in reverse order
// from: http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious
func reverseBits(v, s uint) uint {
	var r uint

	// Since we aren't reversing all the bits in v (just the first s bits),
	// we only need the first bit of v instead of a full copy.
	r = v & 1
	s--

	for v >>= 1; v != 0; v >>= 1 {
		r <<= 1
		r |= v & 1
		s--
	}

	return r << s
}

// bluesteinFFT returns the FFT calculated using the Bluestein algorithm.
func bluesteinFFT(x []complex128) []complex128 {
	lx := len(x)
	a := dsputils.ZeroPad(x, dsputils.NextPowerOf2(lx*2-1))
	la := len(a)
	factors, invFactors := getBluesteinFactors(lx)

	for n, v := range x {
		a[n] = v * invFactors[n]
	}

	b := make([]complex128, la)
	for i := 0; i < lx; i++ {
		b[i] = factors[i]

		if i != 0 {
			b[la-i] = factors[i]
		}
	}

	r := Convolve(a, b)

	for i := 0; i < lx; i++ {
		r[i] *= invFactors[i]
	}

	return r[:lx]
}

// FFT2Real returns the 2-dimensional, forward FFT of the real-valued matrix.
func FFT2Real(x [][]float64) [][]complex128 {
	return FFT2(dsputils.ToComplex2(x))
}

// FFT2 returns the 2-dimensional, forward FFT of the complex-valued matrix.
func FFT2(x [][]complex128) [][]complex128 {
	return computeFFT2(x, FFT)
}

// IFFT2Real returns the 2-dimensional, inverse FFT of the real-valued matrix.
func IFFT2Real(x [][]float64) [][]complex128 {
	return IFFT2(dsputils.ToComplex2(x))
}

// IFFT2 returns the 2-dimensional, inverse FFT of the complex-valued matrix.
func IFFT2(x [][]complex128) [][]complex128 {
	return computeFFT2(x, IFFT)
}

func computeFFT2(x [][]complex128, fftFunc func([]complex128) []complex128) [][]complex128 {
	rows := len(x)
	if rows == 0 {
		panic("empty input array")
	}

	cols := len(x[0])
	r := make([][]complex128, rows)
	for i := 0; i < rows; i++ {
		if len(x[i]) != cols {
			panic("ragged input array")
		}
		r[i] = make([]complex128, cols)
	}

	for i := 0; i < cols; i++ {
		t := make([]complex128, rows)
		for j := 0; j < rows; j++ {
			t[j] = x[j][i]
		}

		for n, v := range fftFunc(t) {
			r[n][i] = v
		}
	}

	for n, v := range r {
		r[n] = fftFunc(v)
	}

	return r
}

// FFTN returns the forward FFT of the matrix m, computed in all N dimensions.
func FFTN(m *dsputils.Matrix) *dsputils.Matrix {
	return computeFFTN(m, FFT)
}

// IFFTN returns the forward FFT of the matrix m, computed in all N dimensions.
func IFFTN(m *dsputils.Matrix) *dsputils.Matrix {
	return computeFFTN(m, IFFT)
}

func computeFFTN(m *dsputils.Matrix, fftFunc func([]complex128) []complex128) *dsputils.Matrix {
	dims := m.Dimensions()
	t := m.Copy()
	r := dsputils.MakeEmptyMatrix(dims)

	for n := range dims {
		dims[n] -= 1
	}

	for n := range dims {
		d := make([]int, len(dims))
		copy(d, dims)
		d[n] = -1

		for {
			r.SetDim(fftFunc(t.Dim(d)), d)

			if !decrDim(d, dims) {
				break
			}
		}

		r, t = t, r
	}

	return t
}

// decrDim decrements an element of x by 1, skipping all -1s, and wrapping up to d.
// If a value is 0, it will be reset to its correspending value in d, and will carry one from the next non -1 value to the right.
// Returns true if decremented, else false.
func decrDim(x, d []int) bool {
	for n, v := range x {
		if v == -1 {
			continue
		} else if v == 0 {
			i := n
			// find the next element to decrement
			for ; i < len(x); i++ {
				if x[i] == -1 {
					continue
				} else if x[i] == 0 {
					x[i] = d[i]
				} else {
					x[i] -= 1
					return true
				}
			}

			// no decrement
			return false
		} else {
			x[n] -= 1
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package schema

import (
	"time"

	"code.google.com/p/go-uuid/uuid"
)

type Build struct {
	ID               uuid.UUID           `json:"id"`
	SourceRepo       string              `json:"source_repo"`
	SourceBranch     string              `json:"source_branch"`
	Name             string              `json:"name"`
	Dockerfile       string              `json:"dockerfile"`
	CacheDirectories []map[string]string `json:"cache_directories"`
	Status           string              `json:"status"`
	CreatedAt        time.Time           `json:"created_at"`
	UpdatedAt        time.Time           `json:"updated_at"`
}

type BuildCreateOpts struct {
	SourceRepo       string              `json:"source_repo"`
	SourceBranch     string              `json:"source_branch"`
	Name             string              `json:"name"`
	Dockerfile       string              `json:"dockerfile"`
	CacheDirectories []map[string]string `json:"cache_directories"`
}

// NewBuild creates new build struct
func NewBuild(opts BuildCreateOpts) Build {
	if opts.SourceBranch == "" {
		opts.SourceBranch = "master"
	}

	if opts.Dockerfile == "" {
		opts.Dockerfile = "Dockerfile"
	}

	currentTime := time.Now()
	return Build{
		ID:               uuid.NewUUID(),
		SourceRepo:       opts.SourceRepo,
		SourceBranch:     opts.SourceBranch,
		Name:             opts.Name,
		Dockerfile:       opts.Dockerfile,
		CacheDirectories: opts.CacheDirectories,
		Status:           "building",
		CreatedAt:        currentTime,
		UpdatedAt:        currentTime,
	}
}
<commit_msg>Modify attribute name<commit_after>package schema

import (
	"time"

	"code.google.com/p/go-uuid/uuid"
)

type Build struct {
	ID               uuid.UUID           `json:"id"`
	SourceRepo       string              `json:"source_repo"`
	SourceBranch     string              `json:"source_branch"`
	ImageName        string              `json:"image_name"`
	Dockerfile       string              `json:"dockerfile"`
	CacheDirectories []map[string]string `json:"cache_directories"`
	Status           string              `json:"status"`
	CreatedAt        time.Time           `json:"created_at"`
	UpdatedAt        time.Time           `json:"updated_at"`
}

type BuildCreateOpts struct {
	SourceRepo       string              `json:"source_repo"`
	SourceBranch     string              `json:"source_branch"`
	ImageName        string              `json:"image_name"`
	Dockerfile       string              `json:"dockerfile"`
	CacheDirectories []map[string]string `json:"cache_directories"`
}

// NewBuild creates new build struct
func NewBuild(opts BuildCreateOpts) Build {
	if opts.SourceBranch == "" {
		opts.SourceBranch = "master"
	}

	if opts.Dockerfile == "" {
		opts.Dockerfile = "Dockerfile"
	}

	currentTime := time.Now()
	return Build{
		ID:               uuid.NewUUID(),
		SourceRepo:       opts.SourceRepo,
		SourceBranch:     opts.SourceBranch,
		ImageName:        opts.ImageName,
		Dockerfile:       opts.Dockerfile,
		CacheDirectories: opts.CacheDirectories,
		Status:           "building",
		CreatedAt:        currentTime,
		UpdatedAt:        currentTime,
	}
}
<|endoftext|>


<commit_before>package pongo

// TODO: Add context-sensitive filters (so they know their location, e.g. for
// context-sensitive escaping within javascript <-> normal body html.)

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

type FilterFunc func(interface{}, []interface{}, *FilterChainContext) (interface{}, error)

type FilterChainContext struct {
	// Store what you want along the filter chain. Every filter has access to this store.
	Store           map[string]interface{}
	applied_filters []string
}

func (ctx *FilterChainContext) HasVisited(names ...string) bool {
	for _, filter := range ctx.applied_filters {
		for _, name := range names {
			if filter == name {
				return true
			}
		}
	}
	return false
}

func (ctx *FilterChainContext) visitFilter(name string) {
	ctx.applied_filters = append(ctx.applied_filters, name)
}

var Filters = map[string]FilterFunc{
	"safe":       filterSafe,
	"unsafe":     nil, // It will not be called, just added to visited filters (applied_filters)
	"lower":      filterLower,
	"upper":      filterUpper,
	"capitalize": filterCapitalize,
	"default":    filterDefault,
	"trim":       filterTrim,
	"length":     filterLength,
	"join":       filterJoin,
	"striptags":  filterStriptags,

	/* TODO:
	- verbatim
	- ...
	*/
}

func newFilterChainContext() *FilterChainContext {
	return &FilterChainContext{
		applied_filters: make([]string, 0, 5),
	}
}

func filterSafe(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	if ctx.HasVisited("unsafe", "safe") {
		// If "unsafe" or "safe" were already applied to the value
		// don't do it (again, in case of "safe")
		return value, nil
	}

	str, is_str := value.(string)
	if !is_str {
		// We don't have to safe non-strings
		return value, nil
	}

	output := strings.Replace(str, "&", "&", -1)
	output = strings.Replace(output, ">", ">", -1)
	output = strings.Replace(output, "<", "<", -1)

	return output, nil
}

func filterLower(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v (%T) is not of type string", value, value))
	}
	return strings.ToLower(str), nil
}

func filterUpper(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v (%T) is not of type string", value, value))
	}
	return strings.ToUpper(str), nil
}

func filterCapitalize(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v (%T) is not of type string", value, value))
	}
	return strings.Title(str), nil
}

func filterTrim(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v (%T) is not of type string", value, value))
	}
	return strings.TrimSpace(str), nil
}

func filterLength(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	rv := reflect.ValueOf(value)
	switch rv.Kind() {
	case reflect.Slice, reflect.Array, reflect.String, reflect.Map:
		return rv.Len(), nil
	default:
		return nil, errors.New(fmt.Sprintf("Cannot determine length from type %T ('%v').", value, value))
	}
	panic("unreachable")
}

func filterJoin(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	if len(args) != 1 {
		return nil, errors.New("Please provide a separator")
	}
	sep, is_string := args[0].(string)
	if !is_string {
		return nil, errors.New(fmt.Sprintf("Separator must be of type string, not %T ('%v')", args[0], args[0]))
	}

	rv := reflect.ValueOf(value)
	switch rv.Kind() {
	case reflect.Slice, reflect.Array:
		items := make([]string, 0, rv.Len())
		for i := 0; i < rv.Len(); i++ {
			items = append(items, fmt.Sprintf("%v", rv.Index(i).Interface()))
		}
		return strings.Join(items, sep), nil
	default:
		return nil, errors.New(fmt.Sprintf("Cannot join variable of type %T ('%v').", value, value))
	}
	panic("unreachable")
}

func filterStriptags(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v is not of type string", value))
	}

	if len(args) > 1 {
		return nil, errors.New("Please provide a comma-seperated string with tags (or no string to remove all tags).")
	}

	if len(args) == 1 {
		taglist, is_string := args[0].(string)
		if !is_string {
			return nil, errors.New(fmt.Sprintf("Taglist must be a string, not %T ('%v')", args[0], args[0]))
		}

		tags := strings.Split(taglist, ",")

		for _, tag := range tags {
			re := regexp.MustCompile(fmt.Sprintf("</?%s/?>", tag))
			str = re.ReplaceAllString(str, "")
		}
	} else {
		re := regexp.MustCompile("<[^>]*?>")
		str = re.ReplaceAllString(str, "")
	}

	return strings.TrimSpace(str), nil
}

func filterDefault(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	// Use reflect to check against zero() of type

	if len(args) != 1 {
		return nil, errors.New("Default filter takes only one argument")
	}

	if reflect.Zero(reflect.TypeOf(value)).Interface() == value {
		return args[0], nil
	}

	return value, nil
}
<commit_msg>Adds time_format filter.<commit_after>package pongo

// TODO: Add context-sensitive filters (so they know their location, e.g. for
// context-sensitive escaping within javascript <-> normal body html.)

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

type FilterFunc func(interface{}, []interface{}, *FilterChainContext) (interface{}, error)

type FilterChainContext struct {
	// Store what you want along the filter chain. Every filter has access to this store.
	Store           map[string]interface{}
	applied_filters []string
}

func (ctx *FilterChainContext) HasVisited(names ...string) bool {
	for _, filter := range ctx.applied_filters {
		for _, name := range names {
			if filter == name {
				return true
			}
		}
	}
	return false
}

func (ctx *FilterChainContext) visitFilter(name string) {
	ctx.applied_filters = append(ctx.applied_filters, name)
}

var Filters = map[string]FilterFunc{
	"safe":        filterSafe,
	"unsafe":      nil, // It will not be called, just added to visited filters (applied_filters)
	"lower":       filterLower,
	"upper":       filterUpper,
	"capitalize":  filterCapitalize,
	"default":     filterDefault,
	"trim":        filterTrim,
	"length":      filterLength,
	"join":        filterJoin,
	"striptags":   filterStriptags,
	"time_format": filterTimeFormat,

	/* TODO:
	- verbatim
	- ...
	*/
}

func newFilterChainContext() *FilterChainContext {
	return &FilterChainContext{
		applied_filters: make([]string, 0, 5),
	}
}

func filterSafe(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	if ctx.HasVisited("unsafe", "safe") {
		// If "unsafe" or "safe" were already applied to the value
		// don't do it (again, in case of "safe")
		return value, nil
	}

	str, is_str := value.(string)
	if !is_str {
		// We don't have to safe non-strings
		return value, nil
	}

	output := strings.Replace(str, "&", "&", -1)
	output = strings.Replace(output, ">", ">", -1)
	output = strings.Replace(output, "<", "<", -1)

	return output, nil
}

func filterLower(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v (%T) is not of type string", value, value))
	}
	return strings.ToLower(str), nil
}

func filterTimeFormat(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	t, is_time := value.(time.Time)
	if !is_time {
		return nil, errors.New(fmt.Sprintf("%v (%T) is not of type string", value, value))
	}

	arg := args[0]
	if arg == nil {
		return nil, errors.New("time_format requires you pass a format.")
	}

	format, is_string := arg.(string)
	if !is_string {
		return nil, errors.New(fmt.Sprintf("time_format's format must be a string. %v (%T) passed.", format, format))
	}

	return t.Format(format), nil
}

func filterUpper(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v (%T) is not of type string", value, value))
	}
	return strings.ToUpper(str), nil
}

func filterCapitalize(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v (%T) is not of type string", value, value))
	}
	return strings.Title(str), nil
}

func filterTrim(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v (%T) is not of type string", value, value))
	}
	return strings.TrimSpace(str), nil
}

func filterLength(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	rv := reflect.ValueOf(value)
	switch rv.Kind() {
	case reflect.Slice, reflect.Array, reflect.String, reflect.Map:
		return rv.Len(), nil
	default:
		return nil, errors.New(fmt.Sprintf("Cannot determine length from type %T ('%v').", value, value))
	}
	panic("unreachable")
}

func filterJoin(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	if len(args) != 1 {
		return nil, errors.New("Please provide a separator")
	}
	sep, is_string := args[0].(string)
	if !is_string {
		return nil, errors.New(fmt.Sprintf("Separator must be of type string, not %T ('%v')", args[0], args[0]))
	}

	rv := reflect.ValueOf(value)
	switch rv.Kind() {
	case reflect.Slice, reflect.Array:
		items := make([]string, 0, rv.Len())
		for i := 0; i < rv.Len(); i++ {
			items = append(items, fmt.Sprintf("%v", rv.Index(i).Interface()))
		}
		return strings.Join(items, sep), nil
	default:
		return nil, errors.New(fmt.Sprintf("Cannot join variable of type %T ('%v').", value, value))
	}
	panic("unreachable")
}

func filterStriptags(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	str, is_str := value.(string)
	if !is_str {
		return nil, errors.New(fmt.Sprintf("%v is not of type string", value))
	}

	if len(args) > 1 {
		return nil, errors.New("Please provide a comma-seperated string with tags (or no string to remove all tags).")
	}

	if len(args) == 1 {
		taglist, is_string := args[0].(string)
		if !is_string {
			return nil, errors.New(fmt.Sprintf("Taglist must be a string, not %T ('%v')", args[0], args[0]))
		}

		tags := strings.Split(taglist, ",")

		for _, tag := range tags {
			re := regexp.MustCompile(fmt.Sprintf("</?%s/?>", tag))
			str = re.ReplaceAllString(str, "")
		}
	} else {
		re := regexp.MustCompile("<[^>]*?>")
		str = re.ReplaceAllString(str, "")
	}

	return strings.TrimSpace(str), nil
}

func filterDefault(value interface{}, args []interface{}, ctx *FilterChainContext) (interface{}, error) {
	// Use reflect to check against zero() of type

	if len(args) != 1 {
		return nil, errors.New("Default filter takes only one argument")
	}

	if reflect.Zero(reflect.TypeOf(value)).Interface() == value {
		return args[0], nil
	}

	return value, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors 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 e2e

import (
	"fmt"

	. "github.com/onsi/ginkgo"
	federationapi "k8s.io/kubernetes/federation/apis/federation"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/test/e2e/framework"
)

// Create/delete cluster api objects
var _ = framework.KubeDescribe("Federation apiserver [Feature:Federation]", func() {
	f := framework.NewDefaultFederatedFramework("federated-cluster")
	It("should allow creation of cluster api objects", func() {
		framework.SkipUnlessFederated(f.Client)

		contexts := f.GetUnderlyingFederatedContexts()

		for _, context := range contexts {
			framework.Logf("Creating cluster object: %s (%s)", context.Name, context.Cluster.Cluster.Server)
			cluster := federationapi.Cluster{
				ObjectMeta: api.ObjectMeta{
					Name: context.Name,
				},
				Spec: federationapi.ClusterSpec{
					ServerAddressByClientCIDRs: []federationapi.ServerAddressByClientCIDR{
						{
							ClientCIDR:    "0.0.0.0/0",
							ServerAddress: context.Cluster.Cluster.Server,
						},
					},
					//TODO(colhom): add SecretRef when #26132 lands
				},
			}
			_, err := f.FederationClient.Clusters().Create(&cluster)
			framework.ExpectNoError(err, fmt.Sprintf("creating cluster: %+v", err))
		}

		for _, context := range contexts {
			c, err := f.FederationClient.Clusters().Get(context.Name)
			framework.ExpectNoError(err, fmt.Sprintf("get cluster: %+v", err))
			if c.ObjectMeta.Name != context.Name {
				framework.Failf("cluster name does not match input context: actual=%+v, expected=%+v", c, context)
			}
		}
	})
})
<commit_msg>Add secret to Federation API Server e2e test.<commit_after>/*
Copyright 2015 The Kubernetes Authors 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 e2e

import (
	"fmt"

	. "github.com/onsi/ginkgo"
	federationapi "k8s.io/kubernetes/federation/apis/federation"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/test/e2e/framework"
)

// Create/delete cluster api objects
var _ = framework.KubeDescribe("Federation apiserver [Feature:Federation]", func() {
	f := framework.NewDefaultFederatedFramework("federated-cluster")
	It("should allow creation of cluster api objects", func() {
		framework.SkipUnlessFederated(f.Client)

		contexts := f.GetUnderlyingFederatedContexts()

		for _, context := range contexts {
			framework.Logf("Creating cluster object: %s (%s, secret: %s)", context.Name, context.Cluster.Cluster.Server, context.Name)
			cluster := federationapi.Cluster{
				ObjectMeta: api.ObjectMeta{
					Name: context.Name,
				},
				Spec: federationapi.ClusterSpec{
					ServerAddressByClientCIDRs: []federationapi.ServerAddressByClientCIDR{
						{
							ClientCIDR:    "0.0.0.0/0",
							ServerAddress: context.Cluster.Cluster.Server,
						},
					},
					SecretRef: &api.LocalObjectReference{
						// Note: Name must correlate with federation build script secret name,
						//       which currently matches the cluster name.
						//       See federation/cluster/common.sh:132
						Name: context.Name,
					},
				},
			}
			_, err := f.FederationClient.Clusters().Create(&cluster)
			framework.ExpectNoError(err, fmt.Sprintf("creating cluster: %+v", err))
		}

		for _, context := range contexts {
			c, err := f.FederationClient.Clusters().Get(context.Name)
			framework.ExpectNoError(err, fmt.Sprintf("get cluster: %+v", err))
			if c.ObjectMeta.Name != context.Name {
				framework.Failf("cluster name does not match input context: actual=%+v, expected=%+v", c, context)
			}
		}
	})
})
<|endoftext|>


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

package api

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

var (
	testCheck = Check{
		CID:            "/check/1234",
		Active:         true,
		BrokerCID:      "/broker/1234",
		CheckBundleCID: "/check_bundle/1234",
		CheckUUID:      "abc123-a1b2-c3d4-e5f6-123abc",
		Details:        CheckDetails{SubmissionURL: "http://example.com/"},
	}
)

func testCheckServer() *httptest.Server {
	f := func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path
		if path == "/check/1234" {
			switch r.Method {
			case "GET": // get by id/cid
				ret, err := json.Marshal(testCheck)
				if err != nil {
					panic(err)
				}
				w.WriteHeader(200)
				w.Header().Set("Content-Type", "application/json")
				fmt.Fprintln(w, string(ret))
			default:
				w.WriteHeader(404)
				fmt.Fprintln(w, fmt.Sprintf("not found: %s %s", r.Method, path))
			}
		} else if path == "/check" {
			switch r.Method {
			case "GET": // search or filter
				reqURL := r.URL.String()
				var c []Check
				if reqURL == "/check?search=test" {
					c = []Check{testCheck}
				} else if reqURL == "/check?f__tags_has=cat%3Atag" {
					c = []Check{testCheck}
				} else if reqURL == "/check?f__tags_has=cat%3Atag&search=test" {
					c = []Check{testCheck}
				} else if reqURL == "/check" {
					c = []Check{testCheck}
				} else {
					c = []Check{}
				}
				if len(c) > 0 {
					ret, err := json.Marshal(c)
					if err != nil {
						panic(err)
					}
					w.WriteHeader(200)
					w.Header().Set("Content-Type", "application/json")
					fmt.Fprintln(w, string(ret))
				} else {
					w.WriteHeader(404)
					fmt.Fprintln(w, fmt.Sprintf("not found: %s %s", r.Method, reqURL))
				}
			default:
				w.WriteHeader(404)
				fmt.Fprintln(w, fmt.Sprintf("not found: %s %s", r.Method, path))
			}
		} else {
			w.WriteHeader(404)
			fmt.Fprintln(w, fmt.Sprintf("not found: %s %s", r.Method, path))
		}
	}

	return httptest.NewServer(http.HandlerFunc(f))
}

func TestFetchCheck(t *testing.T) {
	server := testCheckServer()
	defer server.Close()

	ac := &Config{
		TokenKey: "abc123",
		TokenApp: "test",
		URL:      server.URL,
	}
	apih, err := NewAPI(ac)
	if err != nil {
		t.Errorf("Expected no error, got '%v'", err)
	}

	t.Log("invalid CID")
	{
		cid := "/invalid"
		expectedError := errors.New("Invalid check CID [/invalid]")
		_, err = apih.FetchCheck(CIDType(&cid))
		if err == nil {
			t.Fatalf("Expected error")
		}
		if err.Error() != expectedError.Error() {
			t.Fatalf("Expected %+v got '%+v'", expectedError, err)
		}
	}

	t.Log("valid CID")
	{
		cid := CIDType(&testCheck.CID)
		check, err := apih.FetchCheck(cid)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(check)
		expectedType := "*api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}

		if check.CID != testCheck.CID {
			t.Fatalf("CIDs do not match: %+v != %+v\n", check, testCheck)
		}
	}
}

func TestSearchChecks(t *testing.T) {
	server := testCheckServer()
	defer server.Close()

	var apih *API
	var err error

	ac := &Config{
		TokenKey: "abc123",
		TokenApp: "test",
		URL:      server.URL,
	}
	apih, err = NewAPI(ac)
	if err != nil {
		t.Errorf("Expected no error, got '%v'", err)
	}

	t.Log("no search, no filter")
	{
		clusters, err := apih.SearchChecks(nil, nil)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(clusters)
		expectedType := "*[]api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}
	}

	t.Log("search, no filter")
	{
		search := SearchQueryType("test")
		clusters, err := apih.SearchChecks(&search, nil)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(clusters)
		expectedType := "*[]api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}
	}

	t.Log("no search, filter")
	{
		filter := SearchFilterType{"f__tags_has": []string{"cat:tag"}}
		clusters, err := apih.SearchChecks(nil, &filter)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(clusters)
		expectedType := "*[]api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}
	}

	t.Log("search, filter")
	{
		search := SearchQueryType("test")
		filter := SearchFilterType{"f__tags_has": []string{"cat:tag"}}
		clusters, err := apih.SearchChecks(&search, &filter)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(clusters)
		expectedType := "*[]api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}
	}
}

/*
func TestFetchCheckBySubmissionURL(t *testing.T) {
    server := testCheckServer()
    defer server.Close()

    var apih *API
    var err error

    ac := &Config{
        TokenKey: "abc123",
        TokenApp: "test",
        URL:      server.URL,
    }
    apih, err = NewAPI(ac)
    if err != nil {
        t.Errorf("Expected no error, got '%v'", err)
    }

    t.Log("Testing invalid URL (blank)")
    {
        expectedError := errors.New("[ERROR] Invalid submission URL (blank)")
        _, err = apih.FetchCheckBySubmissionURL("")
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing invalid URL (bad format)")
    {
        expectedError := errors.New("parse http://example.com\\noplace$: invalid character \"\\\\\" in host name")
        _, err = apih.FetchCheckBySubmissionURL(URLType("http://example.com\\noplace$"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing invalid URL (bad path)")
    {
        expectedError := errors.New("[ERROR] Invalid submission URL 'http://example.com/foo', unrecognized path")
        _, err = apih.FetchCheckBySubmissionURL(URLType("http://example.com/foo"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing invalid URL (no uuid)")
    {
        expectedError := errors.New("[ERROR] Invalid submission URL 'http://example.com/module/httptrap/', UUID not where expected")
        _, err = apih.FetchCheckBySubmissionURL(URLType("http://example.com/module/httptrap/"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing valid URL (0 checks returned)")
    {
        expectedError := errors.New("[ERROR] No checks found with UUID none")
        _, err := apih.FetchCheckBySubmissionURL(URLType("http://example.com/module/httptrap/none/boo"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing valid URL (multiple checks returned)")
    {
        expectedError := errors.New("[ERROR] Multiple checks with same UUID multi")
        _, err := apih.FetchCheckBySubmissionURL(URLType("http://example.com/module/httptrap/multi/boo"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing valid URL (1 check returned)")
    {
        check, err := apih.FetchCheckBySubmissionURL(URLType("http://example.com/module/httptrap/abc123-abc1-def2-ghi3-123abc/boo"))
        if err != nil {
            t.Fatalf("Expected no error, got '%v'", err)
        }

        actualType := reflect.TypeOf(check)
        expectedType := "*api.Check"
        if actualType.String() != expectedType {
            t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
        }

        if check.CID != testCheck.CID {
            t.Fatalf("CIDs do not match: %+v != %+v\n", check, testCheck)
        }
    }
}
*/
<commit_msg>upd: increase test coverage<commit_after>// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

var (
	testCheck = Check{
		CID:            "/check/1234",
		Active:         true,
		BrokerCID:      "/broker/1234",
		CheckBundleCID: "/check_bundle/1234",
		CheckUUID:      "abc123-a1b2-c3d4-e5f6-123abc",
		Details:        CheckDetails{SubmissionURL: "http://example.com/"},
	}
)

func testCheckServer() *httptest.Server {
	f := func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path
		if path == "/check/1234" {
			switch r.Method {
			case "GET": // get by id/cid
				ret, err := json.Marshal(testCheck)
				if err != nil {
					panic(err)
				}
				w.WriteHeader(200)
				w.Header().Set("Content-Type", "application/json")
				fmt.Fprintln(w, string(ret))
			default:
				w.WriteHeader(404)
				fmt.Fprintln(w, fmt.Sprintf("not found: %s %s", r.Method, path))
			}
		} else if path == "/check" {
			switch r.Method {
			case "GET": // search or filter
				reqURL := r.URL.String()
				var c []Check
				if reqURL == "/check?search=test" {
					c = []Check{testCheck}
				} else if reqURL == "/check?f__tags_has=cat%3Atag" {
					c = []Check{testCheck}
				} else if reqURL == "/check?f__tags_has=cat%3Atag&search=test" {
					c = []Check{testCheck}
				} else if reqURL == "/check" {
					c = []Check{testCheck}
				} else {
					c = []Check{}
				}
				if len(c) > 0 {
					ret, err := json.Marshal(c)
					if err != nil {
						panic(err)
					}
					w.WriteHeader(200)
					w.Header().Set("Content-Type", "application/json")
					fmt.Fprintln(w, string(ret))
				} else {
					w.WriteHeader(404)
					fmt.Fprintln(w, fmt.Sprintf("not found: %s %s", r.Method, reqURL))
				}
			default:
				w.WriteHeader(404)
				fmt.Fprintln(w, fmt.Sprintf("not found: %s %s", r.Method, path))
			}
		} else {
			w.WriteHeader(404)
			fmt.Fprintln(w, fmt.Sprintf("not found: %s %s", r.Method, path))
		}
	}

	return httptest.NewServer(http.HandlerFunc(f))
}

func TestFetchCheck(t *testing.T) {
	server := testCheckServer()
	defer server.Close()

	ac := &Config{
		TokenKey: "abc123",
		TokenApp: "test",
		URL:      server.URL,
	}
	apih, err := NewAPI(ac)
	if err != nil {
		t.Errorf("Expected no error, got '%v'", err)
	}

	t.Log("invalid CID [nil]")
	{
		expectedError := errors.New("Invalid check CID [none]")
		_, err = apih.FetchCheck(nil)
		if err == nil {
			t.Fatalf("Expected error")
		}
		if err.Error() != expectedError.Error() {
			t.Fatalf("Expected %+v got '%+v'", expectedError, err)
		}
	}

	t.Log("invalid CID [\"\"]")
	{
		cid := ""
		expectedError := errors.New("Invalid check CID [none]")
		_, err = apih.FetchCheck(CIDType(&cid))
		if err == nil {
			t.Fatalf("Expected error")
		}
		if err.Error() != expectedError.Error() {
			t.Fatalf("Expected %+v got '%+v'", expectedError, err)
		}
	}

	t.Log("invalid CID [/invalid]")
	{
		cid := "/invalid"
		expectedError := errors.New("Invalid check CID [/invalid]")
		_, err = apih.FetchCheck(CIDType(&cid))
		if err == nil {
			t.Fatalf("Expected error")
		}
		if err.Error() != expectedError.Error() {
			t.Fatalf("Expected %+v got '%+v'", expectedError, err)
		}
	}

	t.Log("valid CID")
	{
		cid := CIDType(&testCheck.CID)
		check, err := apih.FetchCheck(cid)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(check)
		expectedType := "*api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}

		if check.CID != testCheck.CID {
			t.Fatalf("CIDs do not match: %+v != %+v\n", check, testCheck)
		}
	}
}

func TestSearchChecks(t *testing.T) {
	server := testCheckServer()
	defer server.Close()

	var apih *API
	var err error

	ac := &Config{
		TokenKey: "abc123",
		TokenApp: "test",
		URL:      server.URL,
	}
	apih, err = NewAPI(ac)
	if err != nil {
		t.Errorf("Expected no error, got '%v'", err)
	}

	t.Log("no search, no filter")
	{
		clusters, err := apih.SearchChecks(nil, nil)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(clusters)
		expectedType := "*[]api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}
	}

	t.Log("search, no filter")
	{
		search := SearchQueryType("test")
		clusters, err := apih.SearchChecks(&search, nil)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(clusters)
		expectedType := "*[]api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}
	}

	t.Log("no search, filter")
	{
		filter := SearchFilterType{"f__tags_has": []string{"cat:tag"}}
		clusters, err := apih.SearchChecks(nil, &filter)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(clusters)
		expectedType := "*[]api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}
	}

	t.Log("search, filter")
	{
		search := SearchQueryType("test")
		filter := SearchFilterType{"f__tags_has": []string{"cat:tag"}}
		clusters, err := apih.SearchChecks(&search, &filter)
		if err != nil {
			t.Fatalf("Expected no error, got '%v'", err)
		}

		actualType := reflect.TypeOf(clusters)
		expectedType := "*[]api.Check"
		if actualType.String() != expectedType {
			t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
		}
	}
}

/*
func TestFetchCheckBySubmissionURL(t *testing.T) {
    server := testCheckServer()
    defer server.Close()

    var apih *API
    var err error

    ac := &Config{
        TokenKey: "abc123",
        TokenApp: "test",
        URL:      server.URL,
    }
    apih, err = NewAPI(ac)
    if err != nil {
        t.Errorf("Expected no error, got '%v'", err)
    }

    t.Log("Testing invalid URL (blank)")
    {
        expectedError := errors.New("[ERROR] Invalid submission URL (blank)")
        _, err = apih.FetchCheckBySubmissionURL("")
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing invalid URL (bad format)")
    {
        expectedError := errors.New("parse http://example.com\\noplace$: invalid character \"\\\\\" in host name")
        _, err = apih.FetchCheckBySubmissionURL(URLType("http://example.com\\noplace$"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing invalid URL (bad path)")
    {
        expectedError := errors.New("[ERROR] Invalid submission URL 'http://example.com/foo', unrecognized path")
        _, err = apih.FetchCheckBySubmissionURL(URLType("http://example.com/foo"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing invalid URL (no uuid)")
    {
        expectedError := errors.New("[ERROR] Invalid submission URL 'http://example.com/module/httptrap/', UUID not where expected")
        _, err = apih.FetchCheckBySubmissionURL(URLType("http://example.com/module/httptrap/"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing valid URL (0 checks returned)")
    {
        expectedError := errors.New("[ERROR] No checks found with UUID none")
        _, err := apih.FetchCheckBySubmissionURL(URLType("http://example.com/module/httptrap/none/boo"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing valid URL (multiple checks returned)")
    {
        expectedError := errors.New("[ERROR] Multiple checks with same UUID multi")
        _, err := apih.FetchCheckBySubmissionURL(URLType("http://example.com/module/httptrap/multi/boo"))
        if err == nil {
            t.Fatalf("Expected error")
        }
        if err.Error() != expectedError.Error() {
            t.Fatalf("Expected %+v got '%+v'", expectedError, err)
        }
    }

    t.Log("Testing valid URL (1 check returned)")
    {
        check, err := apih.FetchCheckBySubmissionURL(URLType("http://example.com/module/httptrap/abc123-abc1-def2-ghi3-123abc/boo"))
        if err != nil {
            t.Fatalf("Expected no error, got '%v'", err)
        }

        actualType := reflect.TypeOf(check)
        expectedType := "*api.Check"
        if actualType.String() != expectedType {
            t.Fatalf("Expected %s, got %s", expectedType, actualType.String())
        }

        if check.CID != testCheck.CID {
            t.Fatalf("CIDs do not match: %+v != %+v\n", check, testCheck)
        }
    }
}
*/
<|endoftext|>


<commit_before>package extension

import (
	"fmt"
	"github.com/kayex/sirius"
	"golang.org/x/net/context"
	"googlemaps.github.io/maps"
)

type Geocode struct {
	APIKey string
}

func (x *Geocode) Run(m sirius.Message, cfg sirius.ExtensionConfig) (sirius.MessageAction, error) {
	cmd, match := m.Command("address")

	if !match {
		return sirius.NoAction(), nil
	}

	c, err := maps.NewClient(maps.WithAPIKey(x.APIKey))

	if err != nil {
		return nil, err
	}

	r := &maps.GeocodingRequest{
		Address: cmd.Args[0],
	}

	res, err := c.Geocode(context.Background(), r)

	if err != nil {
		return nil, err
	}

	pos := res[0]
	location := pos.Geometry.Location
	formatted := fmt.Sprintf("*%v*\n`(%.6f, %.6f)`", pos.FormattedAddress, location.Lat, location.Lng)

	edit := m.EditText().ReplaceWith(formatted)

	return edit, nil
}
<commit_msg>Check arg length<commit_after>package extension

import (
	"fmt"
	"github.com/kayex/sirius"
	"golang.org/x/net/context"
	"googlemaps.github.io/maps"
)

type Geocode struct {
	APIKey string
}

func (x *Geocode) Run(m sirius.Message, cfg sirius.ExtensionConfig) (sirius.MessageAction, error) {
	cmd, match := m.Command("address")

	if !match || len(cmd.Args) == 0 {
		return sirius.NoAction(), nil
	}

	c, err := maps.NewClient(maps.WithAPIKey(x.APIKey))

	if err != nil {
		return nil, err
	}

	r := &maps.GeocodingRequest{
		Address: cmd.Args[0],
	}

	res, err := c.Geocode(context.Background(), r)

	if err != nil {
		return nil, err
	}

	pos := res[0]
	location := pos.Geometry.Location
	formatted := fmt.Sprintf("*%v*\n`(%.6f, %.6f)`", pos.FormattedAddress, location.Lat, location.Lng)

	edit := m.EditText().ReplaceWith(formatted)

	return edit, nil
}
<|endoftext|>