<commit_before>package zfs

import (
	"bytes"
	"fmt"
	"io"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

type command struct {
	Command string
	Stdin   io.Reader
	Stdout  io.Writer
}

func (c *command) Run(arg ...string) ([][]string, error) {

	cmd := exec.Command(c.Command, arg...)

	var stdout, stderr bytes.Buffer

	if c.Stdout == nil {
		cmd.Stdout = &stdout
	} else {
		cmd.Stdout = c.Stdout
	}

	if c.Stdin != nil {
		cmd.Stdin = c.Stdin

	}
	cmd.Stderr = &stderr

	debug := strings.Join([]string{cmd.Path, strings.Join(cmd.Args, " ")}, " ")
	if logger != nil {
		logger.Log(cmd.Args)
	}
	err := cmd.Run()

	if err != nil {
		return nil, &Error{
			Err:    err,
			Debug:  debug,
			Stderr: stderr.String(),
		}
	}

	// assume if you passed in something for stdout, that you know what to do with it
	if c.Stdout != nil {
		return nil, nil
	}

	lines := strings.Split(stdout.String(), "\n")

	//last line is always blank
	lines = lines[0 : len(lines)-1]
	output := make([][]string, len(lines))

	for i, l := range lines {
		output[i] = strings.Fields(l)
	}

	return output, nil
}

func setString(field *string, value string) {
	v := ""
	if value != "-" {
		v = value
	}
	*field = v
}

func setUint(field *uint64, value string) error {
	var v uint64
	if value != "-" {
		var err error
		v, err = strconv.ParseUint(value, 10, 64)
		if err != nil {
			return err
		}
	}
	*field = v
	return nil
}

func (ds *Dataset) parseLine(line []string) error {
	prop := line[1]
	val := line[2]

	var err error

	switch prop {
	case "available":
		err = setUint(&ds.Avail, val)
	case "compression":
		setString(&ds.Compression, val)
	case "mountpoint":
		setString(&ds.Mountpoint, val)
	case "quota":
		err = setUint(&ds.Quota, val)
	case "type":
		setString(&ds.Type, val)
	case "origin":
		setString(&ds.Origin, val)
	case "used":
		err = setUint(&ds.Used, val)
	case "volsize":
		err = setUint(&ds.Volsize, val)
	case "written":
		err = setUint(&ds.Written, val)
	case "logicalused":
		err = setUint(&ds.Logicalused, val)
	}
	return err
}

/*
 * from zfs diff`s escape function:
 *
 * Prints a file name out a character at a time.  If the character is
 * not in the range of what we consider "printable" ASCII, display it
 * as an escaped 3-digit octal value.  ASCII values less than a space
 * are all control characters and we declare the upper end as the
 * DELete character.  This also is the last 7-bit ASCII character.
 * We choose to treat all 8-bit ASCII as not printable for this
 * application.
 */
func unescapeFilepath(path string) (string, error) {
	buf := make([]byte, 0, len(path))
	llen := len(path)
	for i := 0; i < llen; {
		if path[i] == '\\' {
			if llen < i+4 {
				return "", fmt.Errorf("Invalid octal code: too short")
			}
			octalCode := path[(i + 1):(i + 4)]
			val, err := strconv.ParseUint(octalCode, 8, 8)
			if err != nil {
				return "", fmt.Errorf("Invalid octal code: %v", err)
			}
			buf = append(buf, byte(val))
			i += 4
		} else {
			buf = append(buf, path[i])
			i++
		}
	}
	return string(buf), nil
}

var changeTypeMap = map[string]ChangeType{
	"-": Removed,
	"+": Created,
	"M": Modified,
	"R": Renamed,
}
var inodeTypeMap = map[string]InodeType{
	"B": BlockDevice,
	"C": CharacterDevice,
	"/": Directory,
	">": Door,
	"|": NamedPipe,
	"@": SymbolicLink,
	"P": EventPort,
	"=": Socket,
	"F": File,
}

// matches (+1) or (-1)
var referenceCountRegex = regexp.MustCompile("\\(([+-]\\d+?)\\)")

func parseReferenceCount(field string) (int, error) {
	matches := referenceCountRegex.FindStringSubmatch(field)
	if matches == nil {
		return 0, fmt.Errorf("Regexp does not match")
	}
	return strconv.Atoi(matches[1])
}

func parseInodeChange(line []string) (*InodeChange, error) {
	llen := len(line)
	if llen < 1 {
		return nil, fmt.Errorf("Empty line passed")
	}

	changeType := changeTypeMap[line[0]]
	if changeType == 0 {
		return nil, fmt.Errorf("Unknown change type '%s'", line[0])
	}

	switch changeType {
	case Renamed:
		if llen != 4 {
			return nil, fmt.Errorf("Mismatching number of fields: expect 4, got: %d", llen)
		}
	case Modified:
		if llen != 4 && llen != 3 {
			return nil, fmt.Errorf("Mismatching number of fields: expect 3..4, got: %d", llen)
		}
	default:
		if llen != 3 {
			return nil, fmt.Errorf("Mismatching number of fields: expect 3, got: %d", llen)
		}
	}

	inodeType := inodeTypeMap[line[1]]
	if inodeType == 0 {
		return nil, fmt.Errorf("Unknown inode type '%s'", line[1])
	}

	path, err := unescapeFilepath(line[2])
	if err != nil {
		return nil, fmt.Errorf("Failed to parse filename: %v", err)
	}

	var newPath string
	var referenceCount int
	switch changeType {
	case Renamed:
		newPath, err = unescapeFilepath(line[3])
		if err != nil {
			return nil, fmt.Errorf("Failed to parse filename: %v", err)
		}
	case Modified:
		if llen == 4 {
			referenceCount, err = parseReferenceCount(line[3])
			if err != nil {
				return nil, fmt.Errorf("Failed to parse reference count: %v", err)
			}
		}
	default:
		newPath = ""
	}

	return &InodeChange{
		Change:               changeType,
		Type:                 inodeType,
		Path:                 path,
		NewPath:              newPath,
		ReferenceCountChange: referenceCount,
	}, nil
}

// example input
//M       /       /testpool/bar/
//+       F       /testpool/bar/hello.txt
//M       /       /testpool/bar/hello.txt (+1)
//M       /       /testpool/bar/hello-hardlink
func parseInodeChanges(lines [][]string) ([]*InodeChange, error) {
	changes := make([]*InodeChange, len(lines))

	for i, line := range lines {
		c, err := parseInodeChange(line)
		if err != nil {
			return nil, fmt.Errorf("Failed to parse line %d of zfs diff: %v, got: '%s'", i, err, line)
		}
		changes[i] = c
	}
	return changes, nil
}

func listByType(t, filter string) ([]*Dataset, error) {
	args := []string{"get", "all", "-t", t, "-rHp"}
	if filter != "" {
		args = append(args, filter)
	}
	out, err := zfs(args...)
	if err != nil {
		return nil, err
	}

	var datasets []*Dataset

	name := ""
	var ds *Dataset
	for _, line := range out {
		if name != line[0] {
			name = line[0]
			ds = &Dataset{Name: name}
			datasets = append(datasets, ds)
		}
		if err := ds.parseLine(line); err != nil {
			return nil, err
		}
	}

	return datasets, nil
}

func propsSlice(properties map[string]string) []string {
	args := make([]string, 0, len(properties)*3)
	for k, v := range properties {
		args = append(args, "-o")
		args = append(args, fmt.Sprintf("%s=%s", k, v))
	}
	return args
}

func (z *Zpool) parseLine(line []string) error {
	prop := line[1]
	val := line[2]

	var err error

	switch prop {
	case "health":
		setString(&z.Health, val)
	case "allocated":
		err = setUint(&z.Allocated, val)
	case "size":
		err = setUint(&z.Size, val)
	case "free":
		err = setUint(&z.Free, val)
	}
	return err
}
<commit_msg>use raw string literal for regex<commit_after>package zfs

import (
	"bytes"
	"fmt"
	"io"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

type command struct {
	Command string
	Stdin   io.Reader
	Stdout  io.Writer
}

func (c *command) Run(arg ...string) ([][]string, error) {

	cmd := exec.Command(c.Command, arg...)

	var stdout, stderr bytes.Buffer

	if c.Stdout == nil {
		cmd.Stdout = &stdout
	} else {
		cmd.Stdout = c.Stdout
	}

	if c.Stdin != nil {
		cmd.Stdin = c.Stdin

	}
	cmd.Stderr = &stderr

	debug := strings.Join([]string{cmd.Path, strings.Join(cmd.Args, " ")}, " ")
	if logger != nil {
		logger.Log(cmd.Args)
	}
	err := cmd.Run()

	if err != nil {
		return nil, &Error{
			Err:    err,
			Debug:  debug,
			Stderr: stderr.String(),
		}
	}

	// assume if you passed in something for stdout, that you know what to do with it
	if c.Stdout != nil {
		return nil, nil
	}

	lines := strings.Split(stdout.String(), "\n")

	//last line is always blank
	lines = lines[0 : len(lines)-1]
	output := make([][]string, len(lines))

	for i, l := range lines {
		output[i] = strings.Fields(l)
	}

	return output, nil
}

func setString(field *string, value string) {
	v := ""
	if value != "-" {
		v = value
	}
	*field = v
}

func setUint(field *uint64, value string) error {
	var v uint64
	if value != "-" {
		var err error
		v, err = strconv.ParseUint(value, 10, 64)
		if err != nil {
			return err
		}
	}
	*field = v
	return nil
}

func (ds *Dataset) parseLine(line []string) error {
	prop := line[1]
	val := line[2]

	var err error

	switch prop {
	case "available":
		err = setUint(&ds.Avail, val)
	case "compression":
		setString(&ds.Compression, val)
	case "mountpoint":
		setString(&ds.Mountpoint, val)
	case "quota":
		err = setUint(&ds.Quota, val)
	case "type":
		setString(&ds.Type, val)
	case "origin":
		setString(&ds.Origin, val)
	case "used":
		err = setUint(&ds.Used, val)
	case "volsize":
		err = setUint(&ds.Volsize, val)
	case "written":
		err = setUint(&ds.Written, val)
	case "logicalused":
		err = setUint(&ds.Logicalused, val)
	}
	return err
}

/*
 * from zfs diff`s escape function:
 *
 * Prints a file name out a character at a time.  If the character is
 * not in the range of what we consider "printable" ASCII, display it
 * as an escaped 3-digit octal value.  ASCII values less than a space
 * are all control characters and we declare the upper end as the
 * DELete character.  This also is the last 7-bit ASCII character.
 * We choose to treat all 8-bit ASCII as not printable for this
 * application.
 */
func unescapeFilepath(path string) (string, error) {
	buf := make([]byte, 0, len(path))
	llen := len(path)
	for i := 0; i < llen; {
		if path[i] == '\\' {
			if llen < i+4 {
				return "", fmt.Errorf("Invalid octal code: too short")
			}
			octalCode := path[(i + 1):(i + 4)]
			val, err := strconv.ParseUint(octalCode, 8, 8)
			if err != nil {
				return "", fmt.Errorf("Invalid octal code: %v", err)
			}
			buf = append(buf, byte(val))
			i += 4
		} else {
			buf = append(buf, path[i])
			i++
		}
	}
	return string(buf), nil
}

var changeTypeMap = map[string]ChangeType{
	"-": Removed,
	"+": Created,
	"M": Modified,
	"R": Renamed,
}
var inodeTypeMap = map[string]InodeType{
	"B": BlockDevice,
	"C": CharacterDevice,
	"/": Directory,
	">": Door,
	"|": NamedPipe,
	"@": SymbolicLink,
	"P": EventPort,
	"=": Socket,
	"F": File,
}

// matches (+1) or (-1)
var referenceCountRegex = regexp.MustCompile(`\(([+-]\d+?)\)`)

func parseReferenceCount(field string) (int, error) {
	matches := referenceCountRegex.FindStringSubmatch(field)
	if matches == nil {
		return 0, fmt.Errorf("Regexp does not match")
	}
	return strconv.Atoi(matches[1])
}

func parseInodeChange(line []string) (*InodeChange, error) {
	llen := len(line)
	if llen < 1 {
		return nil, fmt.Errorf("Empty line passed")
	}

	changeType := changeTypeMap[line[0]]
	if changeType == 0 {
		return nil, fmt.Errorf("Unknown change type '%s'", line[0])
	}

	switch changeType {
	case Renamed:
		if llen != 4 {
			return nil, fmt.Errorf("Mismatching number of fields: expect 4, got: %d", llen)
		}
	case Modified:
		if llen != 4 && llen != 3 {
			return nil, fmt.Errorf("Mismatching number of fields: expect 3..4, got: %d", llen)
		}
	default:
		if llen != 3 {
			return nil, fmt.Errorf("Mismatching number of fields: expect 3, got: %d", llen)
		}
	}

	inodeType := inodeTypeMap[line[1]]
	if inodeType == 0 {
		return nil, fmt.Errorf("Unknown inode type '%s'", line[1])
	}

	path, err := unescapeFilepath(line[2])
	if err != nil {
		return nil, fmt.Errorf("Failed to parse filename: %v", err)
	}

	var newPath string
	var referenceCount int
	switch changeType {
	case Renamed:
		newPath, err = unescapeFilepath(line[3])
		if err != nil {
			return nil, fmt.Errorf("Failed to parse filename: %v", err)
		}
	case Modified:
		if llen == 4 {
			referenceCount, err = parseReferenceCount(line[3])
			if err != nil {
				return nil, fmt.Errorf("Failed to parse reference count: %v", err)
			}
		}
	default:
		newPath = ""
	}

	return &InodeChange{
		Change:               changeType,
		Type:                 inodeType,
		Path:                 path,
		NewPath:              newPath,
		ReferenceCountChange: referenceCount,
	}, nil
}

// example input
//M       /       /testpool/bar/
//+       F       /testpool/bar/hello.txt
//M       /       /testpool/bar/hello.txt (+1)
//M       /       /testpool/bar/hello-hardlink
func parseInodeChanges(lines [][]string) ([]*InodeChange, error) {
	changes := make([]*InodeChange, len(lines))

	for i, line := range lines {
		c, err := parseInodeChange(line)
		if err != nil {
			return nil, fmt.Errorf("Failed to parse line %d of zfs diff: %v, got: '%s'", i, err, line)
		}
		changes[i] = c
	}
	return changes, nil
}

func listByType(t, filter string) ([]*Dataset, error) {
	args := []string{"get", "all", "-t", t, "-rHp"}
	if filter != "" {
		args = append(args, filter)
	}
	out, err := zfs(args...)
	if err != nil {
		return nil, err
	}

	var datasets []*Dataset

	name := ""
	var ds *Dataset
	for _, line := range out {
		if name != line[0] {
			name = line[0]
			ds = &Dataset{Name: name}
			datasets = append(datasets, ds)
		}
		if err := ds.parseLine(line); err != nil {
			return nil, err
		}
	}

	return datasets, nil
}

func propsSlice(properties map[string]string) []string {
	args := make([]string, 0, len(properties)*3)
	for k, v := range properties {
		args = append(args, "-o")
		args = append(args, fmt.Sprintf("%s=%s", k, v))
	}
	return args
}

func (z *Zpool) parseLine(line []string) error {
	prop := line[1]
	val := line[2]

	var err error

	switch prop {
	case "health":
		setString(&z.Health, val)
	case "allocated":
		err = setUint(&z.Allocated, val)
	case "size":
		err = setUint(&z.Size, val)
	case "free":
		err = setUint(&z.Free, val)
	}
	return err
}
<|endoftext|>


<commit_before>package gohl7

import (
    "errors"
)

var (
    errNoMatchingTypes = errors.New("No matching type")
    errNonInternalImplementation = errors.New("Provided fields do not match internal implementation")
    errNonMatchingChildren = errors.New("Different amount of childrens")
)

//function newSimpleStr is an internal utility function
//mostly for testing
func newSimpleStr(s string) *SimpleField {

    return NewSimpleField([]byte(s))
}

// function newComplexFieldWithChildren is an internal utility function
// mostly for testing
//error code is ignore on purpose as its assume the call is internal
func newComplexFieldWithChildren(t FieldType, v func(Field, Field) error, children ...Field) *ComplexField {

    complexF := NewComplexField(t,v)

    for _, child := range children {
        _ = complexF.Push(child)
    }

    return complexF
}

//function deepEqual compare two fields recursivly for equality
//a return value of nil implies equal a non nil implies difference
func deepEqual(l,r Field) (error) {

    if l.Type() != r.Type() {
        return errNoMatchingTypes
    }

    if l.Type() == Simple {
        return nil
    }

    complexL,okL := l.(*ComplexField)
    complexR,okR := r.(*ComplexField)

    if !okL || !okR {
        return errNonInternalImplementation
    }

    childrenL, childrenR := complexL.children, complexR.children
    if len(childrenL) != len(childrenR) {
        return errNonMatchingChildren
    }

    for i:=0; i < len(childrenL); i++ {
        err := deepEqual(childrenL[i],childrenR[i])
        if err != nil {
            return err
        }
    }

    return nil
}<commit_msg>Adding a more verbose error message<commit_after>package gohl7

import (
    "errors"
    "fmt"
)

var (
    errNoMatchingTypes = errors.New("No matching type")
    errNonInternalImplementation = errors.New("Provided fields do not match internal implementation")
    errNonMatchingChildren = errors.New("Different amount of childrens")
)

//function newSimpleStr is an internal utility function
//mostly for testing
func newSimpleStr(s string) *SimpleField {

    return NewSimpleField([]byte(s))
}

// function newComplexFieldWithChildren is an internal utility function
// mostly for testing
//error code is ignore on purpose as its assume the call is internal
func newComplexFieldWithChildren(t FieldType, v func(Field, Field) error, children ...Field) *ComplexField {

    complexF := NewComplexField(t,v)

    for _, child := range children {
        _ = complexF.Push(child)
    }

    return complexF
}

//function deepEqual compare two fields recursivly for equality
//a return value of nil implies equal a non nil implies difference
func deepEqual(l,r Field) (error) {

    if l.Type() != r.Type() {
        return errNoMatchingTypes
    }

    if l.Type() == Simple {
        return nil
    }

    complexL,okL := l.(*ComplexField)
    complexR,okR := r.(*ComplexField)

    if !okL || !okR {
        return errNonInternalImplementation
    }

    childrenL, childrenR := complexL.children, complexR.children
    if len(childrenL) != len(childrenR) {
        //return errNonMatchingChildren
        return fmt.Errorf("Different amount of childrens \n%s\n %s\n",l,r)
    }

    for i:=0; i < len(childrenL); i++ {
        err := deepEqual(childrenL[i],childrenR[i])
        if err != nil {
            return err
        }
    }

    return nil
}<|endoftext|>


<commit_before>package suggest

import (
	"strings"
)

func SplitIntoNGrams(word string, k int) []string {
	sliceLen := len(word) - k + 1
	if sliceLen <= 0 || sliceLen > len(word) {
		panic("Invalid word length for spliting")
	}

	result := make([]string, sliceLen)
	for i := 0; i < sliceLen; i++ {
		result[i] = word[i : i+k]
	}

	return result
}

func Levenshtein(a, b string) int {
	aLen, bLen := len(a), len(b)
	if aLen == 0 {
		return bLen
	}

	if bLen == 0 {
		return aLen
	}

	r1, r2 := []rune(a), []rune(b)
	column := make([]int, aLen+1)

	for i := 1; i < aLen+1; i++ {
		column[i] = i
	}

	for j := 1; j < bLen+1; j++ {
		column[0] = j
		prev := j - 1
		for i := 1; i < aLen+1; i++ {
			tmp := column[i]
			cost := 0
			if r1[i-1] != r2[j-1] {
				cost = 1
			}

			column[i] = min3(
				column[i]+1,
				column[i-1]+1,
				prev+cost,
			)
			prev = tmp
		}
	}

	return column[aLen]
}

func prepareString(word string) string {
	word = strings.ToLower(word)
	word = strings.Trim(word, " ")
	word = strings.Replace(word, " ", "$", -1)
	return "$" + word + "$"
}

func min3(a, b, c int) int {
	if a < b && a < c {
		return a
	}

	if b < c {
		return b
	}

	return c
}
<commit_msg>replace invalid chars with $<commit_after>package suggest

import (
	"strings"
	"regexp"
)

var reg *regexp.Regexp

func SplitIntoNGrams(word string, k int) []string {
	sliceLen := len(word) - k + 1
	if sliceLen <= 0 || sliceLen > len(word) {
		panic("Invalid word length for spliting")
	}

	result := make([]string, sliceLen)
	for i := 0; i < sliceLen; i++ {
		result[i] = word[i : i+k]
	}

	return result
}

func Levenshtein(a, b string) int {
	aLen, bLen := len(a), len(b)
	if aLen == 0 {
		return bLen
	}

	if bLen == 0 {
		return aLen
	}

	r1, r2 := []rune(a), []rune(b)
	column := make([]int, aLen+1)

	for i := 1; i < aLen+1; i++ {
		column[i] = i
	}

	for j := 1; j < bLen+1; j++ {
		column[0] = j
		prev := j - 1
		for i := 1; i < aLen+1; i++ {
			tmp := column[i]
			cost := 0
			if r1[i-1] != r2[j-1] {
				cost = 1
			}

			column[i] = min3(
				column[i]+1,
				column[i-1]+1,
				prev+cost,
			)
			prev = tmp
		}
	}

	return column[aLen]
}

func prepareString(word string) string {
	word = strings.ToLower(word)
	word = strings.Trim(word, " ")
	word = reg.ReplaceAllString(word, "$")
	return "$" + word + "$"
}

func min3(a, b, c int) int {
	if a < b && a < c {
		return a
	}

	if b < c {
		return b
	}

	return c
}

func init() {
	var err error
	reg, err = regexp.Compile("[^a-z0-9а-яё ]+")
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package rpcperms

import (
	"context"
	"fmt"
	"sync"

	"github.com/btcsuite/btclog"
	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
	"github.com/lightningnetwork/lnd/lnrpc"
	"github.com/lightningnetwork/lnd/macaroons"
	"github.com/lightningnetwork/lnd/monitoring"
	"google.golang.org/grpc"
	"gopkg.in/macaroon-bakery.v2/bakery"
)

// rpcState is an enum that we use to keep track of the current RPC service
// state. This will transition as we go from startup to unlocking the wallet,
// and finally fully active.
type rpcState uint8

const (
	// walletNotCreated is the starting state if the RPC server is active,
	// but the wallet is not yet created. In this state we'll only allow
	// calls to the WalletUnlockerService.
	walletNotCreated rpcState = iota

	// walletLocked indicates the RPC server is active, but the wallet is
	// locked. In this state we'll only allow calls to the
	// WalletUnlockerService.
	walletLocked

	// walletUnlocked means that the wallet has been unlocked, but the full
	// RPC server is not yeat ready.
	walletUnlocked

	// rpcActive means that the RPC server is ready to accept calls.
	rpcActive
)

var (
	// ErrNoWallet is returned if the wallet does not exist.
	ErrNoWallet = fmt.Errorf("wallet not created, create one to enable " +
		"full RPC access")

	// ErrWalletLocked is returned if the wallet is locked and any service
	// other than the WalletUnlocker is called.
	ErrWalletLocked = fmt.Errorf("wallet locked, unlock it to enable " +
		"full RPC access")

	// ErrWalletUnlocked is returned if the WalletUnlocker service is
	// called when the wallet already has been unlocked.
	ErrWalletUnlocked = fmt.Errorf("wallet already unlocked, " +
		"WalletUnlocker service is no longer available")

	// ErrRPCStarting is returned if the wallet has been unlocked but the
	// RPC server is not yet ready to accept calls.
	ErrRPCStarting = fmt.Errorf("the RPC server is in the process of " +
		"starting up, but not yet ready to accept calls")

	// macaroonWhitelist defines methods that we don't require macaroons to
	// access.
	macaroonWhitelist = map[string]struct{}{
		// We allow all calls to the WalletUnlocker without macaroons.
		"/lnrpc.WalletUnlocker/GenSeed":        {},
		"/lnrpc.WalletUnlocker/InitWallet":     {},
		"/lnrpc.WalletUnlocker/UnlockWallet":   {},
		"/lnrpc.WalletUnlocker/ChangePassword": {},
	}
)

// InterceptorChain is a struct that can be added to the running GRPC server,
// intercepting API calls. This is useful for logging, enforcing permissions
// etc.
type InterceptorChain struct {
	// state is the current RPC state of our RPC server.
	state rpcState

	// noMacaroons should be set true if we don't want to check macaroons.
	noMacaroons bool

	// svc is the macaroon service used to enforce permissions in case
	// macaroons are used.
	svc *macaroons.Service

	// permissionMap is the permissions to enforce if macaroons are used.
	permissionMap map[string][]bakery.Op

	// rpcsLog is the logger used to log calles to the RPCs intercepted.
	rpcsLog btclog.Logger

	sync.RWMutex
}

// NewInterceptorChain creates a new InterceptorChain.
func NewInterceptorChain(log btclog.Logger, noMacaroons,
	walletExists bool) *InterceptorChain {

	startState := walletNotCreated
	if walletExists {
		startState = walletLocked
	}

	return &InterceptorChain{
		state:         startState,
		noMacaroons:   noMacaroons,
		permissionMap: make(map[string][]bakery.Op),
		rpcsLog:       log,
	}
}

// SetWalletUnlocked moves the RPC state from either walletNotCreated or
// walletLocked to walletUnlocked.
func (r *InterceptorChain) SetWalletUnlocked() {
	r.Lock()
	defer r.Unlock()

	r.state = walletUnlocked
}

// SetRPCActive moves the RPC state from walletUnlocked to rpcActive.
func (r *InterceptorChain) SetRPCActive() {
	r.Lock()
	defer r.Unlock()

	r.state = rpcActive
}

// AddMacaroonService adds a macaroon service to the interceptor. After this is
// done every RPC call made will have to pass a valid macaroon to be accepted.
func (r *InterceptorChain) AddMacaroonService(svc *macaroons.Service) {
	r.Lock()
	defer r.Unlock()

	r.svc = svc
}

// AddPermission adds a new macaroon rule for the given method.
func (r *InterceptorChain) AddPermission(method string, ops []bakery.Op) error {
	r.Lock()
	defer r.Unlock()

	if _, ok := r.permissionMap[method]; ok {
		return fmt.Errorf("detected duplicate macaroon constraints "+
			"for path: %v", method)
	}

	r.permissionMap[method] = ops
	return nil
}

// Permissions returns the current set of macaroon permissions.
func (r *InterceptorChain) Permissions() map[string][]bakery.Op {
	r.RLock()
	defer r.RUnlock()

	// Make a copy under the read lock to avoid races.
	c := make(map[string][]bakery.Op)
	for k, v := range r.permissionMap {
		s := make([]bakery.Op, len(v))
		copy(s, v)
		c[k] = s
	}

	return c
}

// CreateServerOpts creates the GRPC server options that can be added to a GRPC
// server in order to add this InterceptorChain.
func (r *InterceptorChain) CreateServerOpts() []grpc.ServerOption {
	var unaryInterceptors []grpc.UnaryServerInterceptor
	var strmInterceptors []grpc.StreamServerInterceptor

	// The first interceptors we'll add to the chain is our logging
	// interceptors, so we can automatically log all errors that happen
	// during RPC calls.
	unaryInterceptors = append(
		unaryInterceptors, errorLogUnaryServerInterceptor(r.rpcsLog),
	)
	strmInterceptors = append(
		strmInterceptors, errorLogStreamServerInterceptor(r.rpcsLog),
	)

	// Next we'll add our RPC state check interceptors, that will check
	// whether the attempted call is allowed in the current state.
	unaryInterceptors = append(
		unaryInterceptors, r.rpcStateUnaryServerInterceptor(),
	)
	strmInterceptors = append(
		strmInterceptors, r.rpcStateStreamServerInterceptor(),
	)

	// We'll add the macaroon interceptors. If macaroons aren't disabled,
	// then these interceptors will enforce macaroon authentication.
	unaryInterceptors = append(
		unaryInterceptors, r.macaroonUnaryServerInterceptor(),
	)
	strmInterceptors = append(
		strmInterceptors, r.macaroonStreamServerInterceptor(),
	)

	// Get interceptors for Prometheus to gather gRPC performance metrics.
	// If monitoring is disabled, GetPromInterceptors() will return empty
	// slices.
	promUnaryInterceptors, promStrmInterceptors :=
		monitoring.GetPromInterceptors()

	// Concatenate the slices of unary and stream interceptors respectively.
	unaryInterceptors = append(unaryInterceptors, promUnaryInterceptors...)
	strmInterceptors = append(strmInterceptors, promStrmInterceptors...)

	// Create server options from the interceptors we just set up.
	chainedUnary := grpc_middleware.WithUnaryServerChain(
		unaryInterceptors...,
	)
	chainedStream := grpc_middleware.WithStreamServerChain(
		strmInterceptors...,
	)
	serverOpts := []grpc.ServerOption{chainedUnary, chainedStream}

	return serverOpts
}

// errorLogUnaryServerInterceptor is a simple UnaryServerInterceptor that will
// automatically log any errors that occur when serving a client's unary
// request.
func errorLogUnaryServerInterceptor(logger btclog.Logger) grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler) (interface{}, error) {

		resp, err := handler(ctx, req)
		if err != nil {
			// TODO(roasbeef): also log request details?
			logger.Errorf("[%v]: %v", info.FullMethod, err)
		}

		return resp, err
	}
}

// errorLogStreamServerInterceptor is a simple StreamServerInterceptor that
// will log any errors that occur while processing a client or server streaming
// RPC.
func errorLogStreamServerInterceptor(logger btclog.Logger) grpc.StreamServerInterceptor {
	return func(srv interface{}, ss grpc.ServerStream,
		info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {

		err := handler(srv, ss)
		if err != nil {
			logger.Errorf("[%v]: %v", info.FullMethod, err)
		}

		return err
	}
}

// checkMacaroon validates that the context contains the macaroon needed to
// invoke the given RPC method.
func (r *InterceptorChain) checkMacaroon(ctx context.Context,
	fullMethod string) error {

	// If noMacaroons is set, we'll always allow the call.
	if r.noMacaroons {
		return nil
	}

	// Check whether the method is whitelisted, if so we'll allow it
	// regardless of macaroons.
	_, ok := macaroonWhitelist[fullMethod]
	if ok {
		return nil
	}

	r.RLock()
	svc := r.svc
	r.RUnlock()

	// If the macaroon service is not yet active, we cannot allow
	// the call.
	if svc == nil {
		return fmt.Errorf("unable to determine macaroon permissions")
	}

	r.RLock()
	uriPermissions, ok := r.permissionMap[fullMethod]
	r.RUnlock()
	if !ok {
		return fmt.Errorf("%s: unknown permissions required for method",
			fullMethod)
	}

	// Find out if there is an external validator registered for
	// this method. Fall back to the internal one if there isn't.
	validator, ok := svc.ExternalValidators[fullMethod]
	if !ok {
		validator = svc
	}

	// Now that we know what validator to use, let it do its work.
	return validator.ValidateMacaroon(ctx, uriPermissions, fullMethod)
}

// macaroonUnaryServerInterceptor is a GRPC interceptor that checks whether the
// request is authorized by the included macaroons.
func (r *InterceptorChain) macaroonUnaryServerInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{},
		info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler) (interface{}, error) {

		// Check macaroons.
		if err := r.checkMacaroon(ctx, info.FullMethod); err != nil {
			return nil, err
		}

		return handler(ctx, req)
	}
}

// macaroonStreamServerInterceptor is a GRPC interceptor that checks whether
// the request is authorized by the included macaroons.
func (r *InterceptorChain) macaroonStreamServerInterceptor() grpc.StreamServerInterceptor {
	return func(srv interface{}, ss grpc.ServerStream,
		info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {

		// Check macaroons.
		err := r.checkMacaroon(ss.Context(), info.FullMethod)
		if err != nil {
			return err
		}

		return handler(srv, ss)
	}
}

// checkRPCState checks whether a call to the given server is allowed in the
// current RPC state.
func (r *InterceptorChain) checkRPCState(srv interface{}) error {
	r.RLock()
	state := r.state
	r.RUnlock()

	switch state {

	// If the wallet does not exists, only calls to the WalletUnlocker are
	// accepted.
	case walletNotCreated:
		_, ok := srv.(lnrpc.WalletUnlockerServer)
		if !ok {
			return ErrNoWallet
		}

	// If the wallet is locked, only calls to the WalletUnlocker are
	// accepted.
	case walletLocked:
		_, ok := srv.(lnrpc.WalletUnlockerServer)
		if !ok {
			return ErrWalletLocked
		}

	// If the wallet is unlocked, but the RPC not yet active, we reject.
	case walletUnlocked:
		_, ok := srv.(lnrpc.WalletUnlockerServer)
		if ok {
			return ErrWalletUnlocked
		}

		return ErrRPCStarting

	// If the RPC is active, we allow calls to any service except the
	// WalletUnlocker.
	case rpcActive:
		_, ok := srv.(lnrpc.WalletUnlockerServer)
		if ok {
			return ErrWalletUnlocked
		}

	default:
		return fmt.Errorf("unknown RPC state: %v", state)
	}

	return nil
}

// rpcStateUnaryServerInterceptor is a GRPC interceptor that checks whether
// calls to the given gGRPC server is allowed in the current rpc state.
func (r *InterceptorChain) rpcStateUnaryServerInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler) (interface{}, error) {

		if err := r.checkRPCState(info.Server); err != nil {
			return nil, err
		}

		return handler(ctx, req)
	}
}

// rpcStateStreamServerInterceptor is a GRPC interceptor that checks whether
// calls to the given gGRPC server is allowed in the current rpc state.
func (r *InterceptorChain) rpcStateStreamServerInterceptor() grpc.StreamServerInterceptor {
	return func(srv interface{}, ss grpc.ServerStream,
		info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {

		if err := r.checkRPCState(srv); err != nil {
			return err
		}

		return handler(srv, ss)
	}
}
<commit_msg>rpcperms: export macaroon interceptor methods<commit_after>package rpcperms

import (
	"context"
	"fmt"
	"sync"

	"github.com/btcsuite/btclog"
	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
	"github.com/lightningnetwork/lnd/lnrpc"
	"github.com/lightningnetwork/lnd/macaroons"
	"github.com/lightningnetwork/lnd/monitoring"
	"google.golang.org/grpc"
	"gopkg.in/macaroon-bakery.v2/bakery"
)

// rpcState is an enum that we use to keep track of the current RPC service
// state. This will transition as we go from startup to unlocking the wallet,
// and finally fully active.
type rpcState uint8

const (
	// walletNotCreated is the starting state if the RPC server is active,
	// but the wallet is not yet created. In this state we'll only allow
	// calls to the WalletUnlockerService.
	walletNotCreated rpcState = iota

	// walletLocked indicates the RPC server is active, but the wallet is
	// locked. In this state we'll only allow calls to the
	// WalletUnlockerService.
	walletLocked

	// walletUnlocked means that the wallet has been unlocked, but the full
	// RPC server is not yeat ready.
	walletUnlocked

	// rpcActive means that the RPC server is ready to accept calls.
	rpcActive
)

var (
	// ErrNoWallet is returned if the wallet does not exist.
	ErrNoWallet = fmt.Errorf("wallet not created, create one to enable " +
		"full RPC access")

	// ErrWalletLocked is returned if the wallet is locked and any service
	// other than the WalletUnlocker is called.
	ErrWalletLocked = fmt.Errorf("wallet locked, unlock it to enable " +
		"full RPC access")

	// ErrWalletUnlocked is returned if the WalletUnlocker service is
	// called when the wallet already has been unlocked.
	ErrWalletUnlocked = fmt.Errorf("wallet already unlocked, " +
		"WalletUnlocker service is no longer available")

	// ErrRPCStarting is returned if the wallet has been unlocked but the
	// RPC server is not yet ready to accept calls.
	ErrRPCStarting = fmt.Errorf("the RPC server is in the process of " +
		"starting up, but not yet ready to accept calls")

	// macaroonWhitelist defines methods that we don't require macaroons to
	// access.
	macaroonWhitelist = map[string]struct{}{
		// We allow all calls to the WalletUnlocker without macaroons.
		"/lnrpc.WalletUnlocker/GenSeed":        {},
		"/lnrpc.WalletUnlocker/InitWallet":     {},
		"/lnrpc.WalletUnlocker/UnlockWallet":   {},
		"/lnrpc.WalletUnlocker/ChangePassword": {},
	}
)

// InterceptorChain is a struct that can be added to the running GRPC server,
// intercepting API calls. This is useful for logging, enforcing permissions
// etc.
type InterceptorChain struct {
	// state is the current RPC state of our RPC server.
	state rpcState

	// noMacaroons should be set true if we don't want to check macaroons.
	noMacaroons bool

	// svc is the macaroon service used to enforce permissions in case
	// macaroons are used.
	svc *macaroons.Service

	// permissionMap is the permissions to enforce if macaroons are used.
	permissionMap map[string][]bakery.Op

	// rpcsLog is the logger used to log calles to the RPCs intercepted.
	rpcsLog btclog.Logger

	sync.RWMutex
}

// NewInterceptorChain creates a new InterceptorChain.
func NewInterceptorChain(log btclog.Logger, noMacaroons,
	walletExists bool) *InterceptorChain {

	startState := walletNotCreated
	if walletExists {
		startState = walletLocked
	}

	return &InterceptorChain{
		state:         startState,
		noMacaroons:   noMacaroons,
		permissionMap: make(map[string][]bakery.Op),
		rpcsLog:       log,
	}
}

// SetWalletUnlocked moves the RPC state from either walletNotCreated or
// walletLocked to walletUnlocked.
func (r *InterceptorChain) SetWalletUnlocked() {
	r.Lock()
	defer r.Unlock()

	r.state = walletUnlocked
}

// SetRPCActive moves the RPC state from walletUnlocked to rpcActive.
func (r *InterceptorChain) SetRPCActive() {
	r.Lock()
	defer r.Unlock()

	r.state = rpcActive
}

// AddMacaroonService adds a macaroon service to the interceptor. After this is
// done every RPC call made will have to pass a valid macaroon to be accepted.
func (r *InterceptorChain) AddMacaroonService(svc *macaroons.Service) {
	r.Lock()
	defer r.Unlock()

	r.svc = svc
}

// AddPermission adds a new macaroon rule for the given method.
func (r *InterceptorChain) AddPermission(method string, ops []bakery.Op) error {
	r.Lock()
	defer r.Unlock()

	if _, ok := r.permissionMap[method]; ok {
		return fmt.Errorf("detected duplicate macaroon constraints "+
			"for path: %v", method)
	}

	r.permissionMap[method] = ops
	return nil
}

// Permissions returns the current set of macaroon permissions.
func (r *InterceptorChain) Permissions() map[string][]bakery.Op {
	r.RLock()
	defer r.RUnlock()

	// Make a copy under the read lock to avoid races.
	c := make(map[string][]bakery.Op)
	for k, v := range r.permissionMap {
		s := make([]bakery.Op, len(v))
		copy(s, v)
		c[k] = s
	}

	return c
}

// CreateServerOpts creates the GRPC server options that can be added to a GRPC
// server in order to add this InterceptorChain.
func (r *InterceptorChain) CreateServerOpts() []grpc.ServerOption {
	var unaryInterceptors []grpc.UnaryServerInterceptor
	var strmInterceptors []grpc.StreamServerInterceptor

	// The first interceptors we'll add to the chain is our logging
	// interceptors, so we can automatically log all errors that happen
	// during RPC calls.
	unaryInterceptors = append(
		unaryInterceptors, errorLogUnaryServerInterceptor(r.rpcsLog),
	)
	strmInterceptors = append(
		strmInterceptors, errorLogStreamServerInterceptor(r.rpcsLog),
	)

	// Next we'll add our RPC state check interceptors, that will check
	// whether the attempted call is allowed in the current state.
	unaryInterceptors = append(
		unaryInterceptors, r.rpcStateUnaryServerInterceptor(),
	)
	strmInterceptors = append(
		strmInterceptors, r.rpcStateStreamServerInterceptor(),
	)

	// We'll add the macaroon interceptors. If macaroons aren't disabled,
	// then these interceptors will enforce macaroon authentication.
	unaryInterceptors = append(
		unaryInterceptors, r.MacaroonUnaryServerInterceptor(),
	)
	strmInterceptors = append(
		strmInterceptors, r.MacaroonStreamServerInterceptor(),
	)

	// Get interceptors for Prometheus to gather gRPC performance metrics.
	// If monitoring is disabled, GetPromInterceptors() will return empty
	// slices.
	promUnaryInterceptors, promStrmInterceptors :=
		monitoring.GetPromInterceptors()

	// Concatenate the slices of unary and stream interceptors respectively.
	unaryInterceptors = append(unaryInterceptors, promUnaryInterceptors...)
	strmInterceptors = append(strmInterceptors, promStrmInterceptors...)

	// Create server options from the interceptors we just set up.
	chainedUnary := grpc_middleware.WithUnaryServerChain(
		unaryInterceptors...,
	)
	chainedStream := grpc_middleware.WithStreamServerChain(
		strmInterceptors...,
	)
	serverOpts := []grpc.ServerOption{chainedUnary, chainedStream}

	return serverOpts
}

// errorLogUnaryServerInterceptor is a simple UnaryServerInterceptor that will
// automatically log any errors that occur when serving a client's unary
// request.
func errorLogUnaryServerInterceptor(logger btclog.Logger) grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler) (interface{}, error) {

		resp, err := handler(ctx, req)
		if err != nil {
			// TODO(roasbeef): also log request details?
			logger.Errorf("[%v]: %v", info.FullMethod, err)
		}

		return resp, err
	}
}

// errorLogStreamServerInterceptor is a simple StreamServerInterceptor that
// will log any errors that occur while processing a client or server streaming
// RPC.
func errorLogStreamServerInterceptor(logger btclog.Logger) grpc.StreamServerInterceptor {
	return func(srv interface{}, ss grpc.ServerStream,
		info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {

		err := handler(srv, ss)
		if err != nil {
			logger.Errorf("[%v]: %v", info.FullMethod, err)
		}

		return err
	}
}

// checkMacaroon validates that the context contains the macaroon needed to
// invoke the given RPC method.
func (r *InterceptorChain) checkMacaroon(ctx context.Context,
	fullMethod string) error {

	// If noMacaroons is set, we'll always allow the call.
	if r.noMacaroons {
		return nil
	}

	// Check whether the method is whitelisted, if so we'll allow it
	// regardless of macaroons.
	_, ok := macaroonWhitelist[fullMethod]
	if ok {
		return nil
	}

	r.RLock()
	svc := r.svc
	r.RUnlock()

	// If the macaroon service is not yet active, we cannot allow
	// the call.
	if svc == nil {
		return fmt.Errorf("unable to determine macaroon permissions")
	}

	r.RLock()
	uriPermissions, ok := r.permissionMap[fullMethod]
	r.RUnlock()
	if !ok {
		return fmt.Errorf("%s: unknown permissions required for method",
			fullMethod)
	}

	// Find out if there is an external validator registered for
	// this method. Fall back to the internal one if there isn't.
	validator, ok := svc.ExternalValidators[fullMethod]
	if !ok {
		validator = svc
	}

	// Now that we know what validator to use, let it do its work.
	return validator.ValidateMacaroon(ctx, uriPermissions, fullMethod)
}

// MacaroonUnaryServerInterceptor is a GRPC interceptor that checks whether the
// request is authorized by the included macaroons.
func (r *InterceptorChain) MacaroonUnaryServerInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{},
		info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler) (interface{}, error) {

		// Check macaroons.
		if err := r.checkMacaroon(ctx, info.FullMethod); err != nil {
			return nil, err
		}

		return handler(ctx, req)
	}
}

// MacaroonStreamServerInterceptor is a GRPC interceptor that checks whether
// the request is authorized by the included macaroons.
func (r *InterceptorChain) MacaroonStreamServerInterceptor() grpc.StreamServerInterceptor {
	return func(srv interface{}, ss grpc.ServerStream,
		info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {

		// Check macaroons.
		err := r.checkMacaroon(ss.Context(), info.FullMethod)
		if err != nil {
			return err
		}

		return handler(srv, ss)
	}
}

// checkRPCState checks whether a call to the given server is allowed in the
// current RPC state.
func (r *InterceptorChain) checkRPCState(srv interface{}) error {
	r.RLock()
	state := r.state
	r.RUnlock()

	switch state {

	// If the wallet does not exists, only calls to the WalletUnlocker are
	// accepted.
	case walletNotCreated:
		_, ok := srv.(lnrpc.WalletUnlockerServer)
		if !ok {
			return ErrNoWallet
		}

	// If the wallet is locked, only calls to the WalletUnlocker are
	// accepted.
	case walletLocked:
		_, ok := srv.(lnrpc.WalletUnlockerServer)
		if !ok {
			return ErrWalletLocked
		}

	// If the wallet is unlocked, but the RPC not yet active, we reject.
	case walletUnlocked:
		_, ok := srv.(lnrpc.WalletUnlockerServer)
		if ok {
			return ErrWalletUnlocked
		}

		return ErrRPCStarting

	// If the RPC is active, we allow calls to any service except the
	// WalletUnlocker.
	case rpcActive:
		_, ok := srv.(lnrpc.WalletUnlockerServer)
		if ok {
			return ErrWalletUnlocked
		}

	default:
		return fmt.Errorf("unknown RPC state: %v", state)
	}

	return nil
}

// rpcStateUnaryServerInterceptor is a GRPC interceptor that checks whether
// calls to the given gGRPC server is allowed in the current rpc state.
func (r *InterceptorChain) rpcStateUnaryServerInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler) (interface{}, error) {

		if err := r.checkRPCState(info.Server); err != nil {
			return nil, err
		}

		return handler(ctx, req)
	}
}

// rpcStateStreamServerInterceptor is a GRPC interceptor that checks whether
// calls to the given gGRPC server is allowed in the current rpc state.
func (r *InterceptorChain) rpcStateStreamServerInterceptor() grpc.StreamServerInterceptor {
	return func(srv interface{}, ss grpc.ServerStream,
		info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {

		if err := r.checkRPCState(srv); err != nil {
			return err
		}

		return handler(srv, ss)
	}
}
<|endoftext|>


<commit_before>/*
This file implements the uWSGI protocol.
This implements run as net.Listener:

		l, err = net.Listen("unix", "/path/to/socket")
		http.Serve(&UwsgiListener{l}, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			w.Header().Set("Content-Length", 11)
			w.Write([]byte("hello world"))
		})
*/

package uwsgi

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"strconv"
	"time"
)

type Listener struct {
	Listener net.Listener
}

type Conn struct {
	env    map[string]string
	reader io.Reader
	writer net.Conn
}

func (c *Conn) Read(b []byte) (int, error) {
	n, e := c.reader.Read(b)
	return n, e
}

func (c *Conn) Write(b []byte) (int, error) {
	return c.writer.Write(b)
}

func (c *Conn) Close() error {
	return c.writer.Close()
}

func (c *Conn) LocalAddr() net.Addr {
	return c.writer.LocalAddr()
}

func (c *Conn) RemoteAddr() net.Addr {
	return c.writer.RemoteAddr()
}

func (c *Conn) SetDeadline(t time.Time) error {
	return c.writer.SetDeadline(t)
}

func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.writer.SetReadDeadline(t)
}

func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.writer.SetWriteDeadline(t)
}

/*
func (c *Conn) SetTimeout(s int64) error {
	return c.writer.SetTimeout(s)
}
*/

/*
func (c *Conn) SetReadTimeout(s int64) error {
	return c.writer.SetReadTimeout(s)
}
*/

/*
func (c *Conn) SetWriteTimeout(s int64) error {
	return c.writer.SetWriteTimeout(s)
}
*/

func (l *Listener) Addr() net.Addr {
	return l.Listener.Addr()
}

func (l *Listener) Close() error {
	return l.Listener.Close()
}

// Accept conduct as net.Listener. uWSGI protocol is working good for CGI.
// This function parse headers and pass to the Server.
func (l *Listener) Accept() (net.Conn, error) {
	fd, err := l.Listener.Accept()
	if err != nil {
		return nil, err
	}

	buf := new(bytes.Buffer)
	c := &Conn{map[string]string{}, buf, fd}

	var head [4]byte
	fd.Read(head[:])
	//mod1 := head[0:0]
	b := []byte{head[1], head[2]}
	envsize := binary.LittleEndian.Uint16(b)
	//mod2 := head[3:3]

	envbuf := make([]byte, envsize)
	if _, err := io.ReadFull(fd, envbuf); err != nil {
		return nil, err
	}

	i := uint16(0)
	for {
		b := []byte{envbuf[i], envbuf[i+1]}
		kl := binary.LittleEndian.Uint16(b)
		i += 2
		k := string(envbuf[i : i+kl])
		i += kl
		b = []byte{envbuf[i], envbuf[i+1]}
		vl := binary.LittleEndian.Uint16(b)
		i += 2
		v := string(envbuf[i : i+vl])
		i += vl

		c.env[k] = v
		if i >= envsize {
			break
		}
	}

	//fmt.Fprintf(buf, "%s %s %s\r\n", c.env["REQUEST_METHOD"], c.env["REQUEST_URI"], c.env["SERVER_PROTOCOL"])
	fmt.Fprintf(buf, "%s %s %s\r\n", c.env["REQUEST_METHOD"], c.env["REQUEST_URI"], "HTTP/1.0")

	cl, _ := strconv.ParseInt(c.env["CONTENT_LENGTH"], 10, 64)
	if cl > 0 {
		fmt.Fprintf(buf, "Content-Length: %d\r\n", cl)
	}

	if v := c.env["HTTP_CONTENT_TYPE"]; len(v) > 0 {
		fmt.Fprintf(buf, "Content-Type: %s\r\n", v)
	}

	if v := c.env["HTTP_HOST"]; len(v) > 0 {
		fmt.Fprintf(buf, "Host: %s\r\n", v)
	}

	if v := c.env["HTTP_CONNECTION"]; len(v) > 0 {
		fmt.Fprintf(buf, "Connection: %s\r\n", v)
	}

	if v := c.env["HTTP_ACCEPT"]; len(v) > 0 {
		fmt.Fprintf(buf, "Accept: %s\r\n", v)
	}

	if v := c.env["HTTP_USER_AGENT"]; len(v) > 0 {
		fmt.Fprintf(buf, "User-Agent: %s\r\n", v)
	}

	if v := c.env["HTTP_ACCEPT_ENCODING"]; len(v) > 0 {
		fmt.Fprintf(buf, "Accept-Encoding: %s\r\n", v)
	}

	if v := c.env["HTTP_ACCEPT_LANGUAGE"]; len(v) > 0 {
		fmt.Fprintf(buf, "Accept-Language: %s\r\n", v)
	}

	if v := c.env["HTTP_ACCEPT_CHARSET"]; len(v) > 0 {
		fmt.Fprintf(buf, "Accept-Charset: %s\r\n", v)
	}

	if v, e := c.env["SCRIPT_NAME"]; e {
		fmt.Fprintf(buf, "SCRIPT_NAME: %s\r\n", v)
	}

	if v, e := c.env["PATH_INFO"]; e {
		fmt.Fprintf(buf, "PATH_INFO: %s\r\n", v)
	}

	buf.Write([]byte("\r\n"))

	if cl > 0 {
		io.CopyN(buf, fd, cl)
	}

	return c, nil
}
<commit_msg>add Passenger.<commit_after>/*
This file implements the uWSGI protocol.
This implements run as net.Listener:

		l, err = net.Listen("unix", "/path/to/socket")
		http.Serve(&UwsgiListener{l}, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			w.Header().Set("Content-Length", 11)
			w.Write([]byte("hello world"))
		})
*/

package uwsgi

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"net/http"
	"strconv"
	"strings"
	"regexp"
	"time"
)

type Listener struct {
	Listener net.Listener
}

type Conn struct {
	env    map[string]string
	reader io.Reader
	writer net.Conn
}

func (c *Conn) Read(b []byte) (int, error) {
	n, e := c.reader.Read(b)
	return n, e
}

func (c *Conn) Write(b []byte) (int, error) {
	return c.writer.Write(b)
}

func (c *Conn) Close() error {
	return c.writer.Close()
}

func (c *Conn) LocalAddr() net.Addr {
	return c.writer.LocalAddr()
}

func (c *Conn) RemoteAddr() net.Addr {
	return c.writer.RemoteAddr()
}

func (c *Conn) SetDeadline(t time.Time) error {
	return c.writer.SetDeadline(t)
}

func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.writer.SetReadDeadline(t)
}

func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.writer.SetWriteDeadline(t)
}

/*
func (c *Conn) SetTimeout(s int64) error {
	return c.writer.SetTimeout(s)
}
*/

/*
func (c *Conn) SetReadTimeout(s int64) error {
	return c.writer.SetReadTimeout(s)
}
*/

/*
func (c *Conn) SetWriteTimeout(s int64) error {
	return c.writer.SetWriteTimeout(s)
}
*/

func (l *Listener) Addr() net.Addr {
	return l.Listener.Addr()
}

func (l *Listener) Close() error {
	return l.Listener.Close()
}

// Accept conduct as net.Listener. uWSGI protocol is working good for CGI.
// This function parse headers and pass to the Server.
func (l *Listener) Accept() (net.Conn, error) {
	fd, err := l.Listener.Accept()
	if err != nil {
		return nil, err
	}

	buf := new(bytes.Buffer)
	c := &Conn{map[string]string{}, buf, fd}

	var head [4]byte
	fd.Read(head[:])
	//mod1 := head[0:0]
	b := []byte{head[1], head[2]}
	envsize := binary.LittleEndian.Uint16(b)
	//mod2 := head[3:3]

	envbuf := make([]byte, envsize)
	if _, err := io.ReadFull(fd, envbuf); err != nil {
		return nil, err
	}

	i := uint16(0)
	for {
		b := []byte{envbuf[i], envbuf[i+1]}
		kl := binary.LittleEndian.Uint16(b)
		i += 2
		k := string(envbuf[i : i+kl])
		i += kl
		b = []byte{envbuf[i], envbuf[i+1]}
		vl := binary.LittleEndian.Uint16(b)
		i += 2
		v := string(envbuf[i : i+vl])
		i += vl

		c.env[k] = v
		if i >= envsize {
			break
		}
	}

	//fmt.Fprintf(buf, "%s %s %s\r\n", c.env["REQUEST_METHOD"], c.env["REQUEST_URI"], c.env["SERVER_PROTOCOL"])
	fmt.Fprintf(buf, "%s %s %s\r\n", c.env["REQUEST_METHOD"], c.env["REQUEST_URI"], "HTTP/1.0")

	cl, _ := strconv.ParseInt(c.env["CONTENT_LENGTH"], 10, 64)
	if cl > 0 {
		fmt.Fprintf(buf, "Content-Length: %d\r\n", cl)
	}

	if v := c.env["HTTP_CONTENT_TYPE"]; len(v) > 0 {
		fmt.Fprintf(buf, "Content-Type: %s\r\n", v)
	}

	if v := c.env["HTTP_HOST"]; len(v) > 0 {
		fmt.Fprintf(buf, "Host: %s\r\n", v)
	}

	if v := c.env["HTTP_CONNECTION"]; len(v) > 0 {
		fmt.Fprintf(buf, "Connection: %s\r\n", v)
	}

	if v := c.env["HTTP_ACCEPT"]; len(v) > 0 {
		fmt.Fprintf(buf, "Accept: %s\r\n", v)
	}

	if v := c.env["HTTP_USER_AGENT"]; len(v) > 0 {
		fmt.Fprintf(buf, "User-Agent: %s\r\n", v)
	}

	if v := c.env["HTTP_ACCEPT_ENCODING"]; len(v) > 0 {
		fmt.Fprintf(buf, "Accept-Encoding: %s\r\n", v)
	}

	if v := c.env["HTTP_ACCEPT_LANGUAGE"]; len(v) > 0 {
		fmt.Fprintf(buf, "Accept-Language: %s\r\n", v)
	}

	if v := c.env["HTTP_ACCEPT_CHARSET"]; len(v) > 0 {
		fmt.Fprintf(buf, "Accept-Charset: %s\r\n", v)
	}

	if v, e := c.env["SCRIPT_NAME"]; e {
		fmt.Fprintf(buf, "SCRIPT_NAME: %s\r\n", v)
	}

	if v, e := c.env["PATH_INFO"]; e {
		fmt.Fprintf(buf, "PATH_INFO: %s\r\n", v)
	}

	buf.Write([]byte("\r\n"))

	if cl > 0 {
		io.CopyN(buf, fd, cl)
	}

	return c, nil
}

type Passenger struct {
	Net string
	Addr string
}

var trailingPort = regexp.MustCompile(`:([0-9]+)$`)
func (p Passenger) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	conn, err := net.Dial(p.Net, p.Addr)
	if err != nil {
		panic(err.Error())
	}
	defer conn.Close()

	port := "80"
	if matches := trailingPort.FindStringSubmatch(req.Host); len(matches) != 0 {
		port = matches[1]
	}

	header := make(map[string][]string)
	header["REQUEST_METHOD"] = []string{req.Method}
	header["REQUEST_URI"] = []string{req.RequestURI}
	header["CONTENT_LENGTH"] = []string{strconv.Itoa(int(req.ContentLength))}
	header["SERVER_PROTOCOL"] = []string{req.Proto}
	header["SERVER_NAME"] = []string{req.Host}
	header["SERVER_ADDR"] = []string{req.RemoteAddr}
	header["SERVER_PORT"] = []string{port}
	header["REMOTE_HOST"] = []string{req.RemoteAddr}
	header["REMOTE_ADDR"] = []string{req.RemoteAddr}
	header["SCRIPT_NAME"] = []string{req.URL.Path}
	header["PATH_INFO"] = []string{req.URL.Path}
	header["QUERY_STRING"] = []string{req.URL.RawQuery}
	if ctype := req.Header.Get("Content-Type"); ctype != "" {
		header["CONTENT_TYPE"] = []string{ctype}
	}
	for k, v := range req.Header {
		if _, ok := header[k]; ok == false {
			k = "HTTP_" + strings.ToUpper(strings.Replace(k, "-", "_", -1))
			header[k] = v
		}
	}

	var size uint16
	for k, v := range header {
		for _, vv := range v {
			size += uint16(len(([]byte)(k))) + 2
			size += uint16(len(([]byte)(vv))) + 2
		}
	}

	hsize := make([]byte, 4)
	binary.LittleEndian.PutUint16(hsize[1:3], size)
	conn.Write(hsize)

	for k, v := range header {
		for _, vv := range v {
			binary.Write(conn, binary.LittleEndian, uint16(len(([]byte)(k))))
			conn.Write([]byte(k))
			binary.Write(conn, binary.LittleEndian, uint16(len(([]byte)(vv))))
			conn.Write([]byte(vv))
		}
	}

	io.Copy(conn, req.Body)

	res, err := http.ReadResponse(bufio.NewReader(conn), req)
	if err != nil {
		panic(err.Error())
	}
	for k, v := range res.Header {
		w.Header().Del(k)
		for _, vv := range v {
			w.Header().Add(k, vv)
		}
	}
	io.Copy(w, res.Body)
}
<|endoftext|>


<commit_before>package foursquarego

type Venue struct {
	ID            string     `json:"id"`
	Name          string     `json:"name"`
	Contact       Contact    `json:"contact"`
	Location      Location   `json:"location"`
	CanonicalUrl  string     `json:"canonicalUrl"`
	Categories    []Category `json:"categories"`
	Verified      bool       `json:"verified"`
	Stats         Stats      `json:"stats"`
	Url           string     `json:"url"`
	Price         Price      `json:"price"`
	HasMenu       bool       `json:"hasMenu"`
	Likes         Likes      `json:"likes"`
	Like          bool       `json:"like"`
	Dislike       bool       `json:"dislike"`
	Ok            bool       `json:"ok"`
	Rating        float32    `json:"rating"`
	RatingColor   string     `json:"ratingColor"`
	RatingSignals int        `json:"ratingSignals"`
	Menu          Menu       `json:"menu"`
	Specials      Specials   `json:"specials"`
	Photos        Photos     `json:"photos"`
	Reasons       Reasons    `json:"reasons"`
	CreatedAt     int        `json:"createdAt"`
	Tips          Tips       `json:"tips"`
	Tags          []string   `json:"tags"`
	ShortUrl      string     `json:"shortUrl"`
	TimeZone      string     `json:"timeZone"`
	Listed        Listed     `json:"listed"`
	Phrases       []Phrase   `json:"phrases"`
	Hours         Hours      `json:"hours"`
	Popular       Popular    `json:"popular"`
	PageUpdates   Omit       `json:"-"`
	Inbox         Omit       `json:"-"`
	VenueChains   Omit       `json:"-"`
	Attributes    Attributes `json:"attributes"`
	BestPhoto     Photo      `json:"bestPhoto"`
}

type Contact struct {
	Phone          string `json:"phone"`
	FormattedPhone string `json:"formattedPhone"`
}

type Location struct {
	Address          string  `json:"address"`
	CrossStreet      string  `json:"crossStreet"`
	Lat              float64 `json:"lat"`
	Lng              float64 `json:"lng"`
	PostalCode       string  `json:"postalCode"`
	Cc               string  `json:"cc"`
	City             string  `json:"city"`
	State            string  `json:"state"`
	Country          string  `json:"country"`
	FormattedAddress string  `json:"formattedAddress"`
}

type Category struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	PluralName string `json:"pluralName"`
	ShortName  string `json:"shortName"`
	Icon       Icon   `json:"icon"`
	Primary    bool   `json:"primary"`
}

type Icon struct {
	Prefix string `json:"prefix"`
	Suffix string `json:"suffix"`
}

type Stats struct {
	CheckinsCount int `json:"checkinsCount"`
	UsersCount    int `json:"usersCount"`
	TipCount      int `json:"tipCount"`
	VisitsCount   int `json:"visitsCount"`
}

type Price struct {
	Tier     int    `json:"tier"`
	Message  string `json:"message"`
	Currency string `json:"currency"`
}

type Likes struct {
	Count   int    `json:"count"`
	Groups  Omit   `json:"-"` //TODO: take care fo this later
	Items   []User `json:"items"`
	Summary string `json:"summary"`
}

type Menu struct {
	Type      string `json:"type"`
	Label     string `json:"lablel"`
	Anchor    string `json:"anchor"`
	Url       string `json:"url"`
	MobileUrl string `json:"mobileUrl"`
}

type Specials struct {
	Count int           `json:"count"`
	Items []SpecialItem `json:"items"`
}

type SpecialItem struct {
	id                  string      `json:"id"`
	Type                string      `json:"type"`
	Message             string      `json:"message"`
	Description         string      `json:"description"`
	FinePrint           string      `json:"finePrint"`
	Unlocked            bool        `json:"unlocked"`
	Icon                string      `json:"icon"`
	Title               string      `json:"title"`
	State               string      `json:"state"`
	Provider            string      `json:"provider"`
	Redemption          string      `json:"redemption"`
	Interaction         Interaction `json:"interaction"`
	Progress            int         `json:"progress"`
	ProgressDescription string      `json:"progressDescription"`
	Detail              int         `json:"detail"`
	Target              int         `json:"target"`
	FriendsHere         []User      `json:"friendsHere"`
}

type Interaction struct {
	EntryUrl string `json:"entryUrl"`
}

type Photos struct {
	Count  int          `json:"count"`
	Groups []PhotoGroup `json:"groups"`
}

type PhotoGroup struct {
	Type  string  `json:"type"`
	Name  string  `json:"name"`
	Count int     `json:"count"`
	Items []Photo `json:"items"`
}

type Photo struct {
	ID         string      `json:"id"`
	CreatedAt  int         `json:"createdAt"`
	Source     PhotoSource `json:"source"`
	Prefix     string      `json:"prefix"`
	Suffix     string      `json:"suffix"`
	Width      int         `json:"width"`
	Height     int         `json:"height"`
	User       User        `json:"user"`
	Visibility bool        `json:"visibility"`
}

type PhotoSource struct {
	Name string `json:"name"`
	Url  string `json:"url"`
}

type User struct {
	ID           string    `json:"id"`
	FirstName    string    `json:"firstName"`
	LastName     string    `json:"lastName"`
	Gender       string    `json:"gender"`
	RelationShip string    `json:"relationship"`
	Photo        UserPhoto `json:"photo"`
}

type UserPhoto struct {
	Prefix string `json:"prefix"`
	Suffix string `json:"suffix"`
}

type HereNow struct {
	Count   int           `json:"count"`
	Summary string        `json:"summary"`
	Groups  Omit          `json:"groups,omitempty"` //TODO: take care fo this later
	Items   []HereNowItem `json:"items,omitempty"`  // I dunno sometimes it has groups or Items
}

type HereNowItem struct {
	ID             string `json:"id"`
	CreatedAt      int    `json:"createdAt"`
	Type           string `json:"type"`
	TimeZoneOffset int    `json:"timeZoneOffset"`
	User           User   `json:"user"`
	Likes          Likes  `json:"likes"`
	Like           bool   `json:"like"`
}

type Reasons struct {
	Count int      `json:"count"`
	Items []Reason `json:"items"`
}

type Reason struct {
	Summary    string `json:"summary"`
	Type       string `json:"type"`
	ReasonName string `json:"reasonName"`
}

type Tips struct {
	Count  int        `json:"count"`
	Groups []TipGroup `json:"groups"`
}

type TipGroup struct {
	Type  string `json:"type"`
	Name  string `json:"name"`
	Count int    `json:"count"`
	Items []Tip  `json:"items"`
}

type Tip struct {
	ID           string `json:"id"`
	CreatedAt    int    `json:"createdAt"`
	Text         string `json:"text"`
	Type         string `json:"type"`
	Url          string `json:"url"`
	CanonicalUrl string `json:"canonicalurl"`
	Photo        Photo  `json:"photo"`
	PhotoUrl     string `json:"photoUrl"`
	Flags        Omit   `json:"flags"` //TODO:  take care fo this later
	Likes        Likes  `json:"likes"`
	Like         bool   `json:"like"`
	LogView      bool   `json:"logView"`
	EditedAt     int    `json:"editedAt"`
	Todo         Omit   `json:"todo"` //TODO:  take care fo this later
	User         User   `json:"user"`
}

type Listed struct {
	Count  int         `json:"count"`
	Groups []ListGroup `json:"groups"`
}

type ListGroup struct {
	Type  string `json:"type"`
	Name  string `json:"name"`
	Count int    `json:"count"`
	Items []List `json:"items"`
}

type List struct {
	ID            string      `json:"id"`
	Name          string      `json:"name"`
	Description   string      `json:"description"`
	Type          string      `json:"type"`
	User          User        `json:"user"`
	Editable      bool        `json:"editable"`
	Public        bool        `json:"public"`
	Collaborative bool        `json:"collaborative"`
	Url           string      `json:"url"`
	CanonicalUrl  string      `json:"canonicalUrl"`
	CreatedAt     int         `json:"createdAt"`
	UpdatedAt     int         `json:"updatedAt"`
	Photo         Photo       `json:"photo"`
	Followers     Followers   `json:"followers"`
	ListItems     []ListItems `json:"listItems"`
}

type Followers struct {
	Count int `json:"count"`
}

type ListItems struct {
	Count int        `json:"count"`
	Items []ListItem `json:"items"`
}

type ListItem struct {
	ID        string `json:"id"`
	CreatedAt int    `json:"createdAt"`
	Tip       Tip    `json:"tip"`
	Photo     Photo  `json:"photo"`
}

type Phrase struct {
	Phrase string `json:"phrase"`
	Sample Sample `json:"sample"`
	Count  int    `json:"count"`
}

type Sample struct {
	Entities []Entitie `json:"entities"`
	Text     string    `json:"text"`
	Count    int       `json:"count"`
}

type Entitie struct {
	Indicies []int  `json:"indicies"`
	Type     string `json:"type"`
}

type Hours struct {
	Status     string      `json:"status,omitempty"`
	IsOpen     bool        `json:"isOpen,ommitempty"`
	TimeFrames []TimeFrame `json:"timeFrames,omitempty"`
	Timeframes []Timeframe `json:"timeframes,omitempty"`
}

// This is used in the main Hours struct for the entire venu
type TimeFrame struct {
	Days          string `json:"days"`
	IncludesToday bool   `json:"includesToday"`
	Open          []Open `json:"open"`
	Segments      Omit   `json:"-"` //TODO:  take care fo this later
}

// This is used for the hours endpoint
type Timeframe struct {
	Days          []int  `json:"days"`
	IncludesToday bool   `json:"includesToday"`
	Open          []Open `json:"open"`
	Segements     Omit   `json:"-"`
}

type Open struct {
	Start        string `json:"start"`
	End          string `json:"end"`
	RenderedTime string `json:"renderedTime"`
}

type Popular struct {
	Status     string      `json:"status"`
	IsOpen     bool        `json:"isOpen"`
	TimeFrames []TimeFrame `json:"timeFrames"`
}

type Attributes struct {
	Groups []Attribute `json:"groups"`
}

type Attribute struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Summary string `json:"summary"`
	Count   int    `json:"count"`
	Items   []Omit `json:"-"`
}

type Event struct {
	ID         string     `json:"id"`
	Name       string     `json:"name"`
	Categories []Category `json:"categories"`
	HereNow    HereNow    `json:"hereNow"`
	AllDay     bool       `json:"allDay"`
	Date       int        `json:"date"`
	TimeZone   string     `json:"timeZone"`
	Stats      Stats      `json:"stats"`
	Url        string     `json:"url"`
}

type Links struct {
	Count int        `json:"count"`
	Items []LinkItem `json:"items"`
}

type LinkItem struct {
	Provider Provider `json:"provider"`
	LinkedID string   `json:"linkedId"`
	Url      string   `json:"url"`
}

type Provider struct {
	ID string `json:"id"`
}
<commit_msg>add twitter to contact type<commit_after>package foursquarego

type Venue struct {
	ID            string     `json:"id"`
	Name          string     `json:"name"`
	Contact       Contact    `json:"contact"`
	Location      Location   `json:"location"`
	CanonicalUrl  string     `json:"canonicalUrl"`
	Categories    []Category `json:"categories"`
	Verified      bool       `json:"verified"`
	Stats         Stats      `json:"stats"`
	Url           string     `json:"url"`
	Price         Price      `json:"price"`
	HasMenu       bool       `json:"hasMenu"`
	Likes         Likes      `json:"likes"`
	Like          bool       `json:"like"`
	Dislike       bool       `json:"dislike"`
	Ok            bool       `json:"ok"`
	Rating        float32    `json:"rating"`
	RatingColor   string     `json:"ratingColor"`
	RatingSignals int        `json:"ratingSignals"`
	Menu          Menu       `json:"menu"`
	Specials      Specials   `json:"specials"`
	Photos        Photos     `json:"photos"`
	Reasons       Reasons    `json:"reasons"`
	CreatedAt     int        `json:"createdAt"`
	Tips          Tips       `json:"tips"`
	Tags          []string   `json:"tags"`
	ShortUrl      string     `json:"shortUrl"`
	TimeZone      string     `json:"timeZone"`
	Listed        Listed     `json:"listed"`
	Phrases       []Phrase   `json:"phrases"`
	Hours         Hours      `json:"hours"`
	Popular       Popular    `json:"popular"`
	PageUpdates   Omit       `json:"-"`
	Inbox         Omit       `json:"-"`
	VenueChains   Omit       `json:"-"`
	Attributes    Attributes `json:"attributes"`
	BestPhoto     Photo      `json:"bestPhoto"`
}

type Contact struct {
	Phone          string `json:"phone"`
	FormattedPhone string `json:"formattedPhone"`
	Twitter        string `json:"twitter"`
}

type Location struct {
	Address          string  `json:"address"`
	CrossStreet      string  `json:"crossStreet"`
	Lat              float64 `json:"lat"`
	Lng              float64 `json:"lng"`
	PostalCode       string  `json:"postalCode"`
	Cc               string  `json:"cc"`
	City             string  `json:"city"`
	State            string  `json:"state"`
	Country          string  `json:"country"`
	FormattedAddress string  `json:"formattedAddress"`
}

type Category struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	PluralName string `json:"pluralName"`
	ShortName  string `json:"shortName"`
	Icon       Icon   `json:"icon"`
	Primary    bool   `json:"primary"`
}

type Icon struct {
	Prefix string `json:"prefix"`
	Suffix string `json:"suffix"`
}

type Stats struct {
	CheckinsCount int `json:"checkinsCount"`
	UsersCount    int `json:"usersCount"`
	TipCount      int `json:"tipCount"`
	VisitsCount   int `json:"visitsCount"`
}

type Price struct {
	Tier     int    `json:"tier"`
	Message  string `json:"message"`
	Currency string `json:"currency"`
}

type Likes struct {
	Count   int    `json:"count"`
	Groups  Omit   `json:"-"` //TODO: take care fo this later
	Items   []User `json:"items"`
	Summary string `json:"summary"`
}

type Menu struct {
	Type      string `json:"type"`
	Label     string `json:"lablel"`
	Anchor    string `json:"anchor"`
	Url       string `json:"url"`
	MobileUrl string `json:"mobileUrl"`
}

type Specials struct {
	Count int           `json:"count"`
	Items []SpecialItem `json:"items"`
}

type SpecialItem struct {
	id                  string      `json:"id"`
	Type                string      `json:"type"`
	Message             string      `json:"message"`
	Description         string      `json:"description"`
	FinePrint           string      `json:"finePrint"`
	Unlocked            bool        `json:"unlocked"`
	Icon                string      `json:"icon"`
	Title               string      `json:"title"`
	State               string      `json:"state"`
	Provider            string      `json:"provider"`
	Redemption          string      `json:"redemption"`
	Interaction         Interaction `json:"interaction"`
	Progress            int         `json:"progress"`
	ProgressDescription string      `json:"progressDescription"`
	Detail              int         `json:"detail"`
	Target              int         `json:"target"`
	FriendsHere         []User      `json:"friendsHere"`
}

type Interaction struct {
	EntryUrl string `json:"entryUrl"`
}

type Photos struct {
	Count  int          `json:"count"`
	Groups []PhotoGroup `json:"groups"`
}

type PhotoGroup struct {
	Type  string  `json:"type"`
	Name  string  `json:"name"`
	Count int     `json:"count"`
	Items []Photo `json:"items"`
}

type Photo struct {
	ID         string      `json:"id"`
	CreatedAt  int         `json:"createdAt"`
	Source     PhotoSource `json:"source"`
	Prefix     string      `json:"prefix"`
	Suffix     string      `json:"suffix"`
	Width      int         `json:"width"`
	Height     int         `json:"height"`
	User       User        `json:"user"`
	Visibility bool        `json:"visibility"`
}

type PhotoSource struct {
	Name string `json:"name"`
	Url  string `json:"url"`
}

type User struct {
	ID           string    `json:"id"`
	FirstName    string    `json:"firstName"`
	LastName     string    `json:"lastName"`
	Gender       string    `json:"gender"`
	RelationShip string    `json:"relationship"`
	Photo        UserPhoto `json:"photo"`
}

type UserPhoto struct {
	Prefix string `json:"prefix"`
	Suffix string `json:"suffix"`
}

type HereNow struct {
	Count   int           `json:"count"`
	Summary string        `json:"summary"`
	Groups  Omit          `json:"groups,omitempty"` //TODO: take care fo this later
	Items   []HereNowItem `json:"items,omitempty"`  // I dunno sometimes it has groups or Items
}

type HereNowItem struct {
	ID             string `json:"id"`
	CreatedAt      int    `json:"createdAt"`
	Type           string `json:"type"`
	TimeZoneOffset int    `json:"timeZoneOffset"`
	User           User   `json:"user"`
	Likes          Likes  `json:"likes"`
	Like           bool   `json:"like"`
}

type Reasons struct {
	Count int      `json:"count"`
	Items []Reason `json:"items"`
}

type Reason struct {
	Summary    string `json:"summary"`
	Type       string `json:"type"`
	ReasonName string `json:"reasonName"`
}

type Tips struct {
	Count  int        `json:"count"`
	Groups []TipGroup `json:"groups"`
}

type TipGroup struct {
	Type  string `json:"type"`
	Name  string `json:"name"`
	Count int    `json:"count"`
	Items []Tip  `json:"items"`
}

type Tip struct {
	ID           string `json:"id"`
	CreatedAt    int    `json:"createdAt"`
	Text         string `json:"text"`
	Type         string `json:"type"`
	Url          string `json:"url"`
	CanonicalUrl string `json:"canonicalurl"`
	Photo        Photo  `json:"photo"`
	PhotoUrl     string `json:"photoUrl"`
	Flags        Omit   `json:"flags"` //TODO:  take care fo this later
	Likes        Likes  `json:"likes"`
	Like         bool   `json:"like"`
	LogView      bool   `json:"logView"`
	EditedAt     int    `json:"editedAt"`
	Todo         Omit   `json:"todo"` //TODO:  take care fo this later
	User         User   `json:"user"`
}

type Listed struct {
	Count  int         `json:"count"`
	Groups []ListGroup `json:"groups"`
}

type ListGroup struct {
	Type  string `json:"type"`
	Name  string `json:"name"`
	Count int    `json:"count"`
	Items []List `json:"items"`
}

type List struct {
	ID            string      `json:"id"`
	Name          string      `json:"name"`
	Description   string      `json:"description"`
	Type          string      `json:"type"`
	User          User        `json:"user"`
	Editable      bool        `json:"editable"`
	Public        bool        `json:"public"`
	Collaborative bool        `json:"collaborative"`
	Url           string      `json:"url"`
	CanonicalUrl  string      `json:"canonicalUrl"`
	CreatedAt     int         `json:"createdAt"`
	UpdatedAt     int         `json:"updatedAt"`
	Photo         Photo       `json:"photo"`
	Followers     Followers   `json:"followers"`
	ListItems     []ListItems `json:"listItems"`
}

type Followers struct {
	Count int `json:"count"`
}

type ListItems struct {
	Count int        `json:"count"`
	Items []ListItem `json:"items"`
}

type ListItem struct {
	ID        string `json:"id"`
	CreatedAt int    `json:"createdAt"`
	Tip       Tip    `json:"tip"`
	Photo     Photo  `json:"photo"`
}

type Phrase struct {
	Phrase string `json:"phrase"`
	Sample Sample `json:"sample"`
	Count  int    `json:"count"`
}

type Sample struct {
	Entities []Entitie `json:"entities"`
	Text     string    `json:"text"`
	Count    int       `json:"count"`
}

type Entitie struct {
	Indicies []int  `json:"indicies"`
	Type     string `json:"type"`
}

type Hours struct {
	Status     string      `json:"status,omitempty"`
	IsOpen     bool        `json:"isOpen,ommitempty"`
	TimeFrames []TimeFrame `json:"timeFrames,omitempty"`
	Timeframes []Timeframe `json:"timeframes,omitempty"`
}

// This is used in the main Hours struct for the entire venu
type TimeFrame struct {
	Days          string `json:"days"`
	IncludesToday bool   `json:"includesToday"`
	Open          []Open `json:"open"`
	Segments      Omit   `json:"-"` //TODO:  take care fo this later
}

// This is used for the hours endpoint
type Timeframe struct {
	Days          []int  `json:"days"`
	IncludesToday bool   `json:"includesToday"`
	Open          []Open `json:"open"`
	Segements     Omit   `json:"-"`
}

type Open struct {
	Start        string `json:"start"`
	End          string `json:"end"`
	RenderedTime string `json:"renderedTime"`
}

type Popular struct {
	Status     string      `json:"status"`
	IsOpen     bool        `json:"isOpen"`
	TimeFrames []TimeFrame `json:"timeFrames"`
}

type Attributes struct {
	Groups []Attribute `json:"groups"`
}

type Attribute struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Summary string `json:"summary"`
	Count   int    `json:"count"`
	Items   []Omit `json:"-"`
}

type Event struct {
	ID         string     `json:"id"`
	Name       string     `json:"name"`
	Categories []Category `json:"categories"`
	HereNow    HereNow    `json:"hereNow"`
	AllDay     bool       `json:"allDay"`
	Date       int        `json:"date"`
	TimeZone   string     `json:"timeZone"`
	Stats      Stats      `json:"stats"`
	Url        string     `json:"url"`
}

type Links struct {
	Count int        `json:"count"`
	Items []LinkItem `json:"items"`
}

type LinkItem struct {
	Provider Provider `json:"provider"`
	LinkedID string   `json:"linkedId"`
	Url      string   `json:"url"`
}

type Provider struct {
	ID string `json:"id"`
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"syscall"

	"github.com/kreuzwerker/envplate"
	"github.com/spf13/cobra"
	"github.com/yawn/doubledash"
)

var (
	build   string
	version string
)

func main() {

	var ( // flags
		backup  *bool
		dryRun  *bool
		strict  *bool
		verbose *bool
	)

	os.Args = doubledash.Args

	// commands
	root := &cobra.Command{
		Use:   "ep",
		Short: "envplate provides trivial templating for configuration files using environment keys",
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			envplate.Logger.Verbose = *verbose
		},
	}

	parse := &cobra.Command{
		Use:   "parse",
		Short: "Parse globs and exec after doubledash",
		Run: func(cmd *cobra.Command, args []string) {

			var h = envplate.Handler{
				Backup: *backup,
				DryRun: *dryRun,
				Strict: *strict,
			}

			if err := h.Apply(args); err != nil {
				os.Exit(1)
			}

			if h.DryRun {
				os.Exit(0)
			}

			if len(doubledash.Xtra) > 0 {

				if err := syscall.Exec(doubledash.Xtra[0], doubledash.Xtra, os.Environ()); err != nil {
					log.Fatalf("Cannot exec '%v': %v", doubledash.Xtra, err)
				}

			}

		},
	}

	version := &cobra.Command{
		Use:   "version",
		Short: "Print the version information of ep",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Envplate %s (%s)\n", version, build)
		},
	}

	root.AddCommand(parse)
	root.AddCommand(version)

	// flag parsing
	backup = parse.Flags().BoolP("backup", "b", false, "Create a backup file when using inline mode")
	dryRun = parse.Flags().BoolP("dry-run", "d", false, "Dry-run - output templates to stdout instead of inline replacement")
	strict = parse.Flags().BoolP("strict", "s", false, "Strict-mode - fail when falling back on defaults")
	verbose = parse.Flags().BoolP("verbose", "v", false, "Verbose logging")

	if err := root.Execute(); err != nil {
		log.Fatalf("Failed to start the application: %v", err)
	}

}
<commit_msg>Reorg of command.<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"syscall"

	"github.com/kreuzwerker/envplate"
	"github.com/spf13/cobra"
	"github.com/yawn/doubledash"
)

var (
	build   string
	version string
)

func init() {
	os.Args = doubledash.Args
}

func main() {

	var ( // flags
		backup  *bool
		dryRun  *bool
		strict  *bool
		verbose *bool
	)

	root := &cobra.Command{
		Use:   "ep",
		Short: fmt.Sprintf("envplate %s (%s) provides trivial templating for configuration files using environment keys", version, build),
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			envplate.Logger.Verbose = *verbose
		},
		Run: func(cmd *cobra.Command, args []string) {

			var h = envplate.Handler{
				Backup: *backup,
				DryRun: *dryRun,
				Strict: *strict,
			}

			if err := h.Apply(args); err != nil {
				os.Exit(1)
			}

			if h.DryRun {
				os.Exit(0)
			}

			if len(doubledash.Xtra) > 0 {

				if err := syscall.Exec(doubledash.Xtra[0], doubledash.Xtra, os.Environ()); err != nil {
					log.Fatalf("Cannot exec '%v': %v", doubledash.Xtra, err)
				}

			}

		},
	}

	// flag parsing
	backup = root.Flags().BoolP("backup", "b", false, "Create a backup file when using inline mode")
	dryRun = root.Flags().BoolP("dry-run", "d", false, "Dry-run - output templates to stdout instead of inline replacement")
	strict = root.Flags().BoolP("strict", "s", false, "Strict-mode - fail when falling back on defaults")
	verbose = root.Flags().BoolP("verbose", "v", false, "Verbose logging")

	if err := root.Execute(); err != nil {
		log.Fatalf("Failed to start the application: %v", err)
	}

}
<|endoftext|>


<commit_before>// Package binary provides a collection of binary extensions
// and a utility function to check if given path is a binary
package binary

import (
	"github.com/shamsher31/gobinext"
	"path"
	"strings"
)

var extensions = binext.Get()

// Extensions is the extensions for different binary types
var Extensions map[string]bool

func init() {
	Extensions = map[string]bool{}
	for _, ext := range extensions {
		Extensions[ext] = true
	}
}

// Is checks if a path is a binary
func Is(p string) bool {
	ext := strings.TrimLeft(path.Ext(p), ".")
	return Extensions[strings.ToLower(ext)]
}
<commit_msg>goimports order<commit_after>// Package binary provides a collection of binary extensions
// and a utility function to check if given path is a binary
package binary

import (
	"path"
	"strings"

	"github.com/shamsher31/gobinext"
)

var extensions = binext.Get()

// Extensions is the extensions for different binary types
var Extensions map[string]bool

func init() {
	Extensions = map[string]bool{}
	for _, ext := range extensions {
		Extensions[ext] = true
	}
}

// Is checks if a path is a binary
func Is(p string) bool {
	ext := strings.TrimLeft(path.Ext(p), ".")
	return Extensions[strings.ToLower(ext)]
}
<|endoftext|>


<commit_before>package dht

import (
	"fmt"
	"strings"
)

// bitmap represents a bit array.
type bitmap struct {
	Size int
	data []byte
}

// newBitmap returns a size-length bitmap pointer.
func newBitmap(size int) *bitmap {
	div, mod := size/8, size%8
	if mod > 0 {
		div++
	}
	return &bitmap{size, make([]byte, div)}
}

// newBitmapFrom returns a new copyed bitmap pointer which
// newBitmap.data = other.data[:size].
func newBitmapFrom(other *bitmap, size int) *bitmap {
	bitmap := newBitmap(size)

	if size > other.Size {
		size = other.Size
	}

	div := size / 8

	for i := 0; i < div; i++ {
		bitmap.data[i] = other.data[i]
	}

	for i := div * 8; i < size; i++ {
		if other.Bit(i) == 1 {
			bitmap.Set(i)
		}
	}

	return bitmap
}

// newBitmapFromBytes returns a bitmap pointer created from a byte array.
func newBitmapFromBytes(data []byte) *bitmap {
	bitmap := newBitmap(len(data) * 8)
	copy(bitmap.data, data)
	return bitmap
}

// newBitmapFromString returns a bitmap pointer created from a string.
func newBitmapFromString(data string) *bitmap {
	return newBitmapFromBytes([]byte(data))
}

// Bit returns the bit at index.
func (bitmap *bitmap) Bit(index int) int {
	if index >= bitmap.Size {
		panic("index out of range")
	}

	div, mod := index/8, index%8
	return int((uint(bitmap.data[div]) & (1 << uint(7-mod))) >> uint(7-mod))
}

// set sets the bit at index `index`. If bit is true, set 1, otherwise set 0.
func (bitmap *bitmap) set(index int, bit int) {
	if index >= bitmap.Size {
		panic("index out of range")
	}

	div, mod := index/8, index%8
	shift := byte(1 << uint(7-mod))

	bitmap.data[div] &= ^shift
	if bit > 0 {
		bitmap.data[div] |= shift
	}
}

// Set sets the bit at idnex to 1.
func (bitmap *bitmap) Set(index int) {
	bitmap.set(index, 1)
}

// Unset sets the bit at idnex to 0.
func (bitmap *bitmap) Unset(index int) {
	bitmap.set(index, 0)
}

// Compare compares the prefixLen-prefix of two bitmap.
//   - If bitmap.data[:prefixLen] < other.data[:prefixLen], return -1.
//   - If bitmap.data[:prefixLen] > other.data[:prefixLen], return 1.
//   - Otherwise return 0.
func (bitmap *bitmap) Compare(other *bitmap, prefixLen int) int {
	if prefixLen > bitmap.Size || prefixLen > other.Size {
		panic("index out of range")
	}

	div, mod := prefixLen/8, prefixLen%8
	for i := 0; i < div; i++ {
		if bitmap.data[i] > other.data[i] {
			return 1
		} else if bitmap.data[i] < other.data[i] {
			return -1
		}
	}

	for i := div * 8; i < div*8+mod; i++ {
		bit1, bit2 := bitmap.Bit(i), other.Bit(i)
		if bit1 > bit2 {
			return 1
		} else if bit1 < bit2 {
			return -1
		}
	}

	return 0
}

// Xor returns the xor value of two bitmap.
func (bitmap *bitmap) Xor(other *bitmap) *bitmap {
	if bitmap.Size != other.Size {
		panic("size not the same")
	}

	distance := newBitmap(bitmap.Size)
	div, mod := distance.Size/8, distance.Size%8

	for i := 0; i < div; i++ {
		distance.data[i] = bitmap.data[i] ^ other.data[i]
	}

	for i := div * 8; i < div*8+mod; i++ {
		distance.set(i, bitmap.Bit(i)^other.Bit(i))
	}

	return distance
}

// String returns the bit sequence string of the bitmap.
func (bitmap *bitmap) String() string {
	div, mod := bitmap.Size/8, bitmap.Size%8
	buff := make([]string, div+mod)

	for i := 0; i < div; i++ {
		buff[i] = fmt.Sprintf("%08b", bitmap.data[i])
	}

	for i := div; i < div+mod; i++ {
		buff[i] = fmt.Sprintf("%1b", bitmap.Bit(div*8+(i-div)))
	}

	return strings.Join(buff, "")
}

// RawString returns the string value of bitmap.data.
func (bitmap *bitmap) RawString() string {
	return string(bitmap.data)
}
<commit_msg>bitmap optimization attempt<commit_after>package dht

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

// bitmap represents a bit array.
type bitmap struct {
	Size int
	data []byte
}

// newBitmap returns a size-length bitmap pointer.
func newBitmap(size int) *bitmap {
	div, mod := size/8, size%8
	if mod > 0 {
		div++
	}
	return &bitmap{size, make([]byte, div)}
}

// newBitmapFrom returns a new copyed bitmap pointer which
// newBitmap.data = other.data[:size].
func newBitmapFrom(other *bitmap, size int) *bitmap {
	bitmap := newBitmap(size)

	if size > other.Size {
		size = other.Size
	}

	div := size / 8

	for i := 0; i < div; i++ {
		bitmap.data[i] = other.data[i]
	}

	for i := div * 8; i < size; i++ {
		if other.Bit(i) == 1 {
			bitmap.Set(i)
		}
	}

	return bitmap
}

// newBitmapFromBytes returns a bitmap pointer created from a byte array.
func newBitmapFromBytes(data []byte) *bitmap {
	bitmap := newBitmap(len(data) * 8)
	copy(bitmap.data, data)
	return bitmap
}

// newBitmapFromString returns a bitmap pointer created from a string.
func newBitmapFromString(data string) *bitmap {
	return newBitmapFromBytes([]byte(data))
}

// Bit returns the bit at index.
func (bitmap *bitmap) Bit(index int) int {
	if index >= bitmap.Size {
		panic("index out of range")
	}

	div, mod := index/8, index%8
	return int((uint(bitmap.data[div]) & (1 << uint(7-mod))) >> uint(7-mod))
}

// set sets the bit at index `index`. If bit is true, set 1, otherwise set 0.
func (bitmap *bitmap) set(index int, bit int) {
	if index >= bitmap.Size {
		panic("index out of range")
	}

	div, mod := index/8, index%8
	shift := byte(1 << uint(7-mod))

	bitmap.data[div] &= ^shift
	if bit > 0 {
		bitmap.data[div] |= shift
	}
}

// Set sets the bit at idnex to 1.
func (bitmap *bitmap) Set(index int) {
	bitmap.set(index, 1)
}

// Unset sets the bit at idnex to 0.
func (bitmap *bitmap) Unset(index int) {
	bitmap.set(index, 0)
}

// Compare compares the prefixLen-prefix of two bitmap.
//   - If bitmap.data[:prefixLen] < other.data[:prefixLen], return -1.
//   - If bitmap.data[:prefixLen] > other.data[:prefixLen], return 1.
//   - Otherwise return 0.
func (bitmap *bitmap) Compare(other *bitmap, prefixLen int) int {
	if prefixLen > bitmap.Size || prefixLen > other.Size {
		panic("index out of range")
	}

	div, mod := prefixLen/8, prefixLen%8
	res := bytes.Compare(bitmap.data[:div], other.data[:div])
	if res != 0  {
		return res
	}

	for i := div * 8; i < div*8+mod; i++ {
		bit1, bit2 := bitmap.Bit(i), other.Bit(i)
		if bit1 > bit2 {
			return 1
		} else if bit1 < bit2 {
			return -1
		}
	}

	return 0
}
const wordSize = int(unsafe.Sizeof(uintptr(0)))

func fastXORBytes(dst, a, b []byte) int {
	n := len(a)
	if len(b) < n {
		n = len(b)
	}

	w := n / wordSize
	if w > 0 {
		dw := *(*[]uintptr)(unsafe.Pointer(&dst))
		aw := *(*[]uintptr)(unsafe.Pointer(&a))
		bw := *(*[]uintptr)(unsafe.Pointer(&b))
		for i := 0; i < w; i++ {
			dw[i] = aw[i] ^ bw[i]
		}
	}

	for i := n - n%wordSize; i < n; i++ {
		dst[i] = a[i] ^ b[i]
	}

	return n
}

// Xor returns the xor value of two bitmap.
func (bitmap *bitmap) Xor(other *bitmap) *bitmap {
	if bitmap.Size != other.Size {
		panic("size not the same")
	}

	distance := newBitmap(bitmap.Size)
	div, mod := distance.Size/8, distance.Size%8

	fastXORBytes(distance.data, bitmap.data[:div], other.data[:div])

	for i := div * 8; i < div*8+mod; i++ {
		distance.set(i, bitmap.Bit(i)^other.Bit(i))
	}

	return distance
}

// String returns the bit sequence string of the bitmap.
func (bitmap *bitmap) String() string {
	div, mod := bitmap.Size/8, bitmap.Size%8
	buff := make([]string, div+mod)

	for i := 0; i < div; i++ {
		buff[i] = fmt.Sprintf("%08b", bitmap.data[i])
	}

	for i := div; i < div+mod; i++ {
		buff[i] = fmt.Sprintf("%1b", bitmap.Bit(div*8+(i-div)))
	}

	return strings.Join(buff, "")
}

// RawString returns the string value of bitmap.data.
func (bitmap *bitmap) RawString() string {
	return string(bitmap.data)
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 Apptimist, 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 main

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"
)

const (
	AsnApprovals   = "asn/approvals"
	AsnAuth        = "asn/auth"
	AsnAuthor      = "asn/author"
	AsnBridge      = "asn/bridge"
	AsnEditors     = "asn/editors"
	AsnID          = "asn/user_id"
	AsnInvites     = "asn/invites"
	AsnMark        = "asn/mark"
	AsnMessages    = "asn/messages"
	AsnModerators  = "asn/moderators"
	AsnRemovals    = "asn/removals"
	AsnSubscribers = "asn/subscribers"
	AsnUser        = "asn/user"
	AsnVouchers    = "asn/vouchers"
)

var AsnPubEncrLists = []string{
	AsnEditors,
	AsnInvites,
	AsnModerators,
	AsnSubscribers,
}

type Cache map[string]*CacheEntry

func (c Cache) Auth() *PubAuth {
	return c.PubAuth(AsnAuth)
}

func (c Cache) Author() *PubEncr {
	return c.PubEncr(AsnAuthor)
}

func (c Cache) CacheBuffer(kw string) CacheBuffer {
	l, _ := c[kw].Cacher.(CacheBuffer)
	return l
}

func (c Cache) Editors() *PubEncrList {
	return c.PubEncrList(AsnEditors)
}

func (c Cache) ID() string {
	return c.CacheBuffer(AsnID).Buffer.String()
}

func (c Cache) Invites() *PubEncrList {
	return c.PubEncrList(AsnInvites)
}

func (c Cache) Load(dn string) error {
	for fn, e := range c {
		if fn == AsnID {
			e.Cacher = NewCacheBuffer()
		}
		pn := filepath.Join(dn, fn)
		fi, err := os.Stat(pn)
		if err != nil {
			if os.IsNotExist(err) {
				err = nil
				continue
			} else {
				return err
			}
		}
		if fi.IsDir() {
			dir, err := ioutil.ReadDir(pn)
			if err != nil {
				return &Error{pn, err.Error()}
			}
			for _, fi := range dir {
				keystr := fi.Name()
				key, err := NewPubEncr(keystr)
				if err != nil {
					return err
				}
				c.PubEncrList(fn).KeyAdd(key)
			}
			e.Time = time.Now()
		} else {
			f, err := os.Open(pn)
			if err != nil {
				return err
			}
			var fh FH
			if _, err = fh.ReadFrom(f); err != nil {
				f.Close()
				return &Error{pn, err.Error()}
			}
			e.Time = fh.Blob.Time
			_, err = e.ReadFrom(f)
			f.Close()
			if err != nil {
				return &Error{pn, err.Error()}
			}
		}
	}
	return nil
}

func (c Cache) Mark() *Mark {
	return c[AsnMark].Cacher.(*Mark)
}

func (c Cache) Moderators() *PubEncrList {
	return c.PubEncrList(AsnModerators)
}

func (c Cache) PubAuth(kw string) *PubAuth {
	l, _ := c[kw].Cacher.(*PubAuth)
	return l
}

func (c Cache) PubEncr(kw string) *PubEncr {
	l, _ := c[kw].Cacher.(*PubEncr)
	return l
}

func (c Cache) PubEncrList(kw string) *PubEncrList {
	l, _ := c[kw].Cacher.(*PubEncrList)
	return l
}

func (c Cache) Reset() {
	for _, e := range c {
		e.Reset()
	}
}

func (c Cache) Subscribers() *PubEncrList {
	return c.PubEncrList(AsnSubscribers)
}

type CacheEntry struct {
	time.Time
	Cacher
}

func (e *CacheEntry) Reset() {
	e.Time = Time0
	e.Cacher.Reset()
}

func (e *CacheEntry) Set(v interface{}) error {
	if t, ok := v.(time.Time); ok {
		e.Time = t
		return nil
	}
	return e.Cacher.Set(v)
}

func (e *CacheEntry) String() string {
	return e.Cacher.String()
}

type CacheBuffer struct {
	*bytes.Buffer
}

func NewCacheBuffer() (c CacheBuffer) {
	c.Buffer = new(bytes.Buffer)
	return
}

func (c CacheBuffer) Has(v interface{}) bool {
	switch t := v.(type) {
	case []byte:
		return bytes.Equal(t, c.Bytes())
	case string:
		return t == c.String()
	}
	return false
}

func (c CacheBuffer) Set(v interface{}) error {
	switch t := v.(type) {
	case []byte:
		c.Reset()
		_, err := c.Write(t)
		return err
	case string:
		c.Reset()
		_, err := c.Write([]byte(t))
		return err
	}
	return os.ErrInvalid
}
<commit_msg>catch nil Buffer<commit_after>// Copyright 2014-2015 Apptimist, 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 main

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"
)

const (
	AsnApprovals   = "asn/approvals"
	AsnAuth        = "asn/auth"
	AsnAuthor      = "asn/author"
	AsnBridge      = "asn/bridge"
	AsnEditors     = "asn/editors"
	AsnID          = "asn/user_id"
	AsnInvites     = "asn/invites"
	AsnMark        = "asn/mark"
	AsnMessages    = "asn/messages"
	AsnModerators  = "asn/moderators"
	AsnRemovals    = "asn/removals"
	AsnSubscribers = "asn/subscribers"
	AsnUser        = "asn/user"
	AsnVouchers    = "asn/vouchers"
)

var AsnPubEncrLists = []string{
	AsnEditors,
	AsnInvites,
	AsnModerators,
	AsnSubscribers,
}

type Cache map[string]*CacheEntry

func (c Cache) Auth() *PubAuth {
	return c.PubAuth(AsnAuth)
}

func (c Cache) Author() *PubEncr {
	return c.PubEncr(AsnAuthor)
}

func (c Cache) CacheBuffer(kw string) CacheBuffer {
	l, _ := c[kw].Cacher.(CacheBuffer)
	return l
}

func (c Cache) Editors() *PubEncrList {
	return c.PubEncrList(AsnEditors)
}

func (c Cache) ID() string {
	b := c.CacheBuffer(AsnID).Buffer
	if b == nil {
		return ""
	}
	return b.String()
}

func (c Cache) Invites() *PubEncrList {
	return c.PubEncrList(AsnInvites)
}

func (c Cache) Load(dn string) error {
	for fn, e := range c {
		if fn == AsnID {
			e.Cacher = NewCacheBuffer()
		}
		pn := filepath.Join(dn, fn)
		fi, err := os.Stat(pn)
		if err != nil {
			if os.IsNotExist(err) {
				err = nil
				continue
			} else {
				return err
			}
		}
		if fi.IsDir() {
			dir, err := ioutil.ReadDir(pn)
			if err != nil {
				return &Error{pn, err.Error()}
			}
			for _, fi := range dir {
				keystr := fi.Name()
				key, err := NewPubEncr(keystr)
				if err != nil {
					return err
				}
				c.PubEncrList(fn).KeyAdd(key)
			}
			e.Time = time.Now()
		} else {
			f, err := os.Open(pn)
			if err != nil {
				return err
			}
			var fh FH
			if _, err = fh.ReadFrom(f); err != nil {
				f.Close()
				return &Error{pn, err.Error()}
			}
			e.Time = fh.Blob.Time
			_, err = e.ReadFrom(f)
			f.Close()
			if err != nil {
				return &Error{pn, err.Error()}
			}
		}
	}
	return nil
}

func (c Cache) Mark() *Mark {
	return c[AsnMark].Cacher.(*Mark)
}

func (c Cache) Moderators() *PubEncrList {
	return c.PubEncrList(AsnModerators)
}

func (c Cache) PubAuth(kw string) *PubAuth {
	l, _ := c[kw].Cacher.(*PubAuth)
	return l
}

func (c Cache) PubEncr(kw string) *PubEncr {
	l, _ := c[kw].Cacher.(*PubEncr)
	return l
}

func (c Cache) PubEncrList(kw string) *PubEncrList {
	l, _ := c[kw].Cacher.(*PubEncrList)
	return l
}

func (c Cache) Reset() {
	for _, e := range c {
		e.Reset()
	}
}

func (c Cache) Subscribers() *PubEncrList {
	return c.PubEncrList(AsnSubscribers)
}

type CacheEntry struct {
	time.Time
	Cacher
}

func (e *CacheEntry) Reset() {
	e.Time = Time0
	e.Cacher.Reset()
}

func (e *CacheEntry) Set(v interface{}) error {
	if t, ok := v.(time.Time); ok {
		e.Time = t
		return nil
	}
	return e.Cacher.Set(v)
}

func (e *CacheEntry) String() string {
	return e.Cacher.String()
}

type CacheBuffer struct {
	*bytes.Buffer
}

func NewCacheBuffer() (c CacheBuffer) {
	c.Buffer = new(bytes.Buffer)
	return
}

func (c CacheBuffer) Has(v interface{}) bool {
	switch t := v.(type) {
	case []byte:
		return bytes.Equal(t, c.Bytes())
	case string:
		return t == c.String()
	}
	return false
}

func (c CacheBuffer) Set(v interface{}) error {
	switch t := v.(type) {
	case []byte:
		c.Reset()
		_, err := c.Write(t)
		return err
	case string:
		c.Reset()
		_, err := c.Write([]byte(t))
		return err
	}
	return os.ErrInvalid
}
<|endoftext|>