<commit_before>/*
Package pfsutil provides utility functions that wrap a pfs.ApiClient
to make the calling code slightly cleaner.
*/
package pfsutil

import (
	"io"
	"io/ioutil"

	"go.pedge.io/proto/stream"

	"github.com/pachyderm/pachyderm/src/pfs"
	"golang.org/x/net/context"
)

const (
	GetAll int64 = 1<<63 - 1
)

func CreateRepo(apiClient pfs.ApiClient, repoName string) error {
	_, err := apiClient.CreateRepo(
		context.Background(),
		&pfs.CreateRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	return err
}

func InspectRepo(apiClient pfs.ApiClient, repoName string) (*pfs.RepoInfo, error) {
	repoInfo, err := apiClient.InspectRepo(
		context.Background(),
		&pfs.InspectRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return repoInfo, nil
}

func ListRepo(apiClient pfs.ApiClient) ([]*pfs.RepoInfo, error) {
	repoInfos, err := apiClient.ListRepo(
		context.Background(),
		&pfs.ListRepoRequest{},
	)
	if err != nil {
		return nil, err
	}
	return repoInfos.RepoInfo, nil
}

func DeleteRepo(apiClient pfs.ApiClient, repoName string) error {
	_, err := apiClient.DeleteRepo(
		context.Background(),
		&pfs.DeleteRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	return err
}

func StartCommit(apiClient pfs.ApiClient, repoName string, parentCommit string) (*pfs.Commit, error) {
	commit, err := apiClient.StartCommit(
		context.Background(),
		&pfs.StartCommitRequest{
			Parent: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: parentCommit,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commit, nil
}

func FinishCommit(apiClient pfs.ApiClient, repoName string, commitID string) error {
	_, err := apiClient.FinishCommit(
		context.Background(),
		&pfs.FinishCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func InspectCommit(apiClient pfs.ApiClient, repoName string, commitID string) (*pfs.CommitInfo, error) {
	commitInfo, err := apiClient.InspectCommit(
		context.Background(),
		&pfs.InspectCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commitInfo, nil
}

func ListCommit(apiClient pfs.ApiClient, repoName string) ([]*pfs.CommitInfo, error) {
	commitInfos, err := apiClient.ListCommit(
		context.Background(),
		&pfs.ListCommitRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commitInfos.CommitInfo, nil
}

func DeleteCommit(apiClient pfs.ApiClient, repoName string, commitID string) error {
	_, err := apiClient.DeleteCommit(
		context.Background(),
		&pfs.DeleteCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func PutFile(apiClient pfs.ApiClient, repoName string, commitID string, path string, offset int64, reader io.Reader) (int64, error) {
	value, err := ioutil.ReadAll(reader)
	if err != nil {
		return 0, err
	}
	_, err = apiClient.PutFile(
		context.Background(),
		&pfs.PutFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			FileType:    pfs.FileType_FILE_TYPE_REGULAR,
			OffsetBytes: offset,
			Value:       value,
		},
	)
	return int64(len(value)), err
}

func GetFile(apiClient pfs.ApiClient, repoName string, commitID string, path string, offset int64, size int64, writer io.Writer) error {
	apiGetFileClient, err := apiClient.GetFile(
		context.Background(),
		&pfs.GetFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			OffsetBytes: offset,
			SizeBytes:   size,
		},
	)
	if err != nil {
		return err
	}
	if err := protostream.WriteFromStreamingBytesClient(apiGetFileClient, writer); err != nil {
		return err
	}
	return nil
}

func InspectFile(apiClient pfs.ApiClient, repoName string, commitID string, path string) (*pfs.FileInfo, error) {
	fileInfo, err := apiClient.InspectFile(
		context.Background(),
		&pfs.InspectFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return fileInfo, nil
}

func ListFile(apiClient pfs.ApiClient, repoName string, commitID string, path string, shard uint64, modulus uint64) ([]*pfs.FileInfo, error) {
	fileInfos, err := apiClient.ListFile(
		context.Background(),
		&pfs.ListFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: &pfs.Shard{
				Number: shard,
				Modulo: modulus,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return fileInfos.FileInfo, nil
}

func ListChange(apiClient pfs.ApiClient, repoName string, commitID string, path string, shard uint64, modulus uint64) ([]*pfs.Change, error) {
	changes, err := apiClient.ListChange(
		context.Background(),
		&pfs.ListChangeRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: &pfs.Shard{
				Number: shard,
				Modulo: modulus,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return changes.Change, nil
}

func DeleteFile(apiClient pfs.ApiClient, repoName string, commitID string, path string) error {
	_, err := apiClient.DeleteFile(
		context.Background(),
		&pfs.DeleteFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
	return err
}

func MakeDirectory(apiClient pfs.ApiClient, repoName string, commitID string, path string) error {
	_, err := apiClient.PutFile(
		context.Background(),
		&pfs.PutFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			FileType: pfs.FileType_FILE_TYPE_DIR,
		},
	)
	return err
}

func InspectServer(apiClient pfs.ApiClient, serverID string) (*pfs.ServerInfo, error) {
	return apiClient.InspectServer(
		context.Background(),
		&pfs.InspectServerRequest{
			Server: &pfs.Server{
				Id: serverID,
			},
		},
	)
}

func ListServer(apiClient pfs.ApiClient) ([]*pfs.ServerInfo, error) {
	serverInfos, err := apiClient.ListServer(
		context.Background(),
		&pfs.ListServerRequest{},
	)
	if err != nil {
		return nil, err
	}
	return serverInfos.ServerInfo, nil
}

func PullDiff(internalAPIClient pfs.InternalApiClient, repoName string, commitID string, shard uint64, writer io.Writer) error {
	apiPullDiffClient, err := internalAPIClient.PullDiff(
		context.Background(),
		&pfs.PullDiffRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return err
	}
	if err := protostream.WriteFromStreamingBytesClient(apiPullDiffClient, writer); err != nil {
		return err
	}
	return nil
}

func PushDiff(internalAPIClient pfs.InternalApiClient, repoName string, commitID string, shard uint64, reader io.Reader) error {
	value, err := ioutil.ReadAll(reader)
	if err != nil {
		return err
	}
	_, err = internalAPIClient.PushDiff(
		context.Background(),
		&pfs.PushDiffRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
			Shard: shard,
			Value: value,
		},
	)
	return err
}
<commit_msg>Adds block support to pfsutil.<commit_after>/*
Package pfsutil provides utility functions that wrap a pfs.ApiClient
to make the calling code slightly cleaner.
*/
package pfsutil

import (
	"io"
	"io/ioutil"

	"go.pedge.io/proto/stream"

	"github.com/pachyderm/pachyderm/src/pfs"
	"golang.org/x/net/context"
)

const (
	GetAll int64 = 1<<63 - 1
)

func CreateRepo(apiClient pfs.ApiClient, repoName string) error {
	_, err := apiClient.CreateRepo(
		context.Background(),
		&pfs.CreateRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	return err
}

func InspectRepo(apiClient pfs.ApiClient, repoName string) (*pfs.RepoInfo, error) {
	repoInfo, err := apiClient.InspectRepo(
		context.Background(),
		&pfs.InspectRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return repoInfo, nil
}

func ListRepo(apiClient pfs.ApiClient) ([]*pfs.RepoInfo, error) {
	repoInfos, err := apiClient.ListRepo(
		context.Background(),
		&pfs.ListRepoRequest{},
	)
	if err != nil {
		return nil, err
	}
	return repoInfos.RepoInfo, nil
}

func DeleteRepo(apiClient pfs.ApiClient, repoName string) error {
	_, err := apiClient.DeleteRepo(
		context.Background(),
		&pfs.DeleteRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	return err
}

func StartCommit(apiClient pfs.ApiClient, repoName string, parentCommit string) (*pfs.Commit, error) {
	commit, err := apiClient.StartCommit(
		context.Background(),
		&pfs.StartCommitRequest{
			Parent: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: parentCommit,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commit, nil
}

func FinishCommit(apiClient pfs.ApiClient, repoName string, commitID string) error {
	_, err := apiClient.FinishCommit(
		context.Background(),
		&pfs.FinishCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func InspectCommit(apiClient pfs.ApiClient, repoName string, commitID string) (*pfs.CommitInfo, error) {
	commitInfo, err := apiClient.InspectCommit(
		context.Background(),
		&pfs.InspectCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commitInfo, nil
}

func ListCommit(apiClient pfs.ApiClient, repoName string) ([]*pfs.CommitInfo, error) {
	commitInfos, err := apiClient.ListCommit(
		context.Background(),
		&pfs.ListCommitRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commitInfos.CommitInfo, nil
}

func DeleteCommit(apiClient pfs.ApiClient, repoName string, commitID string) error {
	_, err := apiClient.DeleteCommit(
		context.Background(),
		&pfs.DeleteCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func PutBlock(apiClient pfs.ApiClient, repoName string, commitID string, reader io.Reader) (*pfs.Block, error) {
	value, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}
	return apiClient.PutBlock(
		context.Background(),
		&pfs.PutBlockRequest{
			Parent: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
			Value: value,
		},
	)
}

func GetBlock(apiClient pfs.ApiClient, hash string, writer io.Writer) error {
	apiGetBlockClient, err := apiClient.GetBlock(
		context.Background(),
		&pfs.GetBlockRequest{
			Block: &pfs.Block{
				Hash: hash,
			},
		},
	)
	if err != nil {
		return err
	}
	if err := protostream.WriteFromStreamingBytesClient(apiGetBlockClient, writer); err != nil {
		return err
	}
	return nil
}

func InspectBlock(apiClient pfs.ApiClient, hash string) (*pfs.BlockInfo, error) {
	blockInfo, err := apiClient.InspectBlock(
		context.Background(),
		&pfs.InspectBlockRequest{
			Block: &pfs.Block{
				Hash: hash,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return blockInfo, nil
}

func ListBlock(apiClient pfs.ApiClient, shard uint64, modulus uint64) ([]*pfs.BlockInfo, error) {
	blockInfos, err := apiClient.ListBlock(
		context.Background(),
		&pfs.ListBlockRequest{
			Shard: &pfs.Shard{
				Number: shard,
				Modulo: modulus,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return blockInfos.BlockInfo, nil
}

func PutFile(apiClient pfs.ApiClient, repoName string, commitID string, path string, offset int64, reader io.Reader) (int64, error) {
	value, err := ioutil.ReadAll(reader)
	if err != nil {
		return 0, err
	}
	_, err = apiClient.PutFile(
		context.Background(),
		&pfs.PutFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			FileType:    pfs.FileType_FILE_TYPE_REGULAR,
			OffsetBytes: offset,
			Value:       value,
		},
	)
	return int64(len(value)), err
}

func GetFile(apiClient pfs.ApiClient, repoName string, commitID string, path string, offset int64, size int64, writer io.Writer) error {
	apiGetFileClient, err := apiClient.GetFile(
		context.Background(),
		&pfs.GetFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			OffsetBytes: offset,
			SizeBytes:   size,
		},
	)
	if err != nil {
		return err
	}
	if err := protostream.WriteFromStreamingBytesClient(apiGetFileClient, writer); err != nil {
		return err
	}
	return nil
}

func InspectFile(apiClient pfs.ApiClient, repoName string, commitID string, path string) (*pfs.FileInfo, error) {
	fileInfo, err := apiClient.InspectFile(
		context.Background(),
		&pfs.InspectFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return fileInfo, nil
}

func ListFile(apiClient pfs.ApiClient, repoName string, commitID string, path string, shard uint64, modulus uint64) ([]*pfs.FileInfo, error) {
	fileInfos, err := apiClient.ListFile(
		context.Background(),
		&pfs.ListFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: &pfs.Shard{
				Number: shard,
				Modulo: modulus,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return fileInfos.FileInfo, nil
}

func ListChange(apiClient pfs.ApiClient, repoName string, commitID string, path string, shard uint64, modulus uint64) ([]*pfs.Change, error) {
	changes, err := apiClient.ListChange(
		context.Background(),
		&pfs.ListChangeRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: &pfs.Shard{
				Number: shard,
				Modulo: modulus,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return changes.Change, nil
}

func DeleteFile(apiClient pfs.ApiClient, repoName string, commitID string, path string) error {
	_, err := apiClient.DeleteFile(
		context.Background(),
		&pfs.DeleteFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
	return err
}

func MakeDirectory(apiClient pfs.ApiClient, repoName string, commitID string, path string) error {
	_, err := apiClient.PutFile(
		context.Background(),
		&pfs.PutFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			FileType: pfs.FileType_FILE_TYPE_DIR,
		},
	)
	return err
}

func InspectServer(apiClient pfs.ApiClient, serverID string) (*pfs.ServerInfo, error) {
	return apiClient.InspectServer(
		context.Background(),
		&pfs.InspectServerRequest{
			Server: &pfs.Server{
				Id: serverID,
			},
		},
	)
}

func ListServer(apiClient pfs.ApiClient) ([]*pfs.ServerInfo, error) {
	serverInfos, err := apiClient.ListServer(
		context.Background(),
		&pfs.ListServerRequest{},
	)
	if err != nil {
		return nil, err
	}
	return serverInfos.ServerInfo, nil
}

func PullDiff(internalAPIClient pfs.InternalApiClient, repoName string, commitID string, shard uint64, writer io.Writer) error {
	apiPullDiffClient, err := internalAPIClient.PullDiff(
		context.Background(),
		&pfs.PullDiffRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return err
	}
	if err := protostream.WriteFromStreamingBytesClient(apiPullDiffClient, writer); err != nil {
		return err
	}
	return nil
}

func PushDiff(internalAPIClient pfs.InternalApiClient, repoName string, commitID string, shard uint64, reader io.Reader) error {
	value, err := ioutil.ReadAll(reader)
	if err != nil {
		return err
	}
	_, err = internalAPIClient.PushDiff(
		context.Background(),
		&pfs.PushDiffRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
			Shard: shard,
			Value: value,
		},
	)
	return err
}
<|endoftext|>


<commit_before>package testing

import (
	"errors"
	"fmt"
	"os"
	"sync/atomic"
	"testing"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/drive"
	"github.com/pachyderm/pachyderm/src/pfs/drive/btrfs"
	"github.com/pachyderm/pachyderm/src/pfs/route"
	"github.com/pachyderm/pachyderm/src/pfs/server"
	"github.com/pachyderm/pachyderm/src/pkg/discovery"
	"github.com/pachyderm/pachyderm/src/pkg/grpctest"
	"github.com/pachyderm/pachyderm/src/pkg/grpcutil"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
)

const (
	// TODO(pedge): large numbers of shards takes forever because
	// we are doing tons of btrfs operations on init, is there anything
	// we can do about that?
	testShardsPerServer = 8
	testNumServers      = 8
)

var (
	counter int32
)

func TestRepositoryName() string {
	// TODO could be nice to add callee to this string to make it easy to
	// recover results for debugging
	return fmt.Sprintf("test-%d", atomic.AddInt32(&counter, 1))
}

func RunTest(
	t *testing.T,
	f func(t *testing.T, apiClient pfs.ApiClient, internalAPIClient pfs.InternalApiClient),
) {
	discoveryClient, err := getEtcdClient()
	require.NoError(t, err)
	grpctest.Run(
		t,
		testNumServers,
		func(servers map[string]*grpc.Server) {
			registerFunc(t, discoveryClient, servers)
		},
		func(t *testing.T, clientConns map[string]*grpc.ClientConn) {
			var clientConn *grpc.ClientConn
			for _, c := range clientConns {
				clientConn = c
				break
			}
			f(
				t,
				pfs.NewApiClient(
					clientConn,
				),
				pfs.NewInternalApiClient(
					clientConn,
				),
			)
		},
	)
}

func RunBench(
	b *testing.B,
	f func(b *testing.B, apiClient pfs.ApiClient),
) {
	discoveryClient, err := getEtcdClient()
	require.NoError(b, err)
	grpctest.RunB(
		b,
		testNumServers,
		func(servers map[string]*grpc.Server) {
			registerFunc(b, discoveryClient, servers)
		},
		func(b *testing.B, clientConns map[string]*grpc.ClientConn) {
			var clientConn *grpc.ClientConn
			for _, c := range clientConns {
				clientConn = c
				break
			}
			f(
				b,
				pfs.NewApiClient(
					clientConn,
				),
			)
		},
	)
}

func registerFunc(tb testing.TB, discoveryClient discovery.Client, servers map[string]*grpc.Server) {
	addresser := route.NewDiscoveryAddresser(
		discoveryClient,
		testNamespace(),
	)
	i := 0
	for address := range servers {
		for j := 0; j < testShardsPerServer; j++ {
			// TODO(pedge): error
			_ = addresser.SetMasterAddress((i*testShardsPerServer)+j, address, 0)
			_ = addresser.SetSlaveAddress((((i+1)%len(servers))*testShardsPerServer)+j, address, 0)
			_ = addresser.SetSlaveAddress((((i+2)%len(servers))*testShardsPerServer)+j, address, 0)
		}
		i++
	}
	for address, s := range servers {
		combinedAPIServer := server.NewCombinedAPIServer(
			route.NewSharder(
				testShardsPerServer*testNumServers,
			),
			route.NewRouter(
				addresser,
				grpcutil.NewDialer(),
				address,
			),
			getDriver(tb, address),
		)
		pfs.RegisterApiServer(s, combinedAPIServer)
		pfs.RegisterInternalApiServer(s, combinedAPIServer)
	}
}

func getDriver(tb testing.TB, namespace string) drive.Driver {
	driver, err := btrfs.NewDriver(getBtrfsRootDir(tb), namespace)
	require.NoError(tb, err)
	return driver
}

func getBtrfsRootDir(tb testing.TB) string {
	// TODO(pedge)
	rootDir := os.Getenv("PFS_DRIVER_ROOT")
	if rootDir == "" {
		tb.Fatal("PFS_DRIVER_ROOT not set")
	}
	return rootDir
}

func getEtcdClient() (discovery.Client, error) {
	etcdAddress, err := getEtcdAddress()
	if err != nil {
		return nil, err
	}
	return discovery.NewEtcdClient(etcdAddress), nil
}

func getEtcdAddress() (string, error) {
	etcdAddr := os.Getenv("ETCD_PORT_2379_TCP_ADDR")
	if etcdAddr == "" {
		return "", errors.New("ETCD_PORT_2379_TCP_ADDR not set")
	}
	return fmt.Sprintf("http://%s:2379", etcdAddr), nil
}

func testNamespace() string {
	return fmt.Sprintf("test-%d", atomic.AddInt32(&counter, 1))
}
<commit_msg>Fix a TODO by returning errors.<commit_after>package testing

import (
	"errors"
	"fmt"
	"os"
	"sync/atomic"
	"testing"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/drive"
	"github.com/pachyderm/pachyderm/src/pfs/drive/btrfs"
	"github.com/pachyderm/pachyderm/src/pfs/route"
	"github.com/pachyderm/pachyderm/src/pfs/server"
	"github.com/pachyderm/pachyderm/src/pkg/discovery"
	"github.com/pachyderm/pachyderm/src/pkg/grpctest"
	"github.com/pachyderm/pachyderm/src/pkg/grpcutil"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
)

const (
	// TODO(pedge): large numbers of shards takes forever because
	// we are doing tons of btrfs operations on init, is there anything
	// we can do about that?
	testShardsPerServer = 8
	testNumServers      = 8
)

var (
	counter int32
)

func TestRepositoryName() string {
	// TODO could be nice to add callee to this string to make it easy to
	// recover results for debugging
	return fmt.Sprintf("test-%d", atomic.AddInt32(&counter, 1))
}

func RunTest(
	t *testing.T,
	f func(t *testing.T, apiClient pfs.ApiClient, internalAPIClient pfs.InternalApiClient),
) {
	discoveryClient, err := getEtcdClient()
	require.NoError(t, err)
	grpctest.Run(
		t,
		testNumServers,
		func(servers map[string]*grpc.Server) {
			registerFunc(t, discoveryClient, servers)
		},
		func(t *testing.T, clientConns map[string]*grpc.ClientConn) {
			var clientConn *grpc.ClientConn
			for _, c := range clientConns {
				clientConn = c
				break
			}
			f(
				t,
				pfs.NewApiClient(
					clientConn,
				),
				pfs.NewInternalApiClient(
					clientConn,
				),
			)
		},
	)
}

func RunBench(
	b *testing.B,
	f func(b *testing.B, apiClient pfs.ApiClient),
) {
	discoveryClient, err := getEtcdClient()
	require.NoError(b, err)
	grpctest.RunB(
		b,
		testNumServers,
		func(servers map[string]*grpc.Server) {
			registerFunc(b, discoveryClient, servers)
		},
		func(b *testing.B, clientConns map[string]*grpc.ClientConn) {
			var clientConn *grpc.ClientConn
			for _, c := range clientConns {
				clientConn = c
				break
			}
			f(
				b,
				pfs.NewApiClient(
					clientConn,
				),
			)
		},
	)
}

func registerFunc(tb testing.TB, discoveryClient discovery.Client, servers map[string]*grpc.Server) error {
	addresser := route.NewDiscoveryAddresser(
		discoveryClient,
		testNamespace(),
	)
	i := 0
	for address := range servers {
		for j := 0; j < testShardsPerServer; j++ {
			if err := addresser.SetMasterAddress((i*testShardsPerServer)+j, address, 0); err != nil {
				return err
			}
			if err := addresser.SetSlaveAddress((((i+1)%len(servers))*testShardsPerServer)+j, address, 0); err != nil {
				return err
			}
			if err := addresser.SetSlaveAddress((((i+2)%len(servers))*testShardsPerServer)+j, address, 0); err != nil {
				return err
			}
		}
		i++
	}
	for address, s := range servers {
		combinedAPIServer := server.NewCombinedAPIServer(
			route.NewSharder(
				testShardsPerServer*testNumServers,
			),
			route.NewRouter(
				addresser,
				grpcutil.NewDialer(),
				address,
			),
			getDriver(tb, address),
		)
		pfs.RegisterApiServer(s, combinedAPIServer)
		pfs.RegisterInternalApiServer(s, combinedAPIServer)
	}
	return nil
}

func getDriver(tb testing.TB, namespace string) drive.Driver {
	driver, err := btrfs.NewDriver(getBtrfsRootDir(tb), namespace)
	require.NoError(tb, err)
	return driver
}

func getBtrfsRootDir(tb testing.TB) string {
	// TODO(pedge)
	rootDir := os.Getenv("PFS_DRIVER_ROOT")
	if rootDir == "" {
		tb.Fatal("PFS_DRIVER_ROOT not set")
	}
	return rootDir
}

func getEtcdClient() (discovery.Client, error) {
	etcdAddress, err := getEtcdAddress()
	if err != nil {
		return nil, err
	}
	return discovery.NewEtcdClient(etcdAddress), nil
}

func getEtcdAddress() (string, error) {
	etcdAddr := os.Getenv("ETCD_PORT_2379_TCP_ADDR")
	if etcdAddr == "" {
		return "", errors.New("ETCD_PORT_2379_TCP_ADDR not set")
	}
	return fmt.Sprintf("http://%s:2379", etcdAddr), nil
}

func testNamespace() string {
	return fmt.Sprintf("test-%d", atomic.AddInt32(&counter, 1))
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2014 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// beehive's IRC module.
package ircbee

import (
	irc "github.com/fluffle/goirc/client"
	"github.com/muesli/beehive/bees"
	"log"
	"strings"
	"time"
)

type IrcBee struct {
	bees.Bee

	// channel signaling irc connection status
	connectedState chan bool

	// setup IRC client:
	client   *irc.Conn
	channels []string

	server   string
	nick     string
	password string
	ssl      bool
}

// Interface impl

func (mod *IrcBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}

	switch action.Name {
	case "send":
		tos := []string{}
		text := ""

		for _, opt := range action.Options {
			if opt.Name == "channel" {
				tos = append(tos, opt.Value.(string))
			}
			if opt.Name == "text" {
				text = opt.Value.(string)
			}
		}

		for _, recv := range tos {
			if recv == "*" {
				// special: send to all joined channels
				for _, to := range mod.channels {
					mod.client.Privmsg(to, text)
				}
			} else {
				// needs stripping hostname when sending to user!host
				if strings.Index(recv, "!") > 0 {
					recv = recv[0:strings.Index(recv, "!")]
				}

				mod.client.Privmsg(recv, text)
			}
		}

	case "join":
		for _, opt := range action.Options {
			if opt.Name == "channel" {
				mod.Join(opt.Value.(string))
			}
		}
	case "part":
		for _, opt := range action.Options {
			if opt.Name == "channel" {
				mod.Part(opt.Value.(string))
			}
		}

	default:
		panic("Unknown action triggered in " +mod.Name()+": "+action.Name)
	}

	return outs
}

// ircbee specific impl

func (mod *IrcBee) Rejoin() {
	for _, channel := range mod.channels {
		mod.client.Join(channel)
	}
}

func (mod *IrcBee) Join(channel string) {
	channel = strings.TrimSpace(channel)
	mod.client.Join(channel)

	mod.channels = append(mod.channels, channel)
}

func (mod *IrcBee) Part(channel string) {
	channel = strings.TrimSpace(channel)
	mod.client.Part(channel)

	for k, v := range mod.channels {
		if v == channel {
			mod.channels = append(mod.channels[:k], mod.channels[k+1:]...)
			return
		}
	}
}

func (mod *IrcBee) Run(eventChan chan bees.Event) {
	if len(mod.server) == 0 {
		return
	}

	// channel signaling IRC connection status
	mod.connectedState = make(chan bool)

	// setup IRC client:
	mod.client = irc.SimpleClient(mod.nick, "beehive", "beehive")
	mod.client.SSL = mod.ssl

	mod.client.AddHandler(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) {
		mod.connectedState <- true
	})
	mod.client.AddHandler(irc.DISCONNECTED, func(conn *irc.Conn, line *irc.Line) {
		mod.connectedState <- false
	})
	mod.client.AddHandler("PRIVMSG", func(conn *irc.Conn, line *irc.Line) {
		channel := line.Args[0]
		if channel == mod.client.Me.Nick {
			channel = line.Src // replies go via PM too.
		}
		msg := ""
		if len(line.Args) > 1 {
			msg = line.Args[1]
		}
		user := line.Src[:strings.Index(line.Src, "!")]
		hostmask := line.Src[strings.Index(line.Src, "!") + 2:]

		ev := bees.Event{
			Bee:  mod.Name(),
			Name: "message",
			Options: []bees.Placeholder{
				bees.Placeholder{
					Name:  "channel",
					Type:  "string",
					Value: channel,
				},
				bees.Placeholder{
					Name:  "user",
					Type:  "string",
					Value: user,
				},
				bees.Placeholder{
					Name:  "hostmask",
					Type:  "string",
					Value: hostmask,
				},
				bees.Placeholder{
					Name:  "text",
					Type:  "string",
					Value: msg,
				},
			},
		}
		eventChan <- ev
	})

	// loop on IRC dis/connected events
	for {
		log.Println("Connecting to IRC:", mod.server)
		err := mod.client.Connect(mod.server, mod.password)
		if err != nil {
			log.Println("Failed to connect to IRC:", mod.server)
			log.Println(err)
		} else {
			for {
				select {
					case <-mod.SigChan:
						mod.client.Quit()
						return

					case status := <-mod.connectedState:
						if status {
							log.Println("Connected to IRC:", mod.server)
							mod.Rejoin()
						} else {
							log.Println("Disconnected from IRC:", mod.server)
							break
						}

					default:
				}
			}
		}

		time.Sleep(5 * time.Second)
	}
}
<commit_msg>* Exit loop when disconnected.<commit_after>/*
 *    Copyright (C) 2014 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// beehive's IRC module.
package ircbee

import (
	irc "github.com/fluffle/goirc/client"
	"github.com/muesli/beehive/bees"
	"log"
	"strings"
	"time"
)

type IrcBee struct {
	bees.Bee

	// channel signaling irc connection status
	connectedState chan bool

	// setup IRC client:
	client   *irc.Conn
	channels []string

	server   string
	nick     string
	password string
	ssl      bool
}

// Interface impl

func (mod *IrcBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}

	switch action.Name {
	case "send":
		tos := []string{}
		text := ""

		for _, opt := range action.Options {
			if opt.Name == "channel" {
				tos = append(tos, opt.Value.(string))
			}
			if opt.Name == "text" {
				text = opt.Value.(string)
			}
		}

		for _, recv := range tos {
			if recv == "*" {
				// special: send to all joined channels
				for _, to := range mod.channels {
					mod.client.Privmsg(to, text)
				}
			} else {
				// needs stripping hostname when sending to user!host
				if strings.Index(recv, "!") > 0 {
					recv = recv[0:strings.Index(recv, "!")]
				}

				mod.client.Privmsg(recv, text)
			}
		}

	case "join":
		for _, opt := range action.Options {
			if opt.Name == "channel" {
				mod.Join(opt.Value.(string))
			}
		}
	case "part":
		for _, opt := range action.Options {
			if opt.Name == "channel" {
				mod.Part(opt.Value.(string))
			}
		}

	default:
		panic("Unknown action triggered in " +mod.Name()+": "+action.Name)
	}

	return outs
}

// ircbee specific impl

func (mod *IrcBee) Rejoin() {
	for _, channel := range mod.channels {
		mod.client.Join(channel)
	}
}

func (mod *IrcBee) Join(channel string) {
	channel = strings.TrimSpace(channel)
	mod.client.Join(channel)

	mod.channels = append(mod.channels, channel)
}

func (mod *IrcBee) Part(channel string) {
	channel = strings.TrimSpace(channel)
	mod.client.Part(channel)

	for k, v := range mod.channels {
		if v == channel {
			mod.channels = append(mod.channels[:k], mod.channels[k+1:]...)
			return
		}
	}
}

func (mod *IrcBee) Run(eventChan chan bees.Event) {
	if len(mod.server) == 0 {
		return
	}

	// channel signaling IRC connection status
	mod.connectedState = make(chan bool)

	// setup IRC client:
	mod.client = irc.SimpleClient(mod.nick, "beehive", "beehive")
	mod.client.SSL = mod.ssl

	mod.client.AddHandler(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) {
		mod.connectedState <- true
	})
	mod.client.AddHandler(irc.DISCONNECTED, func(conn *irc.Conn, line *irc.Line) {
		mod.connectedState <- false
	})
	mod.client.AddHandler("PRIVMSG", func(conn *irc.Conn, line *irc.Line) {
		channel := line.Args[0]
		if channel == mod.client.Me.Nick {
			channel = line.Src // replies go via PM too.
		}
		msg := ""
		if len(line.Args) > 1 {
			msg = line.Args[1]
		}
		user := line.Src[:strings.Index(line.Src, "!")]
		hostmask := line.Src[strings.Index(line.Src, "!") + 2:]

		ev := bees.Event{
			Bee:  mod.Name(),
			Name: "message",
			Options: []bees.Placeholder{
				bees.Placeholder{
					Name:  "channel",
					Type:  "string",
					Value: channel,
				},
				bees.Placeholder{
					Name:  "user",
					Type:  "string",
					Value: user,
				},
				bees.Placeholder{
					Name:  "hostmask",
					Type:  "string",
					Value: hostmask,
				},
				bees.Placeholder{
					Name:  "text",
					Type:  "string",
					Value: msg,
				},
			},
		}
		eventChan <- ev
	})

	// loop on IRC dis/connected events
	for {
		log.Println("Connecting to IRC:", mod.server)
		err := mod.client.Connect(mod.server, mod.password)
		if err != nil {
			log.Println("Failed to connect to IRC:", mod.server)
			log.Println(err)
		} else {
			disconnected := false
			for {
				if disconnected {
					break
				}
				select {
					case <-mod.SigChan:
						mod.client.Quit()
						return

					case status := <-mod.connectedState:
						if status {
							log.Println("Connected to IRC:", mod.server)
							mod.Rejoin()
						} else {
							log.Println("Disconnected from IRC:", mod.server)
							disconnected = true
							break
						}

					default:
				}
			}
		}

		time.Sleep(5 * time.Second)
	}
}
<|endoftext|>


<commit_before>package conversation

// Greeting simply replies with the greeting given
func Greeting(greeting string) string {
	return greeting
}

// GreetingV2 takes a greeting string and at the very least returns that as the response.
// it the greeting is supported then we get a relevant, in language response.
func GreetingV2(greeting string) string {

	switch greeting {
	case "Salut":
		return "Salut, ça va ?"
	case "Hola":
		return "Hola, ¿Cómo estás?"
	case "Hello":
		return "How may I help you?"
	case "Bonjour":
		return "Salut"
	}
	// return at least the given greeting to seem polite
	return greeting
}

// Extras for demo
/*case "Hello":
	return "How may I help you?"
case "Bonjour":
	return "Salut"
*/
<commit_msg>ready for the tallk<commit_after>package conversation

// Greeting simply replies with the greeting given
func Greeting(greeting string) string {
	return greeting
}

// GreetingV2 takes a greeting string and at the very least returns that as the response.
// it the greeting is supported then we get a relevant, in language response.
func GreetingV2(greeting string) string {

	switch greeting {
	case "Salut":
		return "Salut, ça va ?"
	case "Hola":
		return "Hola, ¿Cómo estás?"
	}
	// return at least the given greeting to seem polite
	return greeting
}

// Extras for demo
/*case "Hello":
	return "How may I help you?"
case "Bonjour":
	return "Salut"
*/
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"fmt"
	"log"
	"math/big"
	"time"

	"github.com/y0ssar1an/slack-pushups/internal/slack"
)

const (
	minPushUps  = 10
	maxPushUps  = 20
	openingHour = 10
	closingHour = 18
	weekdays    = 7
)

func main() {
	ch, err := slack.NewChannel("workout")
	if err != nil {
		log.Fatal(err)
	}

	loc, err := time.LoadLocation("America/Los_Angeles")
	if err != nil {
		log.Fatal(err)
	}

	// start async goroutine that chooses users randomly for push-ups
	nextMemberID := make(chan string)
	go RandomMember(ch, nextMemberID)

	sgtMittens := slack.Bot{"SgtMittens"}

	for {
		now := time.Now().In(loc)
		if closed, timeToOpen := IsAfterHours(now); closed {
			time.Sleep(timeToOpen)
			sgtMittens.PostMessage("RISE AND SHINE, KITTENS!", ch)
		}

		var user slack.User
		for user.Name == "" {
			user, err = slack.NewUser(<-nextMemberID)
			if err != nil {
				log.Println(err)
				time.Sleep(1 * time.Minute)
			}
		}

		pushUps := RandInt(minPushUps, maxPushUps+1) // +1 because upper bound is non-inclusive
		msg := fmt.Sprintf("@%s %d PUSH-UPS RIGHT MEOW!", user.Name, pushUps)

		if !ClosingSoon(now) {
			msg += "\nNext lottery for push-ups in 20 minutes"
		}

		err = sgtMittens.PostMessage(msg, ch)
		if err != nil {
			log.Println(err)
			time.Sleep(1 * time.Minute)
			continue
		}
		time.Sleep(20 * time.Minute)
	}
}

// RandomMember updates the list of members in the given Slack channel and
// returns a random member ID.
func RandomMember(ch slack.Channel, nextMemberID chan string) {
	var err error
	for {
		err = ch.UpdateMembers()
		if err != nil {
			log.Println(err)
		}

		i := RandInt(0, len(ch.Members))
		nextMemberID <- ch.Members[i]
	}
}

// RandInt uses /dev/urandom to select a random integer in the range [min, max).
func RandInt(min, max int) int {
	n, err := rand.Int(rand.Reader, big.NewInt(int64(max-min)))
	if err != nil {
		log.Println(err)
	}

	return int(n.Int64()) + min // return min if rand.Int() call fails
}

// IsAfterHours returns true if the given time is after work hours at Omaze.
// If Omaze is closed, IsAfterHours will return the duration until opening time
// on Monday.
func IsAfterHours(now time.Time) (closed bool, timeToOpen time.Duration) {
	loc := now.Location()
	if IsWeekend(now) {
		days := DaysToMonday(now.Weekday())
		mondayOpeningTime := time.Date(now.Year(), now.Month(), now.Day()+days, openingHour, 0, 0, 0, loc)
		timeToOpen = mondayOpeningTime.Sub(now)
		return true, timeToOpen
	}

	if now.Hour() < openingHour {
		openToday := time.Date(now.Year(), now.Month(), now.Day(), openingHour, 0, 0, 0, loc)
		timeToOpen = openToday.Sub(now)
		return true, timeToOpen
	}

	if now.Hour() >= closingHour {
		openTomorrow := time.Date(now.Year(), now.Month(), now.Day()+1, openingHour, 0, 0, 0, loc)
		timeToOpen = openTomorrow.Sub(now)
		return true, timeToOpen
	}

	return false, timeToOpen // 0 time
}

// IsWeekend returns true if the given time is Friday after closing time,
// Saturday, or Sunday.
func IsWeekend(t time.Time) bool {
	day := t.Weekday()
	return (day == time.Friday && t.Hour() >= closingHour) || day == time.Saturday || day == time.Sunday
}

// DaysToMonday returns the number of days from the given weekday to Monday.
func DaysToMonday(day time.Weekday) int {
	return (weekdays - int(day-time.Monday)) % weekdays
}

// ClosingSoon returns true if the given time is within 20 minutes of closing
// time.
func ClosingSoon(now time.Time) bool {
	loc := now.Location()
	closingTime := time.Date(now.Year(), now.Month(), now.Day(), closingHour, 0, 0, 0, loc)
	return closingTime.Sub(now) <= (20 * time.Minute)
}
<commit_msg>Make pushupsInterval a const at the top of slack-pushups.go<commit_after>package main

import (
	"crypto/rand"
	"fmt"
	"log"
	"math/big"
	"time"

	"github.com/y0ssar1an/slack-pushups/internal/slack"
)

const (
	minPushups     = 10
	maxPushups     = 20
	pushupInterval = 30
	openingHour    = 10
	closingHour    = 18
	weekdays       = 7
)

func main() {
	ch, err := slack.NewChannel("workout")
	if err != nil {
		log.Fatal(err)
	}

	loc, err := time.LoadLocation("America/Los_Angeles")
	if err != nil {
		log.Fatal(err)
	}

	// start async goroutine that chooses users randomly for push-ups
	nextMemberID := make(chan string)
	go RandomMember(ch, nextMemberID)

	sgtMittens := slack.Bot{"SgtMittens"}

	for {
		now := time.Now().In(loc)
		if closed, timeToOpen := IsAfterHours(now); closed {
			time.Sleep(timeToOpen)
			sgtMittens.PostMessage("RISE AND SHINE, KITTENS!", ch)
		}

		var user slack.User
		for user.Name == "" {
			user, err = slack.NewUser(<-nextMemberID)
			if err != nil {
				log.Println(err)
				time.Sleep(1 * time.Minute)
			}
		}

		pushUps := RandInt(minPushups, maxPushups+1) // +1 because upper bound is non-inclusive
		msg := fmt.Sprintf("@%s %d PUSH-UPS RIGHT MEOW!", user.Name, pushUps)

		if !ClosingSoon(now) {
			msg += fmt.Sprintf("\nNext lottery for push-ups in %d minutes", pushupInterval)
		}

		err = sgtMittens.PostMessage(msg, ch)
		if err != nil {
			log.Println(err)
			time.Sleep(1 * time.Minute)
			continue
		}
		time.Sleep(pushupInterval * time.Minute)
	}
}

// RandomMember updates the list of members in the given Slack channel and
// returns a random member ID.
func RandomMember(ch slack.Channel, nextMemberID chan string) {
	var err error
	for {
		err = ch.UpdateMembers()
		if err != nil {
			log.Println(err)
		}

		i := RandInt(0, len(ch.Members))
		nextMemberID <- ch.Members[i]
	}
}

// RandInt uses /dev/urandom to select a random integer in the range [min, max).
func RandInt(min, max int) int {
	n, err := rand.Int(rand.Reader, big.NewInt(int64(max-min)))
	if err != nil {
		log.Println(err)
	}

	return int(n.Int64()) + min // return min if rand.Int() call fails
}

// IsAfterHours returns true if the given time is after work hours at Omaze.
// If Omaze is closed, IsAfterHours will return the duration until opening time
// on Monday.
func IsAfterHours(now time.Time) (closed bool, timeToOpen time.Duration) {
	loc := now.Location()
	if IsWeekend(now) {
		days := DaysToMonday(now.Weekday())
		mondayOpeningTime := time.Date(now.Year(), now.Month(), now.Day()+days, openingHour, 0, 0, 0, loc)
		timeToOpen = mondayOpeningTime.Sub(now)
		return true, timeToOpen
	}

	if now.Hour() < openingHour {
		openToday := time.Date(now.Year(), now.Month(), now.Day(), openingHour, 0, 0, 0, loc)
		timeToOpen = openToday.Sub(now)
		return true, timeToOpen
	}

	if now.Hour() >= closingHour {
		openTomorrow := time.Date(now.Year(), now.Month(), now.Day()+1, openingHour, 0, 0, 0, loc)
		timeToOpen = openTomorrow.Sub(now)
		return true, timeToOpen
	}

	return false, timeToOpen // 0 time
}

// IsWeekend returns true if the given time is Friday after closing time,
// Saturday, or Sunday.
func IsWeekend(t time.Time) bool {
	day := t.Weekday()
	return (day == time.Friday && t.Hour() >= closingHour) || day == time.Saturday || day == time.Sunday
}

// DaysToMonday returns the number of days from the given weekday to Monday.
func DaysToMonday(day time.Weekday) int {
	return (weekdays - int(day-time.Monday)) % weekdays
}

// ClosingSoon returns true if the given time is within 20 minutes of closing
// time.
func ClosingSoon(now time.Time) bool {
	loc := now.Location()
	closingTime := time.Date(now.Year(), now.Month(), now.Day(), closingHour, 0, 0, 0, loc)
	return closingTime.Sub(now) <= (20 * time.Minute)
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package leveldb

import (
	"fmt"
	"sync/atomic"

	"github.com/conformal/goleveldb/leveldb/journal"
	"github.com/conformal/goleveldb/leveldb/storage"
)

// logging

type dropper struct {
	s    *session
	file storage.File
}

func (d dropper) Drop(err error) {
	if e, ok := err.(journal.DroppedError); ok {
		d.s.logf("journal@drop %s-%d S·%s %q", d.file.Type(), d.file.Num(), shortenb(e.Size), e.Reason)
	} else {
		d.s.logf("journal@drop %s-%d %q", d.file.Type(), d.file.Num, err)
	}
}

func (s *session) log(v ...interface{}) {
	s.stor.Log(fmt.Sprint(v...))
}

func (s *session) logf(format string, v ...interface{}) {
	s.stor.Log(fmt.Sprintf(format, v...))
}

// file utils

func (s *session) getJournalFile(num uint64) storage.File {
	return s.stor.GetFile(num, storage.TypeJournal)
}

func (s *session) getTableFile(num uint64) storage.File {
	return s.stor.GetFile(num, storage.TypeTable)
}

func (s *session) getFiles(t storage.FileType) ([]storage.File, error) {
	return s.stor.GetFiles(t)
}

// session state

// Get current version.
func (s *session) version() *version {
	s.vmu.Lock()
	defer s.vmu.Unlock()
	s.stVersion.ref++
	return s.stVersion
}

// Get current version; no barrier.
func (s *session) version_NB() *version {
	return s.stVersion
}

// Set current version to v.
func (s *session) setVersion(v *version) {
	s.vmu.Lock()
	v.ref = 1
	if old := s.stVersion; old != nil {
		v.ref++
		old.next = v
		old.release_NB()
	}
	s.stVersion = v
	s.vmu.Unlock()
}

// Get current unused file number.
func (s *session) fileNum() uint64 {
	return atomic.LoadUint64(&s.stFileNum)
}

// Get current unused file number to num.
func (s *session) setFileNum(num uint64) {
	atomic.StoreUint64(&s.stFileNum, num)
}

// Mark file number as used.
func (s *session) markFileNum(num uint64) {
	num += 1
	for {
		old, x := s.stFileNum, num
		if old > x {
			x = old
		}
		if atomic.CompareAndSwapUint64(&s.stFileNum, old, x) {
			break
		}
	}
}

// Allocate a file number.
func (s *session) allocFileNum() (num uint64) {
	return atomic.AddUint64(&s.stFileNum, 1) - 1
}

// Reuse given file number.
func (s *session) reuseFileNum(num uint64) {
	for {
		old, x := s.stFileNum, num
		if old != x+1 {
			x = old
		}
		if atomic.CompareAndSwapUint64(&s.stFileNum, old, x) {
			break
		}
	}
}

// manifest related utils

// Fill given session record obj with current states; need external
// synchronization.
func (s *session) fillRecord(r *sessionRecord, snapshot bool) {
	r.setNextNum(s.fileNum())

	if snapshot {
		if !r.has(recJournalNum) {
			r.setJournalNum(s.stJournalNum)
		}

		if !r.has(recSeq) {
			r.setSeq(s.stSeq)
		}

		for level, ik := range s.stCPtrs {
			if ik != nil {
				r.addCompactionPointer(level, ik)
			}
		}

		r.setComparer(s.cmp.cmp.Name())
	}
}

// Mark if record has been commited, this will update session state;
// need external synchronization.
func (s *session) recordCommited(r *sessionRecord) {
	if r.has(recJournalNum) {
		s.stJournalNum = r.journalNum
	}

	if r.has(recPrevJournalNum) {
		s.stPrevJournalNum = r.prevJournalNum
	}

	if r.has(recSeq) {
		s.stSeq = r.seq
	}

	for _, p := range r.compactionPointers {
		s.stCPtrs[p.level] = iKey(p.key)
	}
}

// Create a new manifest file; need external synchronization.
func (s *session) newManifest(rec *sessionRecord, v *version) (err error) {
	num := s.allocFileNum()
	file := s.stor.GetFile(num, storage.TypeManifest)
	writer, err := file.Create()
	if err != nil {
		return
	}
	jw := journal.NewWriter(writer)

	if v == nil {
		v = s.version_NB()
	}
	if rec == nil {
		rec = new(sessionRecord)
	}
	s.fillRecord(rec, true)
	v.fillRecord(rec)

	defer func() {
		if err == nil {
			s.recordCommited(rec)
			if s.manifest != nil {
				s.manifest.Close()
			}
			if s.manifestWriter != nil {
				s.manifestWriter.Close()
			}
			if s.manifestFile != nil {
				s.manifestFile.Remove()
			}
			s.manifestFile = file
			s.manifestWriter = writer
			s.manifest = jw
		} else {
			writer.Close()
			file.Remove()
			s.reuseFileNum(num)
		}
	}()

	w, err := jw.Next()
	if err != nil {
		return
	}
	err = rec.encode(w)
	if err != nil {
		return
	}
	err = jw.Flush()
	if err != nil {
		return
	}
	err = s.stor.SetManifest(file)
	return
}

// Flush record to disk.
func (s *session) flushManifest(rec *sessionRecord) (err error) {
	s.fillRecord(rec, false)
	w, err := s.manifest.Next()
	if err != nil {
		return
	}
	err = rec.encode(w)
	if err != nil {
		return
	}
	err = s.manifest.Flush()
	if err != nil {
		return
	}
	err = s.manifestWriter.Sync()
	if err != nil {
		return
	}
	s.recordCommited(rec)
	return
}
<commit_msg>Added perens to d.file.Num.<commit_after>// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package leveldb

import (
	"fmt"
	"sync/atomic"

	"github.com/conformal/goleveldb/leveldb/journal"
	"github.com/conformal/goleveldb/leveldb/storage"
)

// logging

type dropper struct {
	s    *session
	file storage.File
}

func (d dropper) Drop(err error) {
	if e, ok := err.(journal.DroppedError); ok {
		d.s.logf("journal@drop %s-%d S·%s %q", d.file.Type(), d.file.Num(), shortenb(e.Size), e.Reason)
	} else {
		d.s.logf("journal@drop %s-%d %q", d.file.Type(), d.file.Num(), err)
	}
}

func (s *session) log(v ...interface{}) {
	s.stor.Log(fmt.Sprint(v...))
}

func (s *session) logf(format string, v ...interface{}) {
	s.stor.Log(fmt.Sprintf(format, v...))
}

// file utils

func (s *session) getJournalFile(num uint64) storage.File {
	return s.stor.GetFile(num, storage.TypeJournal)
}

func (s *session) getTableFile(num uint64) storage.File {
	return s.stor.GetFile(num, storage.TypeTable)
}

func (s *session) getFiles(t storage.FileType) ([]storage.File, error) {
	return s.stor.GetFiles(t)
}

// session state

// Get current version.
func (s *session) version() *version {
	s.vmu.Lock()
	defer s.vmu.Unlock()
	s.stVersion.ref++
	return s.stVersion
}

// Get current version; no barrier.
func (s *session) version_NB() *version {
	return s.stVersion
}

// Set current version to v.
func (s *session) setVersion(v *version) {
	s.vmu.Lock()
	v.ref = 1
	if old := s.stVersion; old != nil {
		v.ref++
		old.next = v
		old.release_NB()
	}
	s.stVersion = v
	s.vmu.Unlock()
}

// Get current unused file number.
func (s *session) fileNum() uint64 {
	return atomic.LoadUint64(&s.stFileNum)
}

// Get current unused file number to num.
func (s *session) setFileNum(num uint64) {
	atomic.StoreUint64(&s.stFileNum, num)
}

// Mark file number as used.
func (s *session) markFileNum(num uint64) {
	num += 1
	for {
		old, x := s.stFileNum, num
		if old > x {
			x = old
		}
		if atomic.CompareAndSwapUint64(&s.stFileNum, old, x) {
			break
		}
	}
}

// Allocate a file number.
func (s *session) allocFileNum() (num uint64) {
	return atomic.AddUint64(&s.stFileNum, 1) - 1
}

// Reuse given file number.
func (s *session) reuseFileNum(num uint64) {
	for {
		old, x := s.stFileNum, num
		if old != x+1 {
			x = old
		}
		if atomic.CompareAndSwapUint64(&s.stFileNum, old, x) {
			break
		}
	}
}

// manifest related utils

// Fill given session record obj with current states; need external
// synchronization.
func (s *session) fillRecord(r *sessionRecord, snapshot bool) {
	r.setNextNum(s.fileNum())

	if snapshot {
		if !r.has(recJournalNum) {
			r.setJournalNum(s.stJournalNum)
		}

		if !r.has(recSeq) {
			r.setSeq(s.stSeq)
		}

		for level, ik := range s.stCPtrs {
			if ik != nil {
				r.addCompactionPointer(level, ik)
			}
		}

		r.setComparer(s.cmp.cmp.Name())
	}
}

// Mark if record has been commited, this will update session state;
// need external synchronization.
func (s *session) recordCommited(r *sessionRecord) {
	if r.has(recJournalNum) {
		s.stJournalNum = r.journalNum
	}

	if r.has(recPrevJournalNum) {
		s.stPrevJournalNum = r.prevJournalNum
	}

	if r.has(recSeq) {
		s.stSeq = r.seq
	}

	for _, p := range r.compactionPointers {
		s.stCPtrs[p.level] = iKey(p.key)
	}
}

// Create a new manifest file; need external synchronization.
func (s *session) newManifest(rec *sessionRecord, v *version) (err error) {
	num := s.allocFileNum()
	file := s.stor.GetFile(num, storage.TypeManifest)
	writer, err := file.Create()
	if err != nil {
		return
	}
	jw := journal.NewWriter(writer)

	if v == nil {
		v = s.version_NB()
	}
	if rec == nil {
		rec = new(sessionRecord)
	}
	s.fillRecord(rec, true)
	v.fillRecord(rec)

	defer func() {
		if err == nil {
			s.recordCommited(rec)
			if s.manifest != nil {
				s.manifest.Close()
			}
			if s.manifestWriter != nil {
				s.manifestWriter.Close()
			}
			if s.manifestFile != nil {
				s.manifestFile.Remove()
			}
			s.manifestFile = file
			s.manifestWriter = writer
			s.manifest = jw
		} else {
			writer.Close()
			file.Remove()
			s.reuseFileNum(num)
		}
	}()

	w, err := jw.Next()
	if err != nil {
		return
	}
	err = rec.encode(w)
	if err != nil {
		return
	}
	err = jw.Flush()
	if err != nil {
		return
	}
	err = s.stor.SetManifest(file)
	return
}

// Flush record to disk.
func (s *session) flushManifest(rec *sessionRecord) (err error) {
	s.fillRecord(rec, false)
	w, err := s.manifest.Next()
	if err != nil {
		return
	}
	err = rec.encode(w)
	if err != nil {
		return
	}
	err = s.manifest.Flush()
	if err != nil {
		return
	}
	err = s.manifestWriter.Sync()
	if err != nil {
		return
	}
	s.recordCommited(rec)
	return
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"flag"
	"io"
	"os"
	"runtime"
	"strings"
	"testing"
)

// Do not test empty datagrams by default.
// It causes unexplained timeouts on some systems,
// including Snow Leopard.  I think that the kernel
// doesn't quite expect them.
var testUDP = flag.Bool("udp", false, "whether to test UDP datagrams")

func runEcho(fd io.ReadWriter, done chan<- int) {
	var buf [1024]byte

	for {
		n, err := fd.Read(buf[0:])
		if err != nil || n == 0 || string(buf[:n]) == "END" {
			break
		}
		fd.Write(buf[0:n])
	}
	done <- 1
}

func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
	l, err := Listen(network, addr)
	if err != nil {
		t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
	}
	listening <- l.Addr().String()

	for {
		fd, err := l.Accept()
		if err != nil {
			break
		}
		echodone := make(chan int)
		go runEcho(fd, echodone)
		<-echodone // make sure Echo stops
		l.Close()
	}
	done <- 1
}

func connect(t *testing.T, network, addr string, isEmpty bool) {
	var fd Conn
	var err error
	if network == "unixgram" {
		fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
	} else {
		fd, err = Dial(network, addr)
	}
	if err != nil {
		t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
	}
	fd.SetReadTimeout(1e9) // 1s

	var b []byte
	if !isEmpty {
		b = []byte("hello, world\n")
	}
	var b1 [100]byte

	n, err1 := fd.Write(b)
	if n != len(b) {
		t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
	}

	n, err1 = fd.Read(b1[0:])
	if n != len(b) || err1 != nil {
		t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
	}

	// Send explicit ending for unixpacket.
	// Older Linux kernels do stop reads on close.
	if network == "unixpacket" {
		fd.Write([]byte("END"))
	}

	fd.Close()
}

func doTest(t *testing.T, network, listenaddr, dialaddr string) {
	t.Logf("Test %q %q %q\n", network, listenaddr, dialaddr)
	switch listenaddr {
	case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]":
		if testing.Short() || avoidMacFirewall {
			t.Logf("skip wildcard listen during short test")
			return
		}
	}
	listening := make(chan string)
	done := make(chan int)
	if network == "tcp" || network == "tcp4" || network == "tcp6" {
		listenaddr += ":0" // any available port
	}
	go runServe(t, network, listenaddr, listening, done)
	addr := <-listening // wait for server to start
	if network == "tcp" || network == "tcp4" || network == "tcp6" {
		dialaddr += addr[strings.LastIndex(addr, ":"):]
	}
	connect(t, network, dialaddr, false)
	<-done // make sure server stopped
}

func TestTCPServer(t *testing.T) {
	if runtime.GOOS != "openbsd" {
		doTest(t, "tcp", "", "127.0.0.1")
	}
	doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
	doTest(t, "tcp", "127.0.0.1", "127.0.0.1")
	doTest(t, "tcp4", "", "127.0.0.1")
	doTest(t, "tcp4", "0.0.0.0", "127.0.0.1")
	doTest(t, "tcp4", "127.0.0.1", "127.0.0.1")
	if supportsIPv6 {
		doTest(t, "tcp", "", "[::1]")
		doTest(t, "tcp", "[::]", "[::1]")
		doTest(t, "tcp", "[::1]", "[::1]")
		doTest(t, "tcp6", "", "[::1]")
		doTest(t, "tcp6", "[::]", "[::1]")
		doTest(t, "tcp6", "[::1]", "[::1]")
	}
	if supportsIPv6 && supportsIPv4map {
		doTest(t, "tcp", "[::ffff:0.0.0.0]", "127.0.0.1")
		doTest(t, "tcp", "[::]", "127.0.0.1")
		doTest(t, "tcp4", "[::ffff:0.0.0.0]", "127.0.0.1")
		doTest(t, "tcp6", "", "127.0.0.1")
		doTest(t, "tcp6", "[::ffff:0.0.0.0]", "127.0.0.1")
		doTest(t, "tcp6", "[::]", "127.0.0.1")
		doTest(t, "tcp", "127.0.0.1", "[::ffff:127.0.0.1]")
		doTest(t, "tcp", "[::ffff:127.0.0.1]", "127.0.0.1")
		doTest(t, "tcp4", "127.0.0.1", "[::ffff:127.0.0.1]")
		doTest(t, "tcp4", "[::ffff:127.0.0.1]", "127.0.0.1")
		doTest(t, "tcp6", "127.0.0.1", "[::ffff:127.0.0.1]")
		doTest(t, "tcp6", "[::ffff:127.0.0.1]", "127.0.0.1")
	}
}

func TestUnixServer(t *testing.T) {
	// "unix" sockets are not supported on windows and Plan 9.
	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
		return
	}
	os.Remove("/tmp/gotest.net")
	doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
	os.Remove("/tmp/gotest.net")
	if runtime.GOOS == "linux" {
		doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net")
		os.Remove("/tmp/gotest.net")
		// Test abstract unix domain socket, a Linux-ism
		doTest(t, "unix", "@gotest/net", "@gotest/net")
		doTest(t, "unixpacket", "@gotest/net", "@gotest/net")
	}
}

func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
	c, err := ListenPacket(network, addr)
	if err != nil {
		t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
	}
	listening <- c.LocalAddr().String()
	c.SetReadTimeout(10e6) // 10ms
	var buf [1000]byte
Run:
	for {
		n, addr, err := c.ReadFrom(buf[0:])
		if e, ok := err.(Error); ok && e.Timeout() {
			select {
			case done <- 1:
				break Run
			default:
				continue Run
			}
		}
		if err != nil {
			break
		}
		if _, err = c.WriteTo(buf[0:n], addr); err != nil {
			t.Fatalf("WriteTo %v: %v", addr, err)
		}
	}
	c.Close()
	done <- 1
}

func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) {
	t.Logf("TestPacket %s %s %s\n", network, listenaddr, dialaddr)
	listening := make(chan string)
	done := make(chan int)
	if network == "udp" {
		listenaddr += ":0" // any available port
	}
	go runPacket(t, network, listenaddr, listening, done)
	addr := <-listening // wait for server to start
	if network == "udp" {
		dialaddr += addr[strings.LastIndex(addr, ":"):]
	}
	connect(t, network, dialaddr, isEmpty)
	<-done // tell server to stop
	<-done // wait for stop
}

func TestUDPServer(t *testing.T) {
	if !*testUDP {
		return
	}
	for _, isEmpty := range []bool{false, true} {
		doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
		doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
		if supportsIPv6 && supportsIPv4map {
			doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]", isEmpty)
			doTestPacket(t, "udp", "[::]", "127.0.0.1", isEmpty)
			doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]", isEmpty)
		}
	}
}

func TestUnixDatagramServer(t *testing.T) {
	// "unix" sockets are not supported on windows and Plan 9.
	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
		return
	}
	for _, isEmpty := range []bool{false} {
		os.Remove("/tmp/gotest1.net")
		os.Remove("/tmp/gotest1.net.local")
		doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty)
		os.Remove("/tmp/gotest1.net")
		os.Remove("/tmp/gotest1.net.local")
		if runtime.GOOS == "linux" {
			// Test abstract unix domain socket, a Linux-ism
			doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty)
		}
	}
}
<commit_msg>net: consistent log format in test<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"flag"
	"io"
	"os"
	"runtime"
	"strings"
	"testing"
)

// Do not test empty datagrams by default.
// It causes unexplained timeouts on some systems,
// including Snow Leopard.  I think that the kernel
// doesn't quite expect them.
var testUDP = flag.Bool("udp", false, "whether to test UDP datagrams")

func runEcho(fd io.ReadWriter, done chan<- int) {
	var buf [1024]byte

	for {
		n, err := fd.Read(buf[0:])
		if err != nil || n == 0 || string(buf[:n]) == "END" {
			break
		}
		fd.Write(buf[0:n])
	}
	done <- 1
}

func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
	l, err := Listen(network, addr)
	if err != nil {
		t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
	}
	listening <- l.Addr().String()

	for {
		fd, err := l.Accept()
		if err != nil {
			break
		}
		echodone := make(chan int)
		go runEcho(fd, echodone)
		<-echodone // make sure Echo stops
		l.Close()
	}
	done <- 1
}

func connect(t *testing.T, network, addr string, isEmpty bool) {
	var fd Conn
	var err error
	if network == "unixgram" {
		fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
	} else {
		fd, err = Dial(network, addr)
	}
	if err != nil {
		t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
	}
	fd.SetReadTimeout(1e9) // 1s

	var b []byte
	if !isEmpty {
		b = []byte("hello, world\n")
	}
	var b1 [100]byte

	n, err1 := fd.Write(b)
	if n != len(b) {
		t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
	}

	n, err1 = fd.Read(b1[0:])
	if n != len(b) || err1 != nil {
		t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
	}

	// Send explicit ending for unixpacket.
	// Older Linux kernels do stop reads on close.
	if network == "unixpacket" {
		fd.Write([]byte("END"))
	}

	fd.Close()
}

func doTest(t *testing.T, network, listenaddr, dialaddr string) {
	t.Logf("Test %q %q %q", network, listenaddr, dialaddr)
	switch listenaddr {
	case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]":
		if testing.Short() || avoidMacFirewall {
			t.Logf("skip wildcard listen during short test")
			return
		}
	}
	listening := make(chan string)
	done := make(chan int)
	if network == "tcp" || network == "tcp4" || network == "tcp6" {
		listenaddr += ":0" // any available port
	}
	go runServe(t, network, listenaddr, listening, done)
	addr := <-listening // wait for server to start
	if network == "tcp" || network == "tcp4" || network == "tcp6" {
		dialaddr += addr[strings.LastIndex(addr, ":"):]
	}
	connect(t, network, dialaddr, false)
	<-done // make sure server stopped
}

func TestTCPServer(t *testing.T) {
	if runtime.GOOS != "openbsd" {
		doTest(t, "tcp", "", "127.0.0.1")
	}
	doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
	doTest(t, "tcp", "127.0.0.1", "127.0.0.1")
	doTest(t, "tcp4", "", "127.0.0.1")
	doTest(t, "tcp4", "0.0.0.0", "127.0.0.1")
	doTest(t, "tcp4", "127.0.0.1", "127.0.0.1")
	if supportsIPv6 {
		doTest(t, "tcp", "", "[::1]")
		doTest(t, "tcp", "[::]", "[::1]")
		doTest(t, "tcp", "[::1]", "[::1]")
		doTest(t, "tcp6", "", "[::1]")
		doTest(t, "tcp6", "[::]", "[::1]")
		doTest(t, "tcp6", "[::1]", "[::1]")
	}
	if supportsIPv6 && supportsIPv4map {
		doTest(t, "tcp", "[::ffff:0.0.0.0]", "127.0.0.1")
		doTest(t, "tcp", "[::]", "127.0.0.1")
		doTest(t, "tcp4", "[::ffff:0.0.0.0]", "127.0.0.1")
		doTest(t, "tcp6", "", "127.0.0.1")
		doTest(t, "tcp6", "[::ffff:0.0.0.0]", "127.0.0.1")
		doTest(t, "tcp6", "[::]", "127.0.0.1")
		doTest(t, "tcp", "127.0.0.1", "[::ffff:127.0.0.1]")
		doTest(t, "tcp", "[::ffff:127.0.0.1]", "127.0.0.1")
		doTest(t, "tcp4", "127.0.0.1", "[::ffff:127.0.0.1]")
		doTest(t, "tcp4", "[::ffff:127.0.0.1]", "127.0.0.1")
		doTest(t, "tcp6", "127.0.0.1", "[::ffff:127.0.0.1]")
		doTest(t, "tcp6", "[::ffff:127.0.0.1]", "127.0.0.1")
	}
}

func TestUnixServer(t *testing.T) {
	// "unix" sockets are not supported on windows and Plan 9.
	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
		return
	}
	os.Remove("/tmp/gotest.net")
	doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
	os.Remove("/tmp/gotest.net")
	if runtime.GOOS == "linux" {
		doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net")
		os.Remove("/tmp/gotest.net")
		// Test abstract unix domain socket, a Linux-ism
		doTest(t, "unix", "@gotest/net", "@gotest/net")
		doTest(t, "unixpacket", "@gotest/net", "@gotest/net")
	}
}

func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
	c, err := ListenPacket(network, addr)
	if err != nil {
		t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
	}
	listening <- c.LocalAddr().String()
	c.SetReadTimeout(10e6) // 10ms
	var buf [1000]byte
Run:
	for {
		n, addr, err := c.ReadFrom(buf[0:])
		if e, ok := err.(Error); ok && e.Timeout() {
			select {
			case done <- 1:
				break Run
			default:
				continue Run
			}
		}
		if err != nil {
			break
		}
		if _, err = c.WriteTo(buf[0:n], addr); err != nil {
			t.Fatalf("WriteTo %v: %v", addr, err)
		}
	}
	c.Close()
	done <- 1
}

func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) {
	t.Logf("TestPacket %q %q %q", network, listenaddr, dialaddr)
	listening := make(chan string)
	done := make(chan int)
	if network == "udp" {
		listenaddr += ":0" // any available port
	}
	go runPacket(t, network, listenaddr, listening, done)
	addr := <-listening // wait for server to start
	if network == "udp" {
		dialaddr += addr[strings.LastIndex(addr, ":"):]
	}
	connect(t, network, dialaddr, isEmpty)
	<-done // tell server to stop
	<-done // wait for stop
}

func TestUDPServer(t *testing.T) {
	if !*testUDP {
		return
	}
	for _, isEmpty := range []bool{false, true} {
		doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
		doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
		if supportsIPv6 && supportsIPv4map {
			doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]", isEmpty)
			doTestPacket(t, "udp", "[::]", "127.0.0.1", isEmpty)
			doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]", isEmpty)
		}
	}
}

func TestUnixDatagramServer(t *testing.T) {
	// "unix" sockets are not supported on windows and Plan 9.
	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
		return
	}
	for _, isEmpty := range []bool{false} {
		os.Remove("/tmp/gotest1.net")
		os.Remove("/tmp/gotest1.net.local")
		doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty)
		os.Remove("/tmp/gotest1.net")
		os.Remove("/tmp/gotest1.net.local")
		if runtime.GOOS == "linux" {
			// Test abstract unix domain socket, a Linux-ism
			doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// A package of simple functions to manipulate strings.
package strings

import (
	"unicode"
	"utf8"
)

// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n <= 0 means no limit).
// Invalid UTF-8 sequences become correct encodings of U+FFF8.
func explode(s string, n int) []string {
	l := utf8.RuneCountInString(s)
	if n <= 0 || n > l {
		n = l
	}
	a := make([]string, n)
	var size, rune int
	i, cur := 0, 0
	for ; i+1 < n; i++ {
		rune, size = utf8.DecodeRuneInString(s[cur:])
		a[i] = string(rune)
		cur += size
	}
	// add the rest
	a[i] = s[cur:]
	return a
}

// Count counts the number of non-overlapping instances of sep in s.
func Count(s, sep string) int {
	if sep == "" {
		return utf8.RuneCountInString(s) + 1
	}
	c := sep[0]
	l := len(sep)
	n := 0
	if l == 1 {
		// special case worth making fast
		for i := 0; i < len(s); i++ {
			if s[i] == c {
				n++
			}
		}
		return n
	}
	for i := 0; i+l <= len(s); i++ {
		if s[i] == c && s[i:i+l] == sep {
			n++
			i += l - 1
		}
	}
	return n
}

// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
func Index(s, sep string) int {
	n := len(sep)
	if n == 0 {
		return 0
	}
	c := sep[0]
	if n == 1 {
		// special case worth making fast
		for i := 0; i < len(s); i++ {
			if s[i] == c {
				return i
			}
		}
		return -1
	}
	// n > 1
	for i := 0; i+n <= len(s); i++ {
		if s[i] == c && s[i:i+n] == sep {
			return i
		}
	}
	return -1
}

// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
func LastIndex(s, sep string) int {
	n := len(sep)
	if n == 0 {
		return len(s)
	}
	c := sep[0]
	if n == 1 {
		// special case worth making fast
		for i := len(s) - 1; i >= 0; i-- {
			if s[i] == c {
				return i
			}
		}
		return -1
	}
	// n > 1
	for i := len(s) - n; i >= 0; i-- {
		if s[i] == c && s[i:i+n] == sep {
			return i
		}
	}
	return -1
}

// IndexRune returns the index of the first instance of the Unicode code point
// rune, or -1 if rune is not present in s.
func IndexRune(s string, rune int) int {
	for i, c := range s {
		if c == rune {
			return i
		}
	}
	return -1
}

// IndexAny returns the index of the first instance of any Unicode code point
// from chars in s, or -1 if no Unicode code point from chars is present in s.
func IndexAny(s, chars string) int {
	if len(chars) > 0 {
		for i, c := range s {
			for _, m := range chars {
				if c == m {
					return i
				}
			}
		}
	}
	return -1
}

// Generic split: splits after each instance of sep,
// including sepSave bytes of sep in the subarrays.
func genSplit(s, sep string, sepSave, n int) []string {
	if sep == "" {
		return explode(s, n)
	}
	if n <= 0 {
		n = Count(s, sep) + 1
	}
	c := sep[0]
	start := 0
	a := make([]string, n)
	na := 0
	for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			a[na] = s[start : i+sepSave]
			na++
			start = i + len(sep)
			i += len(sep) - 1
		}
	}
	a[na] = s[start:]
	return a[0 : na+1]
}

// Split splits the string s around each instance of sep, returning an array of substrings of s.
// If sep is empty, Split splits s after each UTF-8 sequence.
// If n > 0, Split splits s into at most n substrings; the last substring will be the unsplit remainder.
func Split(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }

// SplitAfter splits the string s after each instance of sep, returning an array of substrings of s.
// If sep is empty, SplitAfter splits s after each UTF-8 sequence.
// If n > 0, SplitAfter splits s into at most n substrings; the last substring will be the unsplit remainder.
func SplitAfter(s, sep string, n int) []string {
	return genSplit(s, sep, len(sep), n)
}

// Fields splits the string s around each instance of one or more consecutive white space
// characters, returning an array of substrings of s or an empty list if s contains only white space.
func Fields(s string) []string {
	return FieldsFunc(s, unicode.IsSpace)
}

// FieldsFunc splits the string s at each run of Unicode code points c satifying f(c)
// and returns an array of slices of s. If no code points in s satisfy f(c), an empty slice
// is returned.
func FieldsFunc(s string, f func(int) bool) []string {
	// First count the fields.
	n := 0
	inField := false
	for _, rune := range s {
		wasInField := inField
		inField = !f(rune)
		if inField && !wasInField {
			n++
		}
	}

	// Now create them.
	a := make([]string, n)
	na := 0
	fieldStart := -1 // Set to -1 when looking for start of field.
	for i, rune := range s {
		if f(rune) {
			if fieldStart >= 0 {
				a[na] = s[fieldStart:i]
				na++
				fieldStart = -1
			}
		} else if fieldStart == -1 {
			fieldStart = i
		}
	}
	if fieldStart != -1 { // Last field might end at EOF.
		a[na] = s[fieldStart:]
	}
	return a
}

// Join concatenates the elements of a to create a single string.   The separator string
// sep is placed between elements in the resulting string.
func Join(a []string, sep string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := len(sep) * (len(a) - 1)
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := make([]byte, n)
	bp := 0
	for i := 0; i < len(a); i++ {
		s := a[i]
		for j := 0; j < len(s); j++ {
			b[bp] = s[j]
			bp++
		}
		if i+1 < len(a) {
			s = sep
			for j := 0; j < len(s); j++ {
				b[bp] = s[j]
				bp++
			}
		}
	}
	return string(b)
}

// HasPrefix tests whether the string s begins with prefix.
func HasPrefix(s, prefix string) bool {
	return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
}

// HasSuffix tests whether the string s ends with suffix.
func HasSuffix(s, suffix string) bool {
	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
}

// Map returns a copy of the string s with all its characters modified
// according to the mapping function. If mapping returns a negative value, the character is
// dropped from the string with no replacement.
func Map(mapping func(rune int) int, s string) string {
	// In the worst case, the string can grow when mapped, making
	// things unpleasant.  But it's so rare we barge in assuming it's
	// fine.  It could also shrink but that falls out naturally.
	maxbytes := len(s) // length of b
	nbytes := 0        // number of bytes encoded in b
	b := make([]byte, maxbytes)
	for _, c := range s {
		rune := mapping(c)
		if rune >= 0 {
			wid := 1
			if rune >= utf8.RuneSelf {
				wid = utf8.RuneLen(rune)
			}
			if nbytes+wid > maxbytes {
				// Grow the buffer.
				maxbytes = maxbytes*2 + utf8.UTFMax
				nb := make([]byte, maxbytes)
				for i, c := range b[0:nbytes] {
					nb[i] = c
				}
				b = nb
			}
			nbytes += utf8.EncodeRune(rune, b[nbytes:maxbytes])
		}
	}
	return string(b[0:nbytes])
}

// Repeat returns a new string consisting of count copies of the string s.
func Repeat(s string, count int) string {
	b := make([]byte, len(s)*count)
	bp := 0
	for i := 0; i < count; i++ {
		for j := 0; j < len(s); j++ {
			b[bp] = s[j]
			bp++
		}
	}
	return string(b)
}

// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
func ToUpper(s string) string { return Map(unicode.ToUpper, s) }

// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.
func ToLower(s string) string { return Map(unicode.ToLower, s) }

// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case.
func ToTitle(s string) string { return Map(unicode.ToTitle, s) }

// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
// upper case, giving priority to the special casing rules.
func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
	return Map(func(r int) int { return _case.ToUpper(r) }, s)
}

// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their
// lower case, giving priority to the special casing rules.
func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
	return Map(func(r int) int { return _case.ToLower(r) }, s)
}

// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
// title case, giving priority to the special casing rules.
func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
	return Map(func(r int) int { return _case.ToTitle(r) }, s)
}

// TrimLeftFunc returns a slice of the string s with all leading
// Unicode code points c satisfying f(c) removed.
func TrimLeftFunc(s string, f func(r int) bool) string {
	start, end := 0, len(s)
	for start < end {
		wid := 1
		rune := int(s[start])
		if rune >= utf8.RuneSelf {
			rune, wid = utf8.DecodeRuneInString(s[start:end])
		}
		if !f(rune) {
			return s[start:]
		}
		start += wid
	}
	return s[start:]
}

// TrimRightFunc returns a slice of the string s with all trailing
// Unicode code points c satisfying f(c) removed.
func TrimRightFunc(s string, f func(r int) bool) string {
	start, end := 0, len(s)
	for start < end {
		wid := 1
		rune := int(s[end-wid])
		if rune >= utf8.RuneSelf {
			// Back up & look for beginning of rune. Mustn't pass start.
			for wid = 2; start <= end-wid && !utf8.RuneStart(s[end-wid]); wid++ {
			}
			if start > end-wid { // invalid UTF-8 sequence; stop processing
				return s[start:end]
			}
			rune, wid = utf8.DecodeRuneInString(s[end-wid : end])
		}
		if !f(rune) {
			return s[0:end]
		}
		end -= wid
	}
	return s[0:end]
}

// TrimFunc returns a slice of the string s with all leading
// and trailing Unicode code points c satisfying f(c) removed.
func TrimFunc(s string, f func(r int) bool) string {
	return TrimRightFunc(TrimLeftFunc(s, f), f)
}

func makeCutsetFunc(cutset string) func(rune int) bool {
	return func(rune int) bool { return IndexRune(cutset, rune) != -1 }
}

// Trim returns a slice of the string s with all leading and
// trailing Unicode code points contained in cutset removed.
func Trim(s string, cutset string) string {
	if s == "" || cutset == "" {
		return s
	}
	return TrimFunc(s, makeCutsetFunc(cutset))
}

// TrimLeft returns a slice of the string s with all leading
// Unicode code points contained in cutset removed.
func TrimLeft(s string, cutset string) string {
	if s == "" || cutset == "" {
		return s
	}
	return TrimLeftFunc(s, makeCutsetFunc(cutset))
}

// TrimRight returns a slice of the string s, with all trailing
// Unicode code points contained in cutset removed.
func TrimRight(s string, cutset string) string {
	if s == "" || cutset == "" {
		return s
	}
	return TrimRightFunc(s, makeCutsetFunc(cutset))
}

// TrimSpace returns a slice of the string s, with all leading
// and trailing white space removed, as defined by Unicode.
func TrimSpace(s string) string {
	return TrimFunc(s, unicode.IsSpace)
}
<commit_msg>Conversion from loop to copy().<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// A package of simple functions to manipulate strings.
package strings

import (
	"unicode"
	"utf8"
)

// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n <= 0 means no limit).
// Invalid UTF-8 sequences become correct encodings of U+FFF8.
func explode(s string, n int) []string {
	l := utf8.RuneCountInString(s)
	if n <= 0 || n > l {
		n = l
	}
	a := make([]string, n)
	var size, rune int
	i, cur := 0, 0
	for ; i+1 < n; i++ {
		rune, size = utf8.DecodeRuneInString(s[cur:])
		a[i] = string(rune)
		cur += size
	}
	// add the rest
	a[i] = s[cur:]
	return a
}

// Count counts the number of non-overlapping instances of sep in s.
func Count(s, sep string) int {
	if sep == "" {
		return utf8.RuneCountInString(s) + 1
	}
	c := sep[0]
	l := len(sep)
	n := 0
	if l == 1 {
		// special case worth making fast
		for i := 0; i < len(s); i++ {
			if s[i] == c {
				n++
			}
		}
		return n
	}
	for i := 0; i+l <= len(s); i++ {
		if s[i] == c && s[i:i+l] == sep {
			n++
			i += l - 1
		}
	}
	return n
}

// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
func Index(s, sep string) int {
	n := len(sep)
	if n == 0 {
		return 0
	}
	c := sep[0]
	if n == 1 {
		// special case worth making fast
		for i := 0; i < len(s); i++ {
			if s[i] == c {
				return i
			}
		}
		return -1
	}
	// n > 1
	for i := 0; i+n <= len(s); i++ {
		if s[i] == c && s[i:i+n] == sep {
			return i
		}
	}
	return -1
}

// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
func LastIndex(s, sep string) int {
	n := len(sep)
	if n == 0 {
		return len(s)
	}
	c := sep[0]
	if n == 1 {
		// special case worth making fast
		for i := len(s) - 1; i >= 0; i-- {
			if s[i] == c {
				return i
			}
		}
		return -1
	}
	// n > 1
	for i := len(s) - n; i >= 0; i-- {
		if s[i] == c && s[i:i+n] == sep {
			return i
		}
	}
	return -1
}

// IndexRune returns the index of the first instance of the Unicode code point
// rune, or -1 if rune is not present in s.
func IndexRune(s string, rune int) int {
	for i, c := range s {
		if c == rune {
			return i
		}
	}
	return -1
}

// IndexAny returns the index of the first instance of any Unicode code point
// from chars in s, or -1 if no Unicode code point from chars is present in s.
func IndexAny(s, chars string) int {
	if len(chars) > 0 {
		for i, c := range s {
			for _, m := range chars {
				if c == m {
					return i
				}
			}
		}
	}
	return -1
}

// Generic split: splits after each instance of sep,
// including sepSave bytes of sep in the subarrays.
func genSplit(s, sep string, sepSave, n int) []string {
	if sep == "" {
		return explode(s, n)
	}
	if n <= 0 {
		n = Count(s, sep) + 1
	}
	c := sep[0]
	start := 0
	a := make([]string, n)
	na := 0
	for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			a[na] = s[start : i+sepSave]
			na++
			start = i + len(sep)
			i += len(sep) - 1
		}
	}
	a[na] = s[start:]
	return a[0 : na+1]
}

// Split splits the string s around each instance of sep, returning an array of substrings of s.
// If sep is empty, Split splits s after each UTF-8 sequence.
// If n > 0, Split splits s into at most n substrings; the last substring will be the unsplit remainder.
func Split(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }

// SplitAfter splits the string s after each instance of sep, returning an array of substrings of s.
// If sep is empty, SplitAfter splits s after each UTF-8 sequence.
// If n > 0, SplitAfter splits s into at most n substrings; the last substring will be the unsplit remainder.
func SplitAfter(s, sep string, n int) []string {
	return genSplit(s, sep, len(sep), n)
}

// Fields splits the string s around each instance of one or more consecutive white space
// characters, returning an array of substrings of s or an empty list if s contains only white space.
func Fields(s string) []string {
	return FieldsFunc(s, unicode.IsSpace)
}

// FieldsFunc splits the string s at each run of Unicode code points c satifying f(c)
// and returns an array of slices of s. If no code points in s satisfy f(c), an empty slice
// is returned.
func FieldsFunc(s string, f func(int) bool) []string {
	// First count the fields.
	n := 0
	inField := false
	for _, rune := range s {
		wasInField := inField
		inField = !f(rune)
		if inField && !wasInField {
			n++
		}
	}

	// Now create them.
	a := make([]string, n)
	na := 0
	fieldStart := -1 // Set to -1 when looking for start of field.
	for i, rune := range s {
		if f(rune) {
			if fieldStart >= 0 {
				a[na] = s[fieldStart:i]
				na++
				fieldStart = -1
			}
		} else if fieldStart == -1 {
			fieldStart = i
		}
	}
	if fieldStart != -1 { // Last field might end at EOF.
		a[na] = s[fieldStart:]
	}
	return a
}

// Join concatenates the elements of a to create a single string.   The separator string
// sep is placed between elements in the resulting string.
func Join(a []string, sep string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := len(sep) * (len(a) - 1)
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := make([]byte, n)
	bp := 0
	for i := 0; i < len(a); i++ {
		s := a[i]
		for j := 0; j < len(s); j++ {
			b[bp] = s[j]
			bp++
		}
		if i+1 < len(a) {
			s = sep
			for j := 0; j < len(s); j++ {
				b[bp] = s[j]
				bp++
			}
		}
	}
	return string(b)
}

// HasPrefix tests whether the string s begins with prefix.
func HasPrefix(s, prefix string) bool {
	return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
}

// HasSuffix tests whether the string s ends with suffix.
func HasSuffix(s, suffix string) bool {
	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
}

// Map returns a copy of the string s with all its characters modified
// according to the mapping function. If mapping returns a negative value, the character is
// dropped from the string with no replacement.
func Map(mapping func(rune int) int, s string) string {
	// In the worst case, the string can grow when mapped, making
	// things unpleasant.  But it's so rare we barge in assuming it's
	// fine.  It could also shrink but that falls out naturally.
	maxbytes := len(s) // length of b
	nbytes := 0        // number of bytes encoded in b
	b := make([]byte, maxbytes)
	for _, c := range s {
		rune := mapping(c)
		if rune >= 0 {
			wid := 1
			if rune >= utf8.RuneSelf {
				wid = utf8.RuneLen(rune)
			}
			if nbytes+wid > maxbytes {
				// Grow the buffer.
				maxbytes = maxbytes*2 + utf8.UTFMax
				nb := make([]byte, maxbytes)
				copy(nb, b[0:nbytes])
				b = nb
			}
			nbytes += utf8.EncodeRune(rune, b[nbytes:maxbytes])
		}
	}
	return string(b[0:nbytes])
}

// Repeat returns a new string consisting of count copies of the string s.
func Repeat(s string, count int) string {
	b := make([]byte, len(s)*count)
	bp := 0
	for i := 0; i < count; i++ {
		for j := 0; j < len(s); j++ {
			b[bp] = s[j]
			bp++
		}
	}
	return string(b)
}

// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
func ToUpper(s string) string { return Map(unicode.ToUpper, s) }

// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.
func ToLower(s string) string { return Map(unicode.ToLower, s) }

// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case.
func ToTitle(s string) string { return Map(unicode.ToTitle, s) }

// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
// upper case, giving priority to the special casing rules.
func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
	return Map(func(r int) int { return _case.ToUpper(r) }, s)
}

// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their
// lower case, giving priority to the special casing rules.
func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
	return Map(func(r int) int { return _case.ToLower(r) }, s)
}

// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
// title case, giving priority to the special casing rules.
func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
	return Map(func(r int) int { return _case.ToTitle(r) }, s)
}

// TrimLeftFunc returns a slice of the string s with all leading
// Unicode code points c satisfying f(c) removed.
func TrimLeftFunc(s string, f func(r int) bool) string {
	start, end := 0, len(s)
	for start < end {
		wid := 1
		rune := int(s[start])
		if rune >= utf8.RuneSelf {
			rune, wid = utf8.DecodeRuneInString(s[start:end])
		}
		if !f(rune) {
			return s[start:]
		}
		start += wid
	}
	return s[start:]
}

// TrimRightFunc returns a slice of the string s with all trailing
// Unicode code points c satisfying f(c) removed.
func TrimRightFunc(s string, f func(r int) bool) string {
	start, end := 0, len(s)
	for start < end {
		wid := 1
		rune := int(s[end-wid])
		if rune >= utf8.RuneSelf {
			// Back up & look for beginning of rune. Mustn't pass start.
			for wid = 2; start <= end-wid && !utf8.RuneStart(s[end-wid]); wid++ {
			}
			if start > end-wid { // invalid UTF-8 sequence; stop processing
				return s[start:end]
			}
			rune, wid = utf8.DecodeRuneInString(s[end-wid : end])
		}
		if !f(rune) {
			return s[0:end]
		}
		end -= wid
	}
	return s[0:end]
}

// TrimFunc returns a slice of the string s with all leading
// and trailing Unicode code points c satisfying f(c) removed.
func TrimFunc(s string, f func(r int) bool) string {
	return TrimRightFunc(TrimLeftFunc(s, f), f)
}

func makeCutsetFunc(cutset string) func(rune int) bool {
	return func(rune int) bool { return IndexRune(cutset, rune) != -1 }
}

// Trim returns a slice of the string s with all leading and
// trailing Unicode code points contained in cutset removed.
func Trim(s string, cutset string) string {
	if s == "" || cutset == "" {
		return s
	}
	return TrimFunc(s, makeCutsetFunc(cutset))
}

// TrimLeft returns a slice of the string s with all leading
// Unicode code points contained in cutset removed.
func TrimLeft(s string, cutset string) string {
	if s == "" || cutset == "" {
		return s
	}
	return TrimLeftFunc(s, makeCutsetFunc(cutset))
}

// TrimRight returns a slice of the string s, with all trailing
// Unicode code points contained in cutset removed.
func TrimRight(s string, cutset string) string {
	if s == "" || cutset == "" {
		return s
	}
	return TrimRightFunc(s, makeCutsetFunc(cutset))
}

// TrimSpace returns a slice of the string s, with all leading
// and trailing white space removed, as defined by Unicode.
func TrimSpace(s string) string {
	return TrimFunc(s, unicode.IsSpace)
}
<|endoftext|>