<commit_before>package yy

import (
	"strconv"
	"time"
)

// Sets value from chars in []byte
type setter interface {
	Set([]byte) error
}

// Type Loc indicate if timezone present/absent in incomplete date
type Loc struct {
	l *time.Location
}

// Sets timezone
// accept `[+-]\d\d:{0,1}\d\d` or `.+`
func (t *Loc) Set(v []byte) error {
	var (
		l   *time.Location
		err error
	)
	if v[0] == '+' || v[0] == '-' {
		if v[3] == ':' {
			return t.SetHHMM(v[:3], v[4:6])
		} else {
			return t.SetHHMM(v[:3], v[3:5])
		}

	} else {
		return t.SetName(v)
		//l, err = ltzs(v)
	}

	if err != nil {
		return err
	}
	t.l = l
	return nil
}

// Returns if timezone is present in incomplete date
func (t *Loc) Present() bool {
	return t.l != nil
}

// Returns Location
func (t *Loc) Get() *time.Location {
	return t.l
}

// Sets timezone to hh:mm
func (t *Loc) SetHHMM(hs, ms []byte) error {
	h, err := strconv.Atoi(string(hs))
	if err != nil {
		return err
	}
	m, err := strconv.Atoi(string(ms))
	if err != nil {
		return err
	}
	if h < 0 {
		h = -h
		return t.SetS(-((h*60 + m) * 60))
	}
	return t.SetS((h*60 + m) * 60)
}

// Sets timezone from name, special names 'z' && 'l'
// set UTC && Local timezones
func (t *Loc) SetName(v []byte) error {
	// TODO trims spaces
	zs := string(v)
	if zs == "z" {
		t.l = time.UTC
		return nil
	}
	if zs == "l" {
		t.l = time.Local
		return nil
	}

	l, err := time.LoadLocation(zs)
	if err != nil {
		return err
	}
	t.l = l
	return nil
}

// Sets timezone from seconds offset
func (t *Loc) SetS(s int) error {
	t.l = time.FixedZone("", s)
	return nil
}

//////////////////////

type Int struct {
	present bool
	val     int
}

///////////////

// Type Int indicate if various parts of date (day,month,hour,min,sec)
// present/absent in incomplete date
func (i *Int) SetI(v int) {
	i.val = v
	i.present = true
}

// Sets Int from chars in v
func (i *Int) Set(v []byte) error {
	iv, err := strconv.Atoi(string(v))
	if err == nil {
		i.present = true
		i.val = iv
	}
	return err
}

// Returns presense of Int value
func (i *Int) Present() bool {
	return i.present
}

// Returns Int value
func (i *Int) Get() int {
	return i.val
}

///////////////////

// Type Frac indicate if fractions present/absent in incomplete date
type Frac struct {
	Int
}

// Sets Frac from chars in v
func (f *Frac) Set(v []byte) error {
	// force allocation of new backing array
	return f.Int.Set(append(v[:len(v):len(v)], []byte("000000000000")...)[:9])
}

//////////////////////

// Type Year indicate number of year decimal digits in incomplete date (0 digits=no year)
type Year struct {
	digits int8
	y      int
}

// Sets year from chars in v, number of digits is set to len(v)
func (y *Year) Set(v []byte) error {
	if len(v) == 0 {
		y.digits = 0
		return nil
	}
	yv, err := strconv.Atoi(string(v))
	if err == nil {
		y.digits = int8(len(v))
		y.y = yv
	}
	return err
}

// Sets digits & year to integers d, iy
func (y *Year) SetDI(d, iy int) {
	y.digits = int8(d)
	y.y = iy
}

// Returns (incomplete) year
func (y *Year) Get() int {
	return y.y
}

// Returns number of decimal digits in year
func (y *Year) Digits() int8 {
	return y.digits
}

// Type IDate represent components of incomplete date
type IDate struct {
	R, J, Mo, D, H, M, S Int
	F                    Frac
	Y                    Year
	L                    Loc
}
<commit_msg>remove dead code<commit_after>package yy

import (
	"strconv"
	"time"
)

// Sets value from chars in []byte
type setter interface {
	Set([]byte) error
}

// Type Loc indicate if timezone present/absent in incomplete date
type Loc struct {
	l *time.Location
}

// Sets timezone
// accept `[+-]\d\d:{0,1}\d\d` or `.+`
func (t *Loc) Set(v []byte) error {
	if v[0] == '+' || v[0] == '-' {
		if v[3] == ':' {
			return t.SetHHMM(v[:3], v[4:6])
		}
		return t.SetHHMM(v[:3], v[3:5])
	}
	return t.SetName(v)
}

// Returns if timezone is present in incomplete date
func (t *Loc) Present() bool {
	return t.l != nil
}

// Returns Location
func (t *Loc) Get() *time.Location {
	return t.l
}

// Sets timezone to hh:mm
func (t *Loc) SetHHMM(hs, ms []byte) error {
	h, err := strconv.Atoi(string(hs))
	if err != nil {
		return err
	}
	m, err := strconv.Atoi(string(ms))
	if err != nil {
		return err
	}
	if h < 0 {
		h = -h
		return t.SetS(-((h*60 + m) * 60))
	}
	return t.SetS((h*60 + m) * 60)
}

// Sets timezone from name, special names 'z' && 'l'
// set UTC && Local timezones
func (t *Loc) SetName(v []byte) error {
	// TODO trims spaces
	zs := string(v)
	if zs == "z" {
		t.l = time.UTC
		return nil
	}
	if zs == "l" {
		t.l = time.Local
		return nil
	}

	l, err := time.LoadLocation(zs)
	if err != nil {
		return err
	}
	t.l = l
	return nil
}

// Sets timezone from seconds offset
func (t *Loc) SetS(s int) error {
	t.l = time.FixedZone("", s)
	return nil
}

//////////////////////

type Int struct {
	present bool
	val     int
}

///////////////

// Type Int indicate if various parts of date (day,month,hour,min,sec)
// present/absent in incomplete date
func (i *Int) SetI(v int) {
	i.val = v
	i.present = true
}

// Sets Int from chars in v
func (i *Int) Set(v []byte) error {
	iv, err := strconv.Atoi(string(v))
	if err == nil {
		i.present = true
		i.val = iv
	}
	return err
}

// Returns presense of Int value
func (i *Int) Present() bool {
	return i.present
}

// Returns Int value
func (i *Int) Get() int {
	return i.val
}

///////////////////

// Type Frac indicate if fractions present/absent in incomplete date
type Frac struct {
	Int
}

// Sets Frac from chars in v
func (f *Frac) Set(v []byte) error {
	// force allocation of new backing array
	return f.Int.Set(append(v[:len(v):len(v)], []byte("000000000000")...)[:9])
}

//////////////////////

// Type Year indicate number of year decimal digits in incomplete date (0 digits=no year)
type Year struct {
	digits int8
	y      int
}

// Sets year from chars in v, number of digits is set to len(v)
func (y *Year) Set(v []byte) error {
	if len(v) == 0 {
		y.digits = 0
		return nil
	}
	yv, err := strconv.Atoi(string(v))
	if err == nil {
		y.digits = int8(len(v))
		y.y = yv
	}
	return err
}

// Sets digits & year to integers d, iy
func (y *Year) SetDI(d, iy int) {
	y.digits = int8(d)
	y.y = iy
}

// Returns (incomplete) year
func (y *Year) Get() int {
	return y.y
}

// Returns number of decimal digits in year
func (y *Year) Digits() int8 {
	return y.digits
}

// Type IDate represent components of incomplete date
type IDate struct {
	R, J, Mo, D, H, M, S Int
	F                    Frac
	Y                    Year
	L                    Loc
}
<|endoftext|>


<commit_before>package data

import (
	"fmt"
	"log"
	"sort"
	"strings"
)

type Asset struct {
	Currency string `json:"currency"`
	Issuer   string `json:"issuer,omitempty"`
}

func NewAsset(s string) (*Asset, error) {
	if s == "XRP" {
		return &Asset{
			Currency: s,
		}, nil
	}
	parts := strings.Split(s, "/")
	if len(parts) != 2 {
		return nil, fmt.Errorf("bad asset: %s", s)
	}
	return &Asset{
		Currency: parts[0],
		Issuer:   parts[1],
	}, nil
}

func (a *Asset) IsNative() bool {
	return a.Currency == "XRP"
}

func (a Asset) String() string {
	if a.IsNative() {
		return a.Currency
	}
	return fmt.Sprintf("%s/%-34s", a.Currency, a.Issuer)
}

type OrderBookOffer struct {
	Offer
	OwnerFunds      Value          `json:"owner_funds"`
	Quality         NonNativeValue `json:"quality"`
	TakerGetsFunded *Amount        `json:"taker_gets_funded"`
	TakerPaysFunded *Amount        `json:"taker_pays_funded"`
}

type AccountOffer struct {
	Flags      LedgerEntryFlag `json:"flags"`
	Quality    NonNativeValue  `json:"quality"`
	Sequence   uint32          `json:"seq"`
	TakerGets  Amount          `json:"taker_gets"`
	TakerPays  Amount          `json:"taker_pays"`
	Expiration *uint32         `json:"expiration"`
}

type AccountOfferSlice []AccountOffer

func (s AccountOfferSlice) Len() int           { return len(s) }
func (s AccountOfferSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s AccountOfferSlice) Less(i, j int) bool { return s[i].Sequence > s[j].Sequence }

func (s AccountOfferSlice) GetSequences(pays, gets *Asset) []uint32 {
	// TODO: improve performance
	var sequences []uint32
	for i := range s {
		if s[i].TakerPays.Currency.String() == pays.Currency &&
			s[i].TakerPays.Issuer.String() == pays.Issuer &&
			s[i].TakerGets.Currency.String() == gets.Currency &&
			s[i].TakerGets.Issuer.String() == gets.Issuer {
			sequences = append(sequences, s[i].Sequence)
		}
	}
	return sequences
}

func (s AccountOfferSlice) Find(sequence uint32) int {
	return sort.Search(len(s), func(i int) bool {
		return s[i].Sequence <= sequence
	})
}

func (s AccountOfferSlice) Get(sequence uint32) *AccountOffer {
	if i := s.Find(sequence); i < len(s) && s[i].Sequence == sequence {
		return &s[i]
	}
	return nil
}

func defaultUint32(v *uint32) uint32 {
	if v == nil {
		return 0
	}
	return *v
}

func (s *AccountOfferSlice) Add(offer *Offer) bool {
	quality, err := offer.TakerPays.Divide(offer.TakerGets)
	if err != nil {
		panic(fmt.Sprintf("impossible quality: %s %s", offer.TakerPays, offer.TakerGets))
	}
	o := AccountOffer{
		Flags:      LedgerEntryFlag(defaultUint32((*uint32)(offer.Flags))),
		Sequence:   *offer.Sequence,
		TakerGets:  *offer.TakerGets,
		TakerPays:  *offer.TakerPays,
		Quality:    NonNativeValue{*quality.Value},
		Expiration: offer.Expiration,
	}
	i := s.Find(*offer.Sequence)
	switch {
	case i == len(*s):
		*s = append(*s, o)
		return true
	case (*s)[i].Sequence != *offer.Sequence:
		*s = append(*s, AccountOffer{})
		copy((*s)[i+1:], (*s)[i:])
		(*s)[i] = o
		return true
	default:
		return false
	}
}

func (s AccountOfferSlice) Update(offer *Offer) bool {
	if existing := s.Get(*offer.Sequence); existing != nil {
		existing.TakerGets = *offer.TakerGets
		existing.TakerPays = *offer.TakerPays
		return true
	}
	return false
}

func (s *AccountOfferSlice) Delete(offer *Offer) bool {
	if i := s.Find(*offer.Sequence); i < len(*s) && (*s)[i].Sequence == *offer.Sequence {
		*s = append((*s)[:i], (*s)[i+1:]...)
		return true
	}
	return false
}

type AccountLine struct {
	Account      Account        `json:"account"`
	Balance      NonNativeValue `json:"balance"`
	Currency     Currency       `json:"currency"`
	Limit        NonNativeValue `json:"limit"`
	LimitPeer    NonNativeValue `json:"limit_peer"`
	NoRipple     bool           `json:"no_ripple"`
	NoRipplePeer bool           `json:"no_ripple_peer"`
	QualityIn    uint32         `json:"quality_in"`
	QualityOut   uint32         `json:"quality_out"`
}

func (l *AccountLine) Asset() *Asset {
	return &Asset{
		Currency: l.Currency.String(),
		Issuer:   l.Account.String(),
	}
}

func (l *AccountLine) CompareByCurrencyAccount(other *AccountLine) int {
	if cmp := l.Currency.Compare(other.Currency); cmp != 0 {
		return cmp
	}
	return l.Account.Compare(other.Account)
}

func (l *AccountLine) CompareByCurrencyAmount(other *AccountLine) int {
	if cmp := l.Currency.Compare(other.Currency); cmp != 0 {
		return cmp
	}
	return l.Balance.Abs().Compare(*other.Balance.Abs())
}

type AccountLineSlice []AccountLine

type byCurrencyAccount struct {
	AccountLineSlice
}

func (by *byCurrencyAccount) Less(i, j int) bool {
	return by.AccountLineSlice[i].CompareByCurrencyAccount(&by.AccountLineSlice[j]) < 0
}

type byCurrencyAmount struct {
	AccountLineSlice
}

func (by *byCurrencyAmount) Less(i, j int) bool {
	return by.AccountLineSlice[i].CompareByCurrencyAmount(&by.AccountLineSlice[j]) < 0
}

func (s AccountLineSlice) Len() int               { return len(s) }
func (s AccountLineSlice) Swap(i, j int)          { s[i], s[j] = s[j], s[i] }
func (s AccountLineSlice) SortbyCurrencyAccount() { sort.Sort(&byCurrencyAccount{s}) }
func (s AccountLineSlice) SortByCurrencyAmount()  { sort.Sort(&byCurrencyAmount{s}) }

func (s AccountLineSlice) Find(account Account, currency Currency) int {
	return sort.Search(len(s), func(i int) bool {
		switch s[i].Currency.Compare(currency) {
		case 1:
			return true
		case -1:
			return false
		default:
			return s[i].Account.Compare(account) >= 0
		}
	})
}

type highLowFunc func(balance, limit, limitPeer *Amount, noRipple, noRipplePeer bool, qualityIn, qualityOut uint32) bool

func highLow(account Account, rs *RippleState, f highLowFunc) bool {
	high, low := account.Equals(rs.HighLimit.Issuer), account.Equals(rs.LowLimit.Issuer)
	log.Println("highlow", high, low, account)
	switch {
	case high == low:
		return false
	case high:
		noRipple, noRipplePeer := *rs.Flags&LsHighNoRipple > 0, *rs.Flags&LsLowNoRipple > 0
		return f(rs.Balance.Negate(), rs.HighLimit, rs.LowLimit, noRipple, noRipplePeer, defaultUint32(rs.HighQualityIn), defaultUint32(rs.HighQualityOut))
	default:
		noRipple, noRipplePeer := *rs.Flags&LsLowNoRipple > 0, *rs.Flags&LsHighNoRipple > 0
		return f(rs.Balance, rs.LowLimit, rs.HighLimit, noRipple, noRipplePeer, defaultUint32(rs.LowQualityIn), defaultUint32(rs.LowQualityOut))
	}
}

func (s *AccountLineSlice) Add(account Account, rs *RippleState) bool {
	var add = func(balance, limit, limitPeer *Amount, noRipple, noRipplePeer bool, qualityIn, qualityOut uint32) bool {
		line := AccountLine{
			Account:      limitPeer.Issuer,
			Balance:      NonNativeValue{*balance.Value},
			Currency:     limit.Currency,
			Limit:        NonNativeValue{*limit.Value},
			LimitPeer:    NonNativeValue{*limitPeer.Value},
			NoRipple:     noRipple,
			NoRipplePeer: noRipplePeer,
			QualityIn:    qualityIn,
			QualityOut:   qualityOut,
		}
		i := s.Find(limitPeer.Issuer, limitPeer.Currency)
		log.Println("Add", account, limitPeer.Issuer, limitPeer.Currency, len(*s), i)
		switch {
		case i == len(*s):
			*s = append(*s, line)
			return true
		case (*s)[i].Account.Equals(limitPeer.Issuer) && (*s)[i].Currency.Equals(limitPeer.Currency):
			return false
		default:
			*s = append((*s)[:i], append(AccountLineSlice{line}, (*s)[i:]...)...)
			return true
		}
	}
	return highLow(account, rs, add)
}

func (s AccountLineSlice) Update(account Account, rs *RippleState) bool {
	var update = func(balance, limit, limitPeer *Amount, noripple, noRipplePeer bool, qualityIn, qualityOut uint32) bool {
		i := s.Find(limitPeer.Issuer, limitPeer.Currency)
		log.Println("Update:", account, limitPeer.Issuer, limitPeer.Currency, len(s), i)
		if i == len(s) || !s[i].Account.Equals(limitPeer.Issuer) || !s[i].Currency.Equals(limitPeer.Currency) {
			return false
		}
		s[i].Balance = NonNativeValue{*balance.Value}
		s[i].Limit = NonNativeValue{*limit.Value}
		s[i].LimitPeer = NonNativeValue{*limitPeer.Value}
		s[i].NoRipple = noripple
		s[i].NoRipplePeer = noRipplePeer
		return true
	}
	return highLow(account, rs, update)
}

func (s *AccountLineSlice) Delete(account Account, rs *RippleState) bool {
	var del = func(balance, limit, limitPeer *Amount, noripple, noRipplePeer bool, qualityIn, qualityOut uint32) bool {
		i := s.Find(limitPeer.Issuer, limitPeer.Currency)
		log.Println("Delete:", account, limitPeer.Issuer, limitPeer.Currency, len(*s), i)
		if i < len(*s) && (*s)[i].Account.Equals(limitPeer.Issuer) && (*s)[i].Currency.Equals(limitPeer.Currency) {
			*s = append((*s)[:i], (*s)[i+1:]...)
			return true
		}
		return false
	}
	return highLow(account, rs, del)
}
<commit_msg>Remove unnecessary logging<commit_after>package data

import (
	"fmt"
	"log"
	"sort"
	"strings"
)

type Asset struct {
	Currency string `json:"currency"`
	Issuer   string `json:"issuer,omitempty"`
}

func NewAsset(s string) (*Asset, error) {
	if s == "XRP" {
		return &Asset{
			Currency: s,
		}, nil
	}
	parts := strings.Split(s, "/")
	if len(parts) != 2 {
		return nil, fmt.Errorf("bad asset: %s", s)
	}
	return &Asset{
		Currency: parts[0],
		Issuer:   parts[1],
	}, nil
}

func (a *Asset) IsNative() bool {
	return a.Currency == "XRP"
}

func (a Asset) String() string {
	if a.IsNative() {
		return a.Currency
	}
	return fmt.Sprintf("%s/%-34s", a.Currency, a.Issuer)
}

type OrderBookOffer struct {
	Offer
	OwnerFunds      Value          `json:"owner_funds"`
	Quality         NonNativeValue `json:"quality"`
	TakerGetsFunded *Amount        `json:"taker_gets_funded"`
	TakerPaysFunded *Amount        `json:"taker_pays_funded"`
}

type AccountOffer struct {
	Flags      LedgerEntryFlag `json:"flags"`
	Quality    NonNativeValue  `json:"quality"`
	Sequence   uint32          `json:"seq"`
	TakerGets  Amount          `json:"taker_gets"`
	TakerPays  Amount          `json:"taker_pays"`
	Expiration *uint32         `json:"expiration"`
}

type AccountOfferSlice []AccountOffer

func (s AccountOfferSlice) Len() int           { return len(s) }
func (s AccountOfferSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s AccountOfferSlice) Less(i, j int) bool { return s[i].Sequence > s[j].Sequence }

func (s AccountOfferSlice) GetSequences(pays, gets *Asset) []uint32 {
	// TODO: improve performance
	var sequences []uint32
	for i := range s {
		if s[i].TakerPays.Currency.String() == pays.Currency &&
			s[i].TakerPays.Issuer.String() == pays.Issuer &&
			s[i].TakerGets.Currency.String() == gets.Currency &&
			s[i].TakerGets.Issuer.String() == gets.Issuer {
			sequences = append(sequences, s[i].Sequence)
		}
	}
	return sequences
}

func (s AccountOfferSlice) Find(sequence uint32) int {
	return sort.Search(len(s), func(i int) bool {
		return s[i].Sequence <= sequence
	})
}

func (s AccountOfferSlice) Get(sequence uint32) *AccountOffer {
	if i := s.Find(sequence); i < len(s) && s[i].Sequence == sequence {
		return &s[i]
	}
	return nil
}

func defaultUint32(v *uint32) uint32 {
	if v == nil {
		return 0
	}
	return *v
}

func (s *AccountOfferSlice) Add(offer *Offer) bool {
	quality, err := offer.TakerPays.Divide(offer.TakerGets)
	if err != nil {
		panic(fmt.Sprintf("impossible quality: %s %s", offer.TakerPays, offer.TakerGets))
	}
	o := AccountOffer{
		Flags:      LedgerEntryFlag(defaultUint32((*uint32)(offer.Flags))),
		Sequence:   *offer.Sequence,
		TakerGets:  *offer.TakerGets,
		TakerPays:  *offer.TakerPays,
		Quality:    NonNativeValue{*quality.Value},
		Expiration: offer.Expiration,
	}
	i := s.Find(*offer.Sequence)
	switch {
	case i == len(*s):
		*s = append(*s, o)
		return true
	case (*s)[i].Sequence != *offer.Sequence:
		*s = append(*s, AccountOffer{})
		copy((*s)[i+1:], (*s)[i:])
		(*s)[i] = o
		return true
	default:
		return false
	}
}

func (s AccountOfferSlice) Update(offer *Offer) bool {
	if existing := s.Get(*offer.Sequence); existing != nil {
		existing.TakerGets = *offer.TakerGets
		existing.TakerPays = *offer.TakerPays
		return true
	}
	return false
}

func (s *AccountOfferSlice) Delete(offer *Offer) bool {
	if i := s.Find(*offer.Sequence); i < len(*s) && (*s)[i].Sequence == *offer.Sequence {
		*s = append((*s)[:i], (*s)[i+1:]...)
		return true
	}
	return false
}

type AccountLine struct {
	Account      Account        `json:"account"`
	Balance      NonNativeValue `json:"balance"`
	Currency     Currency       `json:"currency"`
	Limit        NonNativeValue `json:"limit"`
	LimitPeer    NonNativeValue `json:"limit_peer"`
	NoRipple     bool           `json:"no_ripple"`
	NoRipplePeer bool           `json:"no_ripple_peer"`
	QualityIn    uint32         `json:"quality_in"`
	QualityOut   uint32         `json:"quality_out"`
}

func (l *AccountLine) Asset() *Asset {
	return &Asset{
		Currency: l.Currency.String(),
		Issuer:   l.Account.String(),
	}
}

func (l *AccountLine) CompareByCurrencyAccount(other *AccountLine) int {
	if cmp := l.Currency.Compare(other.Currency); cmp != 0 {
		return cmp
	}
	return l.Account.Compare(other.Account)
}

func (l *AccountLine) CompareByCurrencyAmount(other *AccountLine) int {
	if cmp := l.Currency.Compare(other.Currency); cmp != 0 {
		return cmp
	}
	return l.Balance.Abs().Compare(*other.Balance.Abs())
}

type AccountLineSlice []AccountLine

type byCurrencyAccount struct {
	AccountLineSlice
}

func (by *byCurrencyAccount) Less(i, j int) bool {
	return by.AccountLineSlice[i].CompareByCurrencyAccount(&by.AccountLineSlice[j]) < 0
}

type byCurrencyAmount struct {
	AccountLineSlice
}

func (by *byCurrencyAmount) Less(i, j int) bool {
	return by.AccountLineSlice[i].CompareByCurrencyAmount(&by.AccountLineSlice[j]) < 0
}

func (s AccountLineSlice) Len() int               { return len(s) }
func (s AccountLineSlice) Swap(i, j int)          { s[i], s[j] = s[j], s[i] }
func (s AccountLineSlice) SortbyCurrencyAccount() { sort.Sort(&byCurrencyAccount{s}) }
func (s AccountLineSlice) SortByCurrencyAmount()  { sort.Sort(&byCurrencyAmount{s}) }

func (s AccountLineSlice) Find(account Account, currency Currency) int {
	return sort.Search(len(s), func(i int) bool {
		switch s[i].Currency.Compare(currency) {
		case 1:
			return true
		case -1:
			return false
		default:
			return s[i].Account.Compare(account) >= 0
		}
	})
}

type highLowFunc func(balance, limit, limitPeer *Amount, noRipple, noRipplePeer bool, qualityIn, qualityOut uint32) bool

func highLow(account Account, rs *RippleState, f highLowFunc) bool {
	high, low := account.Equals(rs.HighLimit.Issuer), account.Equals(rs.LowLimit.Issuer)
	switch {
	case high == low:
		return false
	case high:
		noRipple, noRipplePeer := *rs.Flags&LsHighNoRipple > 0, *rs.Flags&LsLowNoRipple > 0
		return f(rs.Balance.Negate(), rs.HighLimit, rs.LowLimit, noRipple, noRipplePeer, defaultUint32(rs.HighQualityIn), defaultUint32(rs.HighQualityOut))
	default:
		noRipple, noRipplePeer := *rs.Flags&LsLowNoRipple > 0, *rs.Flags&LsHighNoRipple > 0
		return f(rs.Balance, rs.LowLimit, rs.HighLimit, noRipple, noRipplePeer, defaultUint32(rs.LowQualityIn), defaultUint32(rs.LowQualityOut))
	}
}

func (s *AccountLineSlice) Add(account Account, rs *RippleState) bool {
	var add = func(balance, limit, limitPeer *Amount, noRipple, noRipplePeer bool, qualityIn, qualityOut uint32) bool {
		line := AccountLine{
			Account:      limitPeer.Issuer,
			Balance:      NonNativeValue{*balance.Value},
			Currency:     limit.Currency,
			Limit:        NonNativeValue{*limit.Value},
			LimitPeer:    NonNativeValue{*limitPeer.Value},
			NoRipple:     noRipple,
			NoRipplePeer: noRipplePeer,
			QualityIn:    qualityIn,
			QualityOut:   qualityOut,
		}
		i := s.Find(limitPeer.Issuer, limitPeer.Currency)
		log.Println("Add", account, limitPeer.Issuer, limitPeer.Currency, len(*s), i)
		switch {
		case i == len(*s):
			*s = append(*s, line)
			return true
		case (*s)[i].Account.Equals(limitPeer.Issuer) && (*s)[i].Currency.Equals(limitPeer.Currency):
			return false
		default:
			*s = append((*s)[:i], append(AccountLineSlice{line}, (*s)[i:]...)...)
			return true
		}
	}
	return highLow(account, rs, add)
}

func (s AccountLineSlice) Update(account Account, rs *RippleState) bool {
	var update = func(balance, limit, limitPeer *Amount, noripple, noRipplePeer bool, qualityIn, qualityOut uint32) bool {
		i := s.Find(limitPeer.Issuer, limitPeer.Currency)
		log.Println("Update:", account, limitPeer.Issuer, limitPeer.Currency, len(s), i)
		if i == len(s) || !s[i].Account.Equals(limitPeer.Issuer) || !s[i].Currency.Equals(limitPeer.Currency) {
			return false
		}
		s[i].Balance = NonNativeValue{*balance.Value}
		s[i].Limit = NonNativeValue{*limit.Value}
		s[i].LimitPeer = NonNativeValue{*limitPeer.Value}
		s[i].NoRipple = noripple
		s[i].NoRipplePeer = noRipplePeer
		return true
	}
	return highLow(account, rs, update)
}

func (s *AccountLineSlice) Delete(account Account, rs *RippleState) bool {
	var del = func(balance, limit, limitPeer *Amount, noripple, noRipplePeer bool, qualityIn, qualityOut uint32) bool {
		i := s.Find(limitPeer.Issuer, limitPeer.Currency)
		log.Println("Delete:", account, limitPeer.Issuer, limitPeer.Currency, len(*s), i)
		if i < len(*s) && (*s)[i].Account.Equals(limitPeer.Issuer) && (*s)[i].Currency.Equals(limitPeer.Currency) {
			*s = append((*s)[:i], (*s)[i+1:]...)
			return true
		}
		return false
	}
	return highLow(account, rs, del)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gin-gonic/gin"
	csh_auth "github.com/liam-middlebrook/csh-auth"
	log "github.com/sirupsen/logrus"
	"image"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"net/http"
	"time"
)

func protectedProfile(c *gin.Context) {
	claims, ok := c.Value(csh_auth.AuthKey).(csh_auth.CSHClaims)
	if !ok {
		log.Fatal("error finding claims")
		return
	}
	c.String(http.StatusOK, "uid %s email %s name %s uuid %s", claims.UserInfo.Username, claims.UserInfo.Email, claims.UserInfo.FullName, claims.UserInfo.Subject)
}

func index(c *gin.Context) {
	c.Redirect(http.StatusFound, "/upload")
}

func action(c *gin.Context) {
	plug := GetPlug()
	url := S3PresignPlug(plug)

	claims, ok := c.Value(csh_auth.AuthKey).(csh_auth.CSHClaims)
	if !ok {
		log.Fatal("error finding claims")
		return
	}
	log.WithFields(log.Fields{
		"uid":           claims.UserInfo.Username,
		"plug_id":       plug.ID,
		"plug_s3id":     plug.S3ID,
		"presigned_uri": url.String(),
	}).Info("Presigned URI Generated")
	c.Redirect(http.StatusFound, url.String())
}

func upload(c *gin.Context) {
	plug := Plug{}

	claims, ok := c.Value(csh_auth.AuthKey).(csh_auth.CSHClaims)
	if !ok {
		log.Fatal("error finding claims")
		return
	}

	plug.Owner = claims.UserInfo.Username
	plug.ViewsRemaining = 100

	file, err := c.FormFile("file")
	if err != nil {
		log.Error(err)
		c.String(http.BadRequest, "Error Reading File")
		return
	}
	data, err := file.Open()
	if err != nil {
		log.Error(err)
		c.String(http.BadRequest, "Error Reading File")
		return
	}
	defer data.Close()
	imageData, _, err := image.DecodeConfig(data)
	if err != nil {
		log.Error(err)
		c.String(http.StatusUnsupportedMediaType, "Please upload either a JPG or PNG!")
		return
	}
	data.Seek(0, 0)
	if imageData.Width == 728 && imageData.Height == 200 {
		mime := getMime(data)
		data.Seek(0, 0)

		if !DecrementCredits(plug.Owner, 1) {
			c.String(http.StatusPaymentRequired, "Get More Credits!")
			return
		}

		plug.S3ID = time.Now().Format("2006/01/02/150405") + "-" + plug.Owner + "-" + file.Filename
		S3AddFile(plug, data, mime)

		MakePlug(plug)
	} else {
		log.Error("invalid file dimensions")
		c.String(http.StatusBadRequest, "Please upload a 728x200 pixel image!")
		return
	}

	c.Data(http.StatusOK, "text/html", []byte(`

Uploaded a Plug!

Take a look at what you uploaded! (This does not count towards the views for your Plug!)

			<img src="`+S3PresignPlug(plug).String()+`">

	`))
	log.WithFields(log.Fields{
		"uid":       claims.UserInfo.Username,
		"plug_id":   plug.ID,
		"plug_s3id": plug.S3ID,
	}).Info("Uploaded new Plug!")
}

func upload_view(c *gin.Context) {
	c.Data(http.StatusOK, "text/html", []byte(`

Upload a Plug!

You will lose 1 drink credit in exchange for a 100 view-limit plug!

Plugs must be 728x200 pixels and in PNG, or JPG format!

			<form action="/upload" method="post" enctype="multipart/form-data">
				<input type="file" name="file" id="file">
				<input type="submit" value="Upload" name="submit">
			</form>

	`))
}

func getMime(data io.Reader) string {
	buffer := make([]byte, 512)
	n, err := data.Read(buffer)
	if err != nil {
		log.Error(err)
	}
	return http.DetectContentType(buffer[:n])
}
<commit_msg>status<commit_after>package main

import (
	"github.com/gin-gonic/gin"
	csh_auth "github.com/liam-middlebrook/csh-auth"
	log "github.com/sirupsen/logrus"
	"image"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"net/http"
	"time"
)

func protectedProfile(c *gin.Context) {
	claims, ok := c.Value(csh_auth.AuthKey).(csh_auth.CSHClaims)
	if !ok {
		log.Fatal("error finding claims")
		return
	}
	c.String(http.StatusOK, "uid %s email %s name %s uuid %s", claims.UserInfo.Username, claims.UserInfo.Email, claims.UserInfo.FullName, claims.UserInfo.Subject)
}

func index(c *gin.Context) {
	c.Redirect(http.StatusFound, "/upload")
}

func action(c *gin.Context) {
	plug := GetPlug()
	url := S3PresignPlug(plug)

	claims, ok := c.Value(csh_auth.AuthKey).(csh_auth.CSHClaims)
	if !ok {
		log.Fatal("error finding claims")
		return
	}
	log.WithFields(log.Fields{
		"uid":           claims.UserInfo.Username,
		"plug_id":       plug.ID,
		"plug_s3id":     plug.S3ID,
		"presigned_uri": url.String(),
	}).Info("Presigned URI Generated")
	c.Redirect(http.StatusFound, url.String())
}

func upload(c *gin.Context) {
	plug := Plug{}

	claims, ok := c.Value(csh_auth.AuthKey).(csh_auth.CSHClaims)
	if !ok {
		log.Fatal("error finding claims")
		return
	}

	plug.Owner = claims.UserInfo.Username
	plug.ViewsRemaining = 100

	file, err := c.FormFile("file")
	if err != nil {
		log.Error(err)
		c.String(http.StatusBadRequest, "Error Reading File")
		return
	}
	data, err := file.Open()
	if err != nil {
		log.Error(err)
		c.String(http.StatusBadRequest, "Error Reading File")
		return
	}
	defer data.Close()
	imageData, _, err := image.DecodeConfig(data)
	if err != nil {
		log.Error(err)
		c.String(http.StatusUnsupportedMediaType, "Please upload either a JPG or PNG!")
		return
	}
	data.Seek(0, 0)
	if imageData.Width == 728 && imageData.Height == 200 {
		mime := getMime(data)
		data.Seek(0, 0)

		if !DecrementCredits(plug.Owner, 1) {
			c.String(http.StatusPaymentRequired, "Get More Credits!")
			return
		}

		plug.S3ID = time.Now().Format("2006/01/02/150405") + "-" + plug.Owner + "-" + file.Filename
		S3AddFile(plug, data, mime)

		MakePlug(plug)
	} else {
		log.Error("invalid file dimensions")
		c.String(http.StatusBadRequest, "Please upload a 728x200 pixel image!")
		return
	}

	c.Data(http.StatusOK, "text/html", []byte(`

Uploaded a Plug!

Take a look at what you uploaded! (This does not count towards the views for your Plug!)

			<img src="`+S3PresignPlug(plug).String()+`">

	`))
	log.WithFields(log.Fields{
		"uid":       claims.UserInfo.Username,
		"plug_id":   plug.ID,
		"plug_s3id": plug.S3ID,
	}).Info("Uploaded new Plug!")
}

func upload_view(c *gin.Context) {
	c.Data(http.StatusOK, "text/html", []byte(`

Upload a Plug!

You will lose 1 drink credit in exchange for a 100 view-limit plug!

Plugs must be 728x200 pixels and in PNG, or JPG format!

			<form action="/upload" method="post" enctype="multipart/form-data">
				<input type="file" name="file" id="file">
				<input type="submit" value="Upload" name="submit">
			</form>

	`))
}

func getMime(data io.Reader) string {
	buffer := make([]byte, 512)
	n, err := data.Read(buffer)
	if err != nil {
		log.Error(err)
	}
	return http.DetectContentType(buffer[:n])
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"

	"github.com/PuerkitoBio/goquery"
)

type dataTemplate struct {
	Name  string
	Cards []Card
}

type respMap struct {
	Resp *http.Response
	Card Card
}

var cockatricCXMap = map[string]string{
	"CR": "R",
	"CU": "U",
	"CC": "C",
}

const cacheTime = (time.Hour * 24) * 3

func getPlugin(url string) (plugin, error) {
	for _, plugin := range plugins {
		if plugin.isMine(url) {
			return plugin, nil
		}
	}

	return nil, fmt.Errorf("Url: (%v) not supported", url)
}

func fetchTranslation(cardsInfo []Card) []Card {
	translations := []Card{}

	for _, card := range cardsInfo {
		url := hoTcURL + card.ID + "&short=1"
		fmt.Println(url)
		doc, err := goquery.NewDocument(url)
		if err != nil {
			fmt.Println(err)
		}
		textHTML, err := doc.Find("body").Html()
		if err != nil {
			fmt.Println(err)
		}
		card.Translation = html.UnescapeString(textHTML)
		card.URL = yytMap[card.ID].URL

		translations = append(translations, card)
		time.Sleep(1 * time.Second)
	}

	return translations
}

func getTranslationHotC(w http.ResponseWriter, r *http.Request) {
	fmt.Println("getTranslationHotC")
	var link = r.PostFormValue("url")
	plugin, err := getPlugin(link)
	var translations = []Card{}

	if err != nil {
		fmt.Println(err)
	}

	cardsInfo, errGetCardDeckInfo := plugin.getCardDeckInfo(link)
	if errGetCardDeckInfo != nil {
		fmt.Println(errGetCardDeckInfo)
	}

	code := strings.Split(link, "/")
	filename := filepath.Join(plugin.name(), code[len(code)-1]+".json")

	if _, err := os.Stat(filename); err == nil {
		jsonFile, err := os.Open(filename)

		if err != nil {
			fmt.Println("file error:", err)
		}

		defer jsonFile.Close()

		bytesValue, _ := ioutil.ReadAll(jsonFile)

		json.Unmarshal(bytesValue, &translations)

	} else {
		translations = fetchTranslation(cardsInfo)

	}

	b, err := json.Marshal(translations)
	if err != nil {
		fmt.Println(err)
	}
	w.Write(b)
}

func cardimages(w http.ResponseWriter, r *http.Request) {
	var link = r.PostFormValue("url")
	var result = []string{}
	plugin, err := getPlugin(link)

	if err != nil {
		fmt.Println(err)
	}

	cardsInfo, errGetCardDeckInfo := plugin.getCardDeckInfo(link)

	if errGetCardDeckInfo != nil {
		fmt.Println(errGetCardDeckInfo)
	}

	for _, card := range cardsInfo {
		card, has := yytMap[card.ID]
		if has {
			result = append(result, card.URL)
		}
	}
	b, err := json.Marshal(result)

	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	w.Write(b)
}

func estimatePrice(w http.ResponseWriter, r *http.Request) {
	fmt.Println("estimatePrice")
	var decks = [][]Card{}
	var link = r.PostFormValue("url")
	plugin, err := getPlugin(link)

	if err != nil {
		fmt.Println(err)
	}

	decksInfo, errGetCardDeckInfo := plugin.getCardDecksInfoList(link)
	if errGetCardDeckInfo != nil {
		fmt.Println(errGetCardDeckInfo)
	}

	for _, deck := range decksInfo {
		var result = []Card{}
		var deckPrice int
		for _, card := range deck {
			var total = card.Amount * yytMap[card.ID].Price
			deckPrice = deckPrice + total
			card.URL = yytMap[card.ID].URL
			card.Price = yytMap[card.ID].Price
			card.CardURL = yytMap[card.ID].CardURL
			result = append(result, card)
		}
		result = append(result, Card{ID: "TOTAL", Price: deckPrice})
		decks = append(decks, result)
	}

	b, err := json.Marshal(decks)
	if err != nil {
		fmt.Println(err)
	}
	w.Write(b)
}

func exportcockatrice(w http.ResponseWriter, r *http.Request) {
	fmt.Println("exportcockatrice")
	var data = dataTemplate{}
	var b bytes.Buffer
	var link = r.PostFormValue("url")
	plugin, err := getPlugin(link)

	if err != nil {
		fmt.Println(err)
	}

	cardsInfo, errGetCardDeckInfo := plugin.getCardDeckInfo(link)

	if errGetCardDeckInfo != nil {
		fmt.Println(errGetCardDeckInfo)
	}

	data.Name = "ex"
	for _, card := range cardsInfo {
		var complete = yytMap[card.ID]
		complete.Amount = card.Amount
		complete.ID = strings.Replace(complete.ID, "/", "-", 1)
		if elem, ok := cockatricCXMap[complete.Rarity]; ok {
			complete.Rarity = elem
		}
		data.Cards = append(data.Cards, complete)
	}

	t, err := template.ParseFiles("./cockatrice_template.xml")
	if err != nil {
		log.Println(err)
	}

	t.Execute(&b, data)

	if err != nil {
		fmt.Println(err)
	}
	w.Write(b.Bytes())
}
func searchcards(w http.ResponseWriter, r *http.Request) {
	fmt.Println("searchcards")
	ID, ok := r.URL.Query()["id"]

	if !ok {
		http.Error(w, "ID is empty", http.StatusBadRequest)
		return
	}

	infos, exists := yytMap[ID[0]]
	if !exists {
		http.Error(w, fmt.Sprintf("%v does not exists", ID), http.StatusBadRequest)
	} else {
		b, err := json.Marshal(infos)
		if err != nil {
			fmt.Println(err)
		}
		w.Write(b)
	}
}

func cache(w http.ResponseWriter, r *http.Request) {
	fmt.Println("cache")
	var links = r.PostFormValue("decks")

	for _, link := range strings.Split(links, ",") {

		plugin, err := getPlugin(links)
		if err != nil {
			fmt.Println(err)
		}

		code := strings.Split(link, "/")
		filename := filepath.Join(plugin.name(), code[len(code)-1]+".json")
		os.MkdirAll(plugin.name(), 744)

		if infoStat, err := os.Stat(filename); err == nil && r.URL.Query().Get("force") != "true" {
			isGoodEnough := time.Now().Sub(infoStat.ModTime()).Hours() < cacheTime.Hours()
			if isGoodEnough {
				fmt.Printf("USe cache %v for code: %v\n", infoStat.ModTime(), code)
				continue
			}
		}

		cardsInfo, errGetCardDeckInfo := plugin.getCardDeckInfo(link)
		if errGetCardDeckInfo != nil {
			fmt.Println(errGetCardDeckInfo)
		}

		var buffer bytes.Buffer

		translation := fetchTranslation(cardsInfo)
		marsh, err := json.Marshal(translation)

		if err != nil {
			fmt.Println(err.Error())
			w.WriteHeader(500)
			break
		}

		out, err := os.Create(filename)
		if err != nil {
			log.Println("write error", err.Error())
			continue
		}
		json.Indent(&buffer, marsh, "", "\t")
		buffer.WriteTo(out)
		out.Close()

	}

	fmt.Println("end cache")

}
<commit_msg>Download img for cache<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"text/template"
	"time"

	"github.com/PuerkitoBio/goquery"
)

type dataTemplate struct {
	Name  string
	Cards []Card
}

type respMap struct {
	Resp *http.Response
	Card Card
}

var cockatricCXMap = map[string]string{
	"CR": "R",
	"CU": "U",
	"CC": "C",
}

const cacheTime = (time.Hour * 24) * 3

var findHotCImg = regexp.MustCompile(`/heart(.*).png`)

func getPlugin(url string) (plugin, error) {
	for _, plugin := range plugins {
		if plugin.isMine(url) {
			return plugin, nil
		}
	}

	return nil, fmt.Errorf("Url: (%v) not supported", url)
}

func fetchTranslation(cardsInfo []Card) []Card {
	translations := []Card{}

	for _, card := range cardsInfo {
		url := hoTcURL + card.ID + "&short=1"
		fmt.Println(url)
		doc, err := goquery.NewDocument(url)
		if err != nil {
			fmt.Println(err)
		}
		textHTML, err := doc.Find("body").Html()
		if err != nil {
			fmt.Println(err)
		}
		card.Translation = html.UnescapeString(textHTML)
		card.URL = yytMap[card.ID].URL

		translations = append(translations, card)
		time.Sleep(1 * time.Second)
	}

	return translations
}

func getTranslationHotC(w http.ResponseWriter, r *http.Request) {
	fmt.Println("getTranslationHotC")
	var link = r.PostFormValue("url")
	plugin, err := getPlugin(link)
	var translations = []Card{}

	if err != nil {
		fmt.Println(err)
	}

	cardsInfo, errGetCardDeckInfo := plugin.getCardDeckInfo(link)
	if errGetCardDeckInfo != nil {
		fmt.Println(errGetCardDeckInfo)
	}

	code := strings.Split(link, "/")
	filename := filepath.Join(plugin.name(), code[len(code)-1]+".json")

	if _, err := os.Stat(filename); err == nil {
		jsonFile, err := os.Open(filename)

		if err != nil {
			fmt.Println("file error:", err)
		}

		defer jsonFile.Close()

		bytesValue, _ := ioutil.ReadAll(jsonFile)

		json.Unmarshal(bytesValue, &translations)

	} else {
		translations = fetchTranslation(cardsInfo)

	}

	b, err := json.Marshal(translations)
	if err != nil {
		fmt.Println(err)
	}
	w.Write(b)
}

func cardimages(w http.ResponseWriter, r *http.Request) {
	var link = r.PostFormValue("url")
	var result = []string{}
	plugin, err := getPlugin(link)

	if err != nil {
		fmt.Println(err)
	}

	cardsInfo, errGetCardDeckInfo := plugin.getCardDeckInfo(link)

	if errGetCardDeckInfo != nil {
		fmt.Println(errGetCardDeckInfo)
	}

	for _, card := range cardsInfo {
		card, has := yytMap[card.ID]
		if has {
			result = append(result, card.URL)
		}
	}
	b, err := json.Marshal(result)

	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	w.Write(b)
}

func estimatePrice(w http.ResponseWriter, r *http.Request) {
	fmt.Println("estimatePrice")
	var decks = [][]Card{}
	var link = r.PostFormValue("url")
	plugin, err := getPlugin(link)

	if err != nil {
		fmt.Println(err)
	}

	decksInfo, errGetCardDeckInfo := plugin.getCardDecksInfoList(link)
	if errGetCardDeckInfo != nil {
		fmt.Println(errGetCardDeckInfo)
	}

	for _, deck := range decksInfo {
		var result = []Card{}
		var deckPrice int
		for _, card := range deck {
			var total = card.Amount * yytMap[card.ID].Price
			deckPrice = deckPrice + total
			card.URL = yytMap[card.ID].URL
			card.Price = yytMap[card.ID].Price
			card.CardURL = yytMap[card.ID].CardURL
			result = append(result, card)
		}
		result = append(result, Card{ID: "TOTAL", Price: deckPrice})
		decks = append(decks, result)
	}

	b, err := json.Marshal(decks)
	if err != nil {
		fmt.Println(err)
	}
	w.Write(b)
}

func exportcockatrice(w http.ResponseWriter, r *http.Request) {
	fmt.Println("exportcockatrice")
	var data = dataTemplate{}
	var b bytes.Buffer
	var link = r.PostFormValue("url")
	plugin, err := getPlugin(link)

	if err != nil {
		fmt.Println(err)
	}

	cardsInfo, errGetCardDeckInfo := plugin.getCardDeckInfo(link)

	if errGetCardDeckInfo != nil {
		fmt.Println(errGetCardDeckInfo)
	}

	data.Name = "ex"
	for _, card := range cardsInfo {
		var complete = yytMap[card.ID]
		complete.Amount = card.Amount
		complete.ID = strings.Replace(complete.ID, "/", "-", 1)
		if elem, ok := cockatricCXMap[complete.Rarity]; ok {
			complete.Rarity = elem
		}
		data.Cards = append(data.Cards, complete)
	}

	t, err := template.ParseFiles("./cockatrice_template.xml")
	if err != nil {
		log.Println(err)
	}

	t.Execute(&b, data)

	if err != nil {
		fmt.Println(err)
	}
	w.Write(b.Bytes())
}
func searchcards(w http.ResponseWriter, r *http.Request) {
	fmt.Println("searchcards")
	ID, ok := r.URL.Query()["id"]

	if !ok {
		http.Error(w, "ID is empty", http.StatusBadRequest)
		return
	}

	infos, exists := yytMap[ID[0]]
	if !exists {
		http.Error(w, fmt.Sprintf("%v does not exists", ID), http.StatusBadRequest)
	} else {
		b, err := json.Marshal(infos)
		if err != nil {
			fmt.Println(err)
		}
		w.Write(b)
	}
}

func cache(w http.ResponseWriter, r *http.Request) {
	fmt.Println("cache")
	var links = r.PostFormValue("decks")
	var wg sync.WaitGroup

	for _, link := range strings.Split(links, ",") {

		plugin, err := getPlugin(links)
		if err != nil {
			fmt.Println(err)
		}

		code := strings.Split(link, "/")
		folderpath := filepath.Join("cache", plugin.name(), code[len(code)-1])
		filename := filepath.Join(folderpath, "deck.json")
		os.MkdirAll(folderpath, 744)

		if infoStat, err := os.Stat(filename); err == nil && r.URL.Query().Get("force") != "true" {
			isGoodEnough := time.Now().Sub(infoStat.ModTime()).Hours() < cacheTime.Hours()
			if isGoodEnough {
				fmt.Printf("USe cache %v for code: %v\n", infoStat.ModTime(), code)
				continue
			}
		}

		cardsInfo, errGetCardDeckInfo := plugin.getCardDeckInfo(link)
		if errGetCardDeckInfo != nil {
			fmt.Println(errGetCardDeckInfo)
		}

		var buffer bytes.Buffer

		translation := fetchTranslation(cardsInfo)

		for i, card := range translation {
			wg.Add(1)
			imgPath := filepath.Join(folderpath, filepath.Base(card.URL))
			newPath := filepath.Join("https://proxyMaker.moe", imgPath)
			fetchImgURL := string(card.URL)

			translation[i].Translation = findHotCImg.ReplaceAllString(card.Translation, newPath)

			go func(imgPath string, imgURL string) {
				for {

					out, err := os.Create(imgPath)
					if err != nil {
						time.Sleep(time.Second * 1)
						continue
					}

					defer out.Close()
					log.Println("get :", imgURL)
					resp, err := http.Get(imgURL)
					if err != nil {
						log.Println("retry get : ", imgURL)
						time.Sleep(time.Second * 1)
						continue
					}
					defer resp.Body.Close()
					io.Copy(out, resp.Body)
					if err != nil {
						time.Sleep(time.Second * 1)
						continue
					}

					wg.Done()
					break
				}
			}(imgPath, fetchImgURL)
			translation[i].URL = newPath
		}
		wg.Wait()
		marsh, err := json.Marshal(translation)

		if err != nil {
			fmt.Println(err.Error())
			w.WriteHeader(500)
			break
		}

		out, err := os.Create(filename)
		if err != nil {
			log.Println("write error", err.Error())
			continue
		}
		json.Indent(&buffer, marsh, "", "\t")
		buffer.WriteTo(out)
		out.Close()

	}

	fmt.Println("end cache")

}
<|endoftext|>


<commit_before>package finto

import (
	"net/http"

	"github.com/gorilla/mux"
)

type fintoHandlerFunc func(fc *fintoContext) http.Handler

type Route struct {
	Handler fintoHandlerFunc
	Method  string
	Name    string
	Pattern string
}

type Routes []Route

var routes = Routes{
	Route{
		Handler: rolesList,
		Name:    "list-role",
		Method:  "GET",
		Pattern: "/roles",
	},
	Route{
		Handler: rolesSetActive,
		Name:    "set-active-role",
		Method:  "PUT",
		Pattern: "/roles",
	},
	Route{
		Handler: rolesShow,
		Name:    "show-role",
		Method:  "GET",
		Pattern: "/roles/{alias}",
	},
	Route{
		Handler: mockProfileCreds,
		Name:    "get-role-credentials",
		Method:  "GET",
		Pattern: "/roles/{alias}/credentials",
	},
	Route{
		Handler: mockProfile,
		Name:    "metadata-iam-secreds",
		Method:  "GET",
		Pattern: "/latest/meta-data/iam/security-credentials/",
	},
	Route{
		Handler: mockProfileCreds,
		Name:    "metadata-iam-secreds-role",
		Method:  "GET",
		Pattern: "/latest/meta-data/iam/security-credentials/{alias}",
	},
}

func FintoRouter(fc *fintoContext) *mux.Router {
	router := mux.NewRouter()

	for _, route := range routes {
		router.
			Methods(route.Method).
			Name(route.Name).
			Path(route.Pattern).
			Handler(route.Handler(fc))
	}

	return router
}
<commit_msg>Enable strict slash<commit_after>package finto

import (
	"net/http"

	"github.com/gorilla/mux"
)

type fintoHandlerFunc func(fc *fintoContext) http.Handler

type Route struct {
	Handler fintoHandlerFunc
	Method  string
	Name    string
	Pattern string
}

type Routes []Route

var routes = Routes{
	Route{
		Handler: rolesList,
		Name:    "list-role",
		Method:  "GET",
		Pattern: "/roles",
	},
	Route{
		Handler: rolesSetActive,
		Name:    "set-active-role",
		Method:  "PUT",
		Pattern: "/roles",
	},
	Route{
		Handler: rolesShow,
		Name:    "show-role",
		Method:  "GET",
		Pattern: "/roles/{alias}",
	},
	Route{
		Handler: mockProfileCreds,
		Name:    "get-role-credentials",
		Method:  "GET",
		Pattern: "/roles/{alias}/credentials",
	},
	Route{
		Handler: mockProfile,
		Name:    "metadata-iam-secreds",
		Method:  "GET",
		Pattern: "/latest/meta-data/iam/security-credentials/",
	},
	Route{
		Handler: mockProfileCreds,
		Name:    "metadata-iam-secreds-role",
		Method:  "GET",
		Pattern: "/latest/meta-data/iam/security-credentials/{alias}",
	},
}

func FintoRouter(fc *fintoContext) *mux.Router {
	router := mux.NewRouter().StrictSlash(true)

	for _, route := range routes {
		router.
			Methods(route.Method).
			Name(route.Name).
			Path(route.Pattern).
			Handler(route.Handler(fc))
	}

	return router
}
<|endoftext|>


<commit_before>package gochecks

import (
	"fmt"
	"log"

	"encoding/json"

	"github.com/aleasoluciones/simpleamqp"
	"github.com/bigdatadev/goryman"
)

// CheckPublisher define the check result Publisher
type CheckPublisher interface {
	PublishCheckResult(Event)
}

// LogPublisher object to log each check result
type LogPublisher struct {
}

// NewLogPublisher return a new LogPublisher
func NewLogPublisher() LogPublisher {
	return LogPublisher{}
}

func (p LogPublisher) PublishCheckResult(event Event) {
	log.Println(event)
}

type RabbitMqPublisher struct {
	publisher *simpleamqp.AmqpPublisher
}

// NewRabbitMqPublisher return a publisher to send to RabbitMq exchange
func NewRabbitMqPublisher(amqpuri, exchange string) RabbitMqPublisher {
	p := RabbitMqPublisher{simpleamqp.NewAmqpPublisher(amqpuri, exchange)}
	return p
}

func (p RabbitMqPublisher) PublishCheckResult(event Event) {
	topic := fmt.Sprintf("check.%s.%s", event.Host, event.Service)
	serialized, _ := json.Marshal(event)
	p.publisher.Publish(topic, serialized)
}

type RiemannPublisher struct {
	client *goryman.GorymanClient
}

// NewRiemannPublisher return a publisher to send directly to a riemann instance
func NewRiemannPublisher(addr string) RiemannPublisher {
	p := RiemannPublisher{goryman.NewGorymanClient(addr)}
	return p
}

// PublishCheckResult return a publisher to send directly to a riemann instance
func (p RiemannPublisher) PublishCheckResult(event Event) {
	err := p.client.Connect()
	if err != nil {
		log.Println("[error] publishing check", event)
		return
	}
	defer p.client.Close()
	riemannEvent := goryman.Event{Description: event.Description, Host: event.Host, Service: event.Service, State: event.State, Metric: event.Metric, Tags: event.Tags, Attributes: event.Attributes, Ttl: event.TTL}

	err = p.client.SendEvent(&riemannEvent)
	if err != nil {
		log.Println("[error] sending check", event)
		return
	}
}
<commit_msg>Added some docs<commit_after>package gochecks

import (
	"fmt"
	"log"

	"encoding/json"

	"github.com/aleasoluciones/simpleamqp"
	"github.com/bigdatadev/goryman"
)

// CheckPublisher define the check result Publisher
type CheckPublisher interface {
	PublishCheckResult(Event)
}

// LogPublisher object to log each check result
type LogPublisher struct {
}

// NewLogPublisher return a new LogPublisher
func NewLogPublisher() LogPublisher {
	return LogPublisher{}
}

// PublishCheckResult log the event
func (p LogPublisher) PublishCheckResult(event Event) {
	log.Println(event)
}

// RabbitMqPublisher object to publish the event to a rabbitmq exchange
type RabbitMqPublisher struct {
	publisher *simpleamqp.AmqpPublisher
}

// NewRabbitMqPublisher return a publisher to send to RabbitMq exchange
func NewRabbitMqPublisher(amqpuri, exchange string) RabbitMqPublisher {
	p := RabbitMqPublisher{simpleamqp.NewAmqpPublisher(amqpuri, exchange)}
	return p
}

// PublishCheckResult publish the event to a configured rabbitmq exchange
func (p RabbitMqPublisher) PublishCheckResult(event Event) {
	topic := fmt.Sprintf("check.%s.%s", event.Host, event.Service)
	serialized, _ := json.Marshal(event)
	p.publisher.Publish(topic, serialized)
}

// RiemannPublisher object to publish events to a riemann server
type RiemannPublisher struct {
	client *goryman.GorymanClient
}

// NewRiemannPublisher return a publisher to send directly to a riemann instance
func NewRiemannPublisher(addr string) RiemannPublisher {
	p := RiemannPublisher{goryman.NewGorymanClient(addr)}
	return p
}

// PublishCheckResult return a publisher to send directly to a riemann instance
func (p RiemannPublisher) PublishCheckResult(event Event) {
	err := p.client.Connect()
	if err != nil {
		log.Println("[error] publishing check", event)
		return
	}
	defer p.client.Close()
	riemannEvent := goryman.Event{Description: event.Description, Host: event.Host, Service: event.Service, State: event.State, Metric: event.Metric, Tags: event.Tags, Attributes: event.Attributes, Ttl: event.TTL}

	err = p.client.SendEvent(&riemannEvent)
	if err != nil {
		log.Println("[error] sending check", event)
		return
	}
}
<|endoftext|>


<commit_before>package particles

import (
	"reflect"

	"github.com/hAWKdv/go-gravity/vectors/forces"
	"github.com/hAWKdv/go-gravity/vectors/vectors"
)

// Conf represents the configuration structure of a particle system
type Conf struct {
	continious bool
	location   *vectors.Vector
	container  *vectors.Vector
}

// ParticleSystem describes a set a of particles
type ParticleSystem struct {
	particles []*Particle
	conf      *Conf
	gravity   *forces.Gravity
}

// NewConf creates a configuration object for a particle system
func NewConf(continious bool, location, container *vectors.Vector) *Conf {
	return &Conf{continious, location, container}
}

// NewParticleSystem creates an object of type ParticleSystem (constructor)
func NewParticleSystem(objs interface{}, conf *Conf) *ParticleSystem {
	var particles []*Particle

	if reflect.TypeOf(objs).Kind() == reflect.Slice {
		s := reflect.ValueOf(objs)

		for i := 0; i < s.Len(); i++ {
			mover := vectors.NewMover(s.Index(i).Interface(), conf.location.Copy(), conf.container)
			particles = append(particles, NewParticle(mover))
		}
	}

	return &ParticleSystem{particles, conf, forces.CreateGravity()}
}

// UpdateSystem is a genetic method for updating particles in the system
func (ps *ParticleSystem) UpdateSystem(update func(p *Particle)) {
	for _, particle := range ps.particles {
		ps.applyForces(particle)
		// todo run in go routine
		update(particle)
		particle.mover.BounceOff()

		if !ps.conf.continious {
			if particle.lifespan > 0 {
				particle.lifespan--
			} else {
				// to do remove particle
			}
		}
	}
}

func (ps *ParticleSystem) applyForces(p *Particle) {
	p.mover.ApplyForce(ps.gravity.GetForce())
	p.mover.ApplyForce(p.friction.GetForce())
	p.mover.ApplyForce(p.push.GetForce())
}
<commit_msg>Run particle update in go routines<commit_after>package particles

import (
	"reflect"

	"sync"

	"github.com/hAWKdv/go-gravity/vectors/forces"
	"github.com/hAWKdv/go-gravity/vectors/vectors"
)

// Conf represents the configuration structure of a particle system
type Conf struct {
	continious bool
	location   *vectors.Vector
	container  *vectors.Vector
}

// ParticleSystem describes a set a of particles
type ParticleSystem struct {
	particles []*Particle
	conf      *Conf
	gravity   *forces.Gravity
}

// NewConf creates a configuration object for a particle system
func NewConf(continious bool, location, container *vectors.Vector) *Conf {
	return &Conf{continious, location, container}
}

// NewParticleSystem creates an object of type ParticleSystem (constructor)
func NewParticleSystem(objs interface{}, conf *Conf) *ParticleSystem {
	var particles []*Particle

	if reflect.TypeOf(objs).Kind() == reflect.Slice {
		s := reflect.ValueOf(objs)

		for i := 0; i < s.Len(); i++ {
			mover := vectors.NewMover(s.Index(i).Interface(), conf.location.Copy(), conf.container)
			particles = append(particles, NewParticle(mover))
		}
	}

	return &ParticleSystem{particles, conf, forces.CreateGravity()}
}

// UpdateSystem is a genetic method for updating particles in the system
func (ps *ParticleSystem) UpdateSystem(update func(p *Particle)) {
	wg := sync.WaitGroup{}

	for _, particle := range ps.particles {
		wg.Add(1)

		go func(particle *Particle) {
			ps.applyForces(particle)
			// todo run in go routine
			update(particle)
			particle.mover.BounceOff()

			if !ps.conf.continious {
				if particle.lifespan > 0 {
					particle.lifespan--
				} else {
					// to do remove particle
				}
			}
			wg.Done()
		}(particle)
	}

	wg.Wait()
}

func (ps *ParticleSystem) applyForces(p *Particle) {
	p.mover.ApplyForce(ps.gravity.GetForce())
	p.mover.ApplyForce(p.friction.GetForce())
	p.mover.ApplyForce(p.push.GetForce())
}
<|endoftext|>


<commit_before>package sparta

import (
	"fmt"
	"strings"

	_ "github.com/aws/aws-lambda-go/lambda"        // Force dep to resolve
	_ "github.com/aws/aws-lambda-go/lambdacontext" // Force dep to resolve
)

////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////

const (
	// ProperName is the DRY name definition
	ProperName = "Sparta"
)
const (
	// SpartaVersion defines the current Sparta release
	SpartaVersion = "1.6.0"
	// GoLambdaVersion is the Go version runtime used for the lambda function
	GoLambdaVersion = "go1.x"
)

var (
	// SpartaBinaryName is binary name that exposes the Go lambda function
	SpartaBinaryName = fmt.Sprintf("%s.lambda.amd64", ProperName)
)

const (
	// Custom Resource typename used to create new cloudFormationUserDefinedFunctionCustomResource
	cloudFormationLambda = "Custom::SpartaLambdaCustomResource"
	// divider length is the length of a divider in the text
	// based CLI output
	dividerLength = 48
)
const (
	// envVarLogLevel is the provision time debug value
	// carried into the execution environment
	envVarLogLevel = "SPARTA_LOG_LEVEL"
	// spartaEnvVarFunctionName is the name of this function in the
	// map. It's the function that will be registered to run
	// envVarFunctionName = "SPARTA_FUNC_NAME"
	// envVarDiscoveryInformation is the name of the discovery information
	// published into the environment
	envVarDiscoveryInformation = "SPARTA_DISCOVERY_INFO"
)

var (
	// internal logging header
	headerDivider = strings.Repeat("═", dividerLength)
)

// AWS Principal ARNs from http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
// See also
// http://docs.aws.amazon.com/general/latest/gr/rande.html
// for region specific principal names
const (
	// @enum AWSPrincipal
	APIGatewayPrincipal = "apigateway.amazonaws.com"
	// @enum AWSPrincipal
	CloudWatchEventsPrincipal = "events.amazonaws.com"
	// @enum AWSPrincipal
	SESPrincipal = "ses.amazonaws.com"
	// @enum AWSPrincipal
	SNSPrincipal = "sns.amazonaws.com"
	// @enum AWSPrincipal
	EC2Principal = "ec2.amazonaws.com"
	// @enum AWSPrincipal
	LambdaPrincipal = "lambda.amazonaws.com"
)

type contextKey int

const (
	// ContextKeyLogger is the request-independent *logrus.Logger
	// instance common to all requests
	ContextKeyLogger contextKey = iota
	// ContextKeyRequestLogger is the *logrus.Entry instance
	// that is annotated with request-identifying
	// information extracted from the AWS context object
	ContextKeyRequestLogger
	// ContextKeyLambdaContext is the *sparta.LambdaContext
	// pointer in the request
	// DEPRECATED
	ContextKeyLambdaContext
	// ContextKeyLambdaError is the possible error that was returned
	// from the lambda function
	ContextKeyLambdaError
	// ContextKeyLambdaResponse is the possible response that
	// was returned from the lambda function
	ContextKeyLambdaResponse
)

const (
	// ContextKeyLambdaVersions is the key in the context that stores the map
	// of autoincrementing versions
	ContextKeyLambdaVersions = "spartaLambdaVersions"
)
<commit_msg>Update Sparta version<commit_after>package sparta

import (
	"fmt"
	"strings"

	_ "github.com/aws/aws-lambda-go/lambda"        // Force dep to resolve
	_ "github.com/aws/aws-lambda-go/lambdacontext" // Force dep to resolve
)

////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////

const (
	// ProperName is the DRY name definition
	ProperName = "Sparta"
)
const (
	// SpartaVersion defines the current Sparta release
	SpartaVersion = "1.7.1"
	// GoLambdaVersion is the Go version runtime used for the lambda function
	GoLambdaVersion = "go1.x"
)

var (
	// SpartaBinaryName is binary name that exposes the Go lambda function
	SpartaBinaryName = fmt.Sprintf("%s.lambda.amd64", ProperName)
)

const (
	// Custom Resource typename used to create new cloudFormationUserDefinedFunctionCustomResource
	cloudFormationLambda = "Custom::SpartaLambdaCustomResource"
	// divider length is the length of a divider in the text
	// based CLI output
	dividerLength = 48
)
const (
	// envVarLogLevel is the provision time debug value
	// carried into the execution environment
	envVarLogLevel = "SPARTA_LOG_LEVEL"
	// spartaEnvVarFunctionName is the name of this function in the
	// map. It's the function that will be registered to run
	// envVarFunctionName = "SPARTA_FUNC_NAME"
	// envVarDiscoveryInformation is the name of the discovery information
	// published into the environment
	envVarDiscoveryInformation = "SPARTA_DISCOVERY_INFO"
)

var (
	// internal logging header
	headerDivider = strings.Repeat("═", dividerLength)
)

// AWS Principal ARNs from http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
// See also
// http://docs.aws.amazon.com/general/latest/gr/rande.html
// for region specific principal names
const (
	// @enum AWSPrincipal
	APIGatewayPrincipal = "apigateway.amazonaws.com"
	// @enum AWSPrincipal
	CloudWatchEventsPrincipal = "events.amazonaws.com"
	// @enum AWSPrincipal
	SESPrincipal = "ses.amazonaws.com"
	// @enum AWSPrincipal
	SNSPrincipal = "sns.amazonaws.com"
	// @enum AWSPrincipal
	EC2Principal = "ec2.amazonaws.com"
	// @enum AWSPrincipal
	LambdaPrincipal = "lambda.amazonaws.com"
)

type contextKey int

const (
	// ContextKeyLogger is the request-independent *logrus.Logger
	// instance common to all requests
	ContextKeyLogger contextKey = iota
	// ContextKeyRequestLogger is the *logrus.Entry instance
	// that is annotated with request-identifying
	// information extracted from the AWS context object
	ContextKeyRequestLogger
	// ContextKeyLambdaContext is the *sparta.LambdaContext
	// pointer in the request
	// DEPRECATED
	ContextKeyLambdaContext
	// ContextKeyLambdaError is the possible error that was returned
	// from the lambda function
	ContextKeyLambdaError
	// ContextKeyLambdaResponse is the possible response that
	// was returned from the lambda function
	ContextKeyLambdaResponse
)

const (
	// ContextKeyLambdaVersions is the key in the context that stores the map
	// of autoincrementing versions
	ContextKeyLambdaVersions = "spartaLambdaVersions"
)
<|endoftext|>


<commit_before>package svgutil

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/rustyoz/svg"
)

func ReadFile(filename, name string, scale float64) (*svg.Svg, error) {
	// https://godoc.org/github.com/rustyoz/svg#Svg
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	name = strings.TrimSpace(name)
	if len(name) == 0 {
		name = filename
	}

	return svg.ParseSvgFromReader(file, name, scale)
}

func AspectRatio(img *svg.Svg) (float64, error) {
	if img == nil {
		return 0, errors.New("E_NO_IMAGE")
	}
	vals, err := img.ViewBoxValues()
	if err != nil {
		return 0, err
	}
	if len(vals) == 2 {
		if vals[0] == 0 {
			return 0, errors.New("E_DENOM_HEIGHT==0")
		}
		return vals[1] / vals[0], nil
	} else if len(vals) == 4 {
		w := vals[2] - vals[0]
		h := vals[3] - vals[1]
		if h == 0 {
			return 0, errors.New("E_DENOM_HEIGHT==0")
		}
		return w / h, nil
	}
	return 0, fmt.Errorf("E_BAD_VIEWBOX_LEN [%v]", len(vals))
}
<commit_msg>lint: image/svgutil: less errorprone var names<commit_after>package svgutil

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/rustyoz/svg"
)

func ReadFile(filename, name string, scale float64) (*svg.Svg, error) {
	// https://godoc.org/github.com/rustyoz/svg#Svg
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	name = strings.TrimSpace(name)
	if len(name) == 0 {
		name = filename
	}

	return svg.ParseSvgFromReader(file, name, scale)
}

func AspectRatio(img *svg.Svg) (float64, error) {
	if img == nil {
		return 0, errors.New("E_NO_IMAGE")
	}
	vals, err := img.ViewBoxValues()
	if err != nil {
		return 0, err
	}
	if len(vals) == 2 {
		if vals[0] == 0 {
			return 0, errors.New("E_DENOM_HEIGHT==0")
		}
		return vals[1] / vals[0], nil
	} else if len(vals) == 4 {
		width := vals[2] - vals[0]
		height := vals[3] - vals[1]
		if height == 0 {
			return 0, errors.New("E_DENOM_HEIGHT==0")
		}
		return width / height, nil
	}
	return 0, fmt.Errorf("E_BAD_VIEWBOX_LEN [%v]", len(vals))
}
<|endoftext|>


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

package pzse

import (
	"fmt"
	"net/http"
	"os/exec"
	"regexp"
	"strings"

	"github.com/venicegeo/pzsvc-exec/pzsvc"
)

func handleFList(s pzsvc.Session, fList, nameList []string, lFunc rangeFunc, fType, action string, output *OutStruct, fileRec map[string]string) {
	re := regexp.MustCompile(`^[\w\-\.]*$`)
	for i, f := range fList {
		name := ""
		if len(nameList) > i {
			name = nameList[i]
		}
		if !re.Match([]byte(name)) {
			pzsvc.LogAlert(s, `Illegal filename "`+name+`" entered for `+action+`.  Possible attempted security breach.`)
			addOutputError(output, `handleFlist error: Filename "`+name+`" contains illegal characters and is not permitted.`, http.StatusBadRequest)
			continue
		}
		outStr, err := lFunc(f, name, fType)
		if err != nil {
			addOutputError(output, "Error in "+action+" of "+name+".", http.StatusBadRequest)
		} else if outStr == "" {
			pzsvc.LogSimpleErr(s, `handleFlist error: type "`+fType+`", input "`+f+`" blank result.`, nil)
			addOutputError(output, "Blank Result Error in "+action+" of "+name+".", http.StatusBadRequest)
		} else {
			fileRec[f] = outStr
		}
	}
}

func addOutputError(output *OutStruct, errString string, httpStat int) {
	output.Errors = append(output.Errors, errString)
	output.HTTPStatus = httpStat
}

func splitOrNil(inString, knife string) []string {
	if inString == "" {
		return nil
	}
	return strings.Split(inString, knife)
}

// GetVersion spits out the best available version for the
// current software, based on the contents fo the config file
func GetVersion(s pzsvc.Session, configObj *ConfigType) string {
	vCmdSlice := splitOrNil(configObj.VersionCmd, " ")
	if vCmdSlice != nil {
		vCmd := exec.Command(vCmdSlice[0], vCmdSlice[1:]...)
		verB, err := vCmd.Output()
		pzsvc.LogInfo(s, `Called VersionCmd `+configObj.VersionCmd+`.  Results: `+string(verB))
		if err != nil {
			pzsvc.LogSimpleErr(s, "VersionCmd failed: ", err)
		}
		if string(verB) != "" {
			return string(verB)
		}
	}
	return configObj.VersionStr
}

// CheckConfig takes an input config file, checks it over for issues,
// and outputs any issues or concerns to std.out.  It returns whether
// or not the config file permits autoregistration.
func CheckConfig(s pzsvc.Session, configObj *ConfigType) bool {
	canReg := true
	canPzFile := configObj.CanUpload || configObj.CanDownlPz
	if configObj.CliCmd == "" {
		pzsvc.LogAlert(s, `Config: Warning: CliCmd is blank.  This is a major security vulnerability.`)
	}

	if configObj.PzAddr == "" && configObj.PzAddrEnVar == "" {
		errStr := `Config: Did not specify PzAddr or PzAddrEnVar.  Autoregistration disabled.`
		if canPzFile {
			errStr += `  Client will have to provide Piazza Address for uploads and Piazza downloads.`
		}
		pzsvc.LogInfo(s, errStr)
		canReg = false
	} else if configObj.APIKeyEnVar == "" {
		errStr := `Config: APIKeyEnVar was not specified.  Autoregistration disabled.`
		if canPzFile {
			errStr += `  Client will have to provide authKey for uploads and Piazza downloads.`
		}
		pzsvc.LogInfo(s, errStr)
		canReg = false
	} else if configObj.SvcName == "" {
		pzsvc.LogInfo(s, `Config: SvcName not specified.  Autoregistration disabled.`)
		canReg = false
	} else if configObj.URL == "" && configObj.RegForTaskMgr == false {
		pzsvc.LogInfo(s, `Config: URL not specified.  URL required unless registering for task manager.  Autoregistration disabled.`)
		canReg = false
	} else if configObj.RegForTaskMgr && configObj.MaxRunTime == 0 {
		pzsvc.LogInfo(s, `Config: Cannot register for task manager use without MaxRunTime (in seconds).  Registration disabled.`)
		canReg = false
	}

	if !canReg {
		if configObj.VersionCmd != "" {
			pzsvc.LogInfo(s, `Config: VersionCmd was specified, but is much less useful without autoregistration.`)
		}
		if configObj.VersionStr != "" {
			pzsvc.LogInfo(s, `Config: VersionStr was specified, but is much less useful without without autoregistration.`)
		}
		if configObj.APIKeyEnVar != "" {
			if canPzFile {
				pzsvc.LogInfo(s, `Config: APIKeyEnVar was specified, but PzAddr was not.  APIKeyEnVar useless without a Pz instance to authenticate against.`)
			} else {
				pzsvc.LogInfo(s, `Config: APIKeyEnVar was specified, but is meaningless without autoregistration or Pz file interactions.`)
			}
		}
		if configObj.SvcName != "" {
			pzsvc.LogInfo(s, `Config: SvcName was specified, but is meaningless without autoregistration.`)
		}
		if configObj.URL != "" {
			pzsvc.LogInfo(s, `Config: URL was specified, but is meaningless without autoregistration.`)
		}
		if configObj.RegForTaskMgr {
			pzsvc.LogInfo(s, `Config: RegForTaskMgr was specified as true, but is meaningless without autoregistration.`)
		}
		if configObj.MaxRunTime == 0 {
			pzsvc.LogInfo(s, `Config: MaxRunTime was specified, but is meaningless without autoregistration.`)
		}
	} else {
		if configObj.PzAddr == "" && configObj.PzAddrEnVar == "" {
			pzsvc.LogInfo(s, `Config: Both PzAddr and PzAddrEnVar were specified.  Redundant.  Default to PzAddrEnVar.`)
		}
		if configObj.VersionCmd == "" && configObj.VersionStr == "" {
			pzsvc.LogInfo(s, `Config: Neither VersionCmd nor VersionStr were specified.  Version will be left blank.`)
		}
		if configObj.VersionCmd != "" && configObj.VersionStr != "" {
			pzsvc.LogInfo(s, `Config: Both VersionCmd and VersionStr were specified.  Redundant.  Default to VersionCmd.`)
		}
		if configObj.Description == "" {
			pzsvc.LogInfo(s, `Config: Description not specified.  When autoregistering, descriptions are strongly encouraged.`)
		}
		if configObj.MaxRunTime != 0 && !configObj.RegForTaskMgr {
			pzsvc.LogInfo(s, `Config: MaxRunTime not meaningful unless registering for task manager use.`)
		}

	}

	if configObj.Port <= 0 && configObj.PortEnVar == "" {
		pzsvc.LogInfo(s, `Config: Neither Port nor PortEnVar were properly specified.  Default to Port 8080.`)
	}
	if configObj.Port > 0 && configObj.PortEnVar != "" {
		pzsvc.LogInfo(s, `Config: Both Port and PortEnVar were specified.  Redundant.  Default to PortEnVar.`)
	}

	return canReg
}

// PrintHelp prints out a basic helpfile to make things easier on direct users
func PrintHelp(w http.ResponseWriter) {
	fmt.Fprintln(w, `The pzsvc-exec service endpoints are as follows:`)
	fmt.Fprintln(w, `- '/': entry point.  Displays base command if any, and suggests other endpoints.`)
	fmt.Fprintln(w, `- '/execute': The meat of the program.  Downloads files, executes on them, and uploads the results.`)
	fmt.Fprintln(w, `See the Service Request Format section of the Readme for interface details.`)
	fmt.Fprintln(w, `(Readme available at https://github.com/venicegeo/pzsvc-exec).`)
	fmt.Fprintln(w, `- '/description': When enabled, provides a description of this particular pzsvc-exec instance.`)
	fmt.Fprintln(w, `- '/attributes': When enabled, provides a list of key/value attributes for this pzsvc-exec instance.`)
	fmt.Fprintln(w, `- '/version': When enabled, provides version number for the application served by this pzsvc-exec instance.`)
	fmt.Fprintln(w, `- '/help': This screen.`)
}
<commit_msg>updatign versioncmd handler<commit_after>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pzse

import (
	"fmt"
	"net/http"
	"os/exec"
	"regexp"
	"strings"

	"github.com/venicegeo/pzsvc-exec/pzsvc"
)

func handleFList(s pzsvc.Session, fList, nameList []string, lFunc rangeFunc, fType, action string, output *OutStruct, fileRec map[string]string) {
	re := regexp.MustCompile(`^[\w\-\.]*$`)
	for i, f := range fList {
		name := ""
		if len(nameList) > i {
			name = nameList[i]
		}
		if !re.Match([]byte(name)) {
			pzsvc.LogAlert(s, `Illegal filename "`+name+`" entered for `+action+`.  Possible attempted security breach.`)
			addOutputError(output, `handleFlist error: Filename "`+name+`" contains illegal characters and is not permitted.`, http.StatusBadRequest)
			continue
		}
		outStr, err := lFunc(f, name, fType)
		if err != nil {
			addOutputError(output, "Error in "+action+" of "+name+".", http.StatusBadRequest)
		} else if outStr == "" {
			pzsvc.LogSimpleErr(s, `handleFlist error: type "`+fType+`", input "`+f+`" blank result.`, nil)
			addOutputError(output, "Blank Result Error in "+action+" of "+name+".", http.StatusBadRequest)
		} else {
			fileRec[f] = outStr
		}
	}
}

func addOutputError(output *OutStruct, errString string, httpStat int) {
	output.Errors = append(output.Errors, errString)
	output.HTTPStatus = httpStat
}

func splitOrNil(inString, knife string) []string {
	if inString == "" {
		return nil
	}
	return strings.Split(inString, knife)
}

// GetVersion spits out the best available version for the
// current software, based on the contents fo the config file
func GetVersion(s pzsvc.Session, configObj *ConfigType) string {
	vCmdSlice := splitOrNil(configObj.VersionCmd, " ")
	if vCmdSlice != nil {
		vCmd := exec.Command(vCmdSlice[0], vCmdSlice[1:]...)

		// if stdout exists, get that.
		// if it doesn't, and there wasnt' an error, and stderr exists, get that.
		// trim leading/trailign whitespace regardless

		verB, err := vCmd.CombinedOutput()
		pzsvc.LogInfo(s, `Called VersionCmd `+configObj.VersionCmd+`.  Results: `+string(verB))
		if err != nil {
			pzsvc.LogSimpleErr(s, "VersionCmd failed: ", err)
		}
		if string(verB) != "" {
			return string(verB)
		}
	}
	return configObj.VersionStr
}

// CheckConfig takes an input config file, checks it over for issues,
// and outputs any issues or concerns to std.out.  It returns whether
// or not the config file permits autoregistration.
func CheckConfig(s pzsvc.Session, configObj *ConfigType) bool {
	canReg := true
	canPzFile := configObj.CanUpload || configObj.CanDownlPz
	if configObj.CliCmd == "" {
		pzsvc.LogAlert(s, `Config: Warning: CliCmd is blank.  This is a major security vulnerability.`)
	}

	if configObj.PzAddr == "" && configObj.PzAddrEnVar == "" {
		errStr := `Config: Did not specify PzAddr or PzAddrEnVar.  Autoregistration disabled.`
		if canPzFile {
			errStr += `  Client will have to provide Piazza Address for uploads and Piazza downloads.`
		}
		pzsvc.LogInfo(s, errStr)
		canReg = false
	} else if configObj.APIKeyEnVar == "" {
		errStr := `Config: APIKeyEnVar was not specified.  Autoregistration disabled.`
		if canPzFile {
			errStr += `  Client will have to provide authKey for uploads and Piazza downloads.`
		}
		pzsvc.LogInfo(s, errStr)
		canReg = false
	} else if configObj.SvcName == "" {
		pzsvc.LogInfo(s, `Config: SvcName not specified.  Autoregistration disabled.`)
		canReg = false
	} else if configObj.URL == "" && configObj.RegForTaskMgr == false {
		pzsvc.LogInfo(s, `Config: URL not specified.  URL required unless registering for task manager.  Autoregistration disabled.`)
		canReg = false
	} else if configObj.RegForTaskMgr && configObj.MaxRunTime == 0 {
		pzsvc.LogInfo(s, `Config: Cannot register for task manager use without MaxRunTime (in seconds).  Registration disabled.`)
		canReg = false
	}

	if !canReg {
		if configObj.VersionCmd != "" {
			pzsvc.LogInfo(s, `Config: VersionCmd was specified, but is much less useful without autoregistration.`)
		}
		if configObj.VersionStr != "" {
			pzsvc.LogInfo(s, `Config: VersionStr was specified, but is much less useful without without autoregistration.`)
		}
		if configObj.APIKeyEnVar != "" {
			if canPzFile {
				pzsvc.LogInfo(s, `Config: APIKeyEnVar was specified, but PzAddr was not.  APIKeyEnVar useless without a Pz instance to authenticate against.`)
			} else {
				pzsvc.LogInfo(s, `Config: APIKeyEnVar was specified, but is meaningless without autoregistration or Pz file interactions.`)
			}
		}
		if configObj.SvcName != "" {
			pzsvc.LogInfo(s, `Config: SvcName was specified, but is meaningless without autoregistration.`)
		}
		if configObj.URL != "" {
			pzsvc.LogInfo(s, `Config: URL was specified, but is meaningless without autoregistration.`)
		}
		if configObj.RegForTaskMgr {
			pzsvc.LogInfo(s, `Config: RegForTaskMgr was specified as true, but is meaningless without autoregistration.`)
		}
		if configObj.MaxRunTime == 0 {
			pzsvc.LogInfo(s, `Config: MaxRunTime was specified, but is meaningless without autoregistration.`)
		}
	} else {
		if configObj.PzAddr == "" && configObj.PzAddrEnVar == "" {
			pzsvc.LogInfo(s, `Config: Both PzAddr and PzAddrEnVar were specified.  Redundant.  Default to PzAddrEnVar.`)
		}
		if configObj.VersionCmd == "" && configObj.VersionStr == "" {
			pzsvc.LogInfo(s, `Config: Neither VersionCmd nor VersionStr were specified.  Version will be left blank.`)
		}
		if configObj.VersionCmd != "" && configObj.VersionStr != "" {
			pzsvc.LogInfo(s, `Config: Both VersionCmd and VersionStr were specified.  Redundant.  Default to VersionCmd.`)
		}
		if configObj.Description == "" {
			pzsvc.LogInfo(s, `Config: Description not specified.  When autoregistering, descriptions are strongly encouraged.`)
		}
		if configObj.MaxRunTime != 0 && !configObj.RegForTaskMgr {
			pzsvc.LogInfo(s, `Config: MaxRunTime not meaningful unless registering for task manager use.`)
		}

	}

	if configObj.Port <= 0 && configObj.PortEnVar == "" {
		pzsvc.LogInfo(s, `Config: Neither Port nor PortEnVar were properly specified.  Default to Port 8080.`)
	}
	if configObj.Port > 0 && configObj.PortEnVar != "" {
		pzsvc.LogInfo(s, `Config: Both Port and PortEnVar were specified.  Redundant.  Default to PortEnVar.`)
	}

	return canReg
}

// PrintHelp prints out a basic helpfile to make things easier on direct users
func PrintHelp(w http.ResponseWriter) {
	fmt.Fprintln(w, `The pzsvc-exec service endpoints are as follows:`)
	fmt.Fprintln(w, `- '/': entry point.  Displays base command if any, and suggests other endpoints.`)
	fmt.Fprintln(w, `- '/execute': The meat of the program.  Downloads files, executes on them, and uploads the results.`)
	fmt.Fprintln(w, `See the Service Request Format section of the Readme for interface details.`)
	fmt.Fprintln(w, `(Readme available at https://github.com/venicegeo/pzsvc-exec).`)
	fmt.Fprintln(w, `- '/description': When enabled, provides a description of this particular pzsvc-exec instance.`)
	fmt.Fprintln(w, `- '/attributes': When enabled, provides a list of key/value attributes for this pzsvc-exec instance.`)
	fmt.Fprintln(w, `- '/version': When enabled, provides version number for the application served by this pzsvc-exec instance.`)
	fmt.Fprintln(w, `- '/help': This screen.`)
}
<|endoftext|>


<commit_before>package quad

import (
	"crypto/sha1"
	"hash"
	"strconv"
	"strings"
	"sync"
	"time"
)

// Value is a type used by all quad directions.
type Value interface {
	String() string
	// Native converts Value to a closest native Go type.
	//
	// If type has no analogs in Go, Native return an object itself.
	Native() interface{}
}

type TypedStringer interface {
	TypedString() TypedString
}

// Equaler interface is implemented by values, that needs a special equality check.
type Equaler interface {
	Equal(v Value) bool
}

// HashSize is a size of the slice, returned by HashOf.
const HashSize = sha1.Size

var hashPool = sync.Pool{
	New: func() interface{} { return sha1.New() },
}

// HashOf calculates a hash of value v.
func HashOf(v Value) []byte {
	key := make([]byte, HashSize)
	HashTo(v, key)
	return key
}

// HashTo calculates a hash of value v, storing it in a slice p.
func HashTo(v Value, p []byte) {
	h := hashPool.Get().(hash.Hash)
	h.Reset()
	defer hashPool.Put(h)
	if len(p) < HashSize {
		panic("buffer too small to fit the hash")
	}
	if v != nil {
		// TODO(kortschak,dennwc) Remove dependence on String() method.
		h.Write([]byte(v.String()))
	}
	h.Sum(p[:0])
}

// StringOf safely call v.String, returning empty string in case of nil Value.
func StringOf(v Value) string {
	if v == nil {
		return ""
	}
	return v.String()
}

// NativeOf safely call v.Native, returning nil in case of nil Value.
func NativeOf(v Value) interface{} {
	if v == nil {
		return nil
	}
	return v.Native()
}

// AsValue converts native type into closest Value representation.
// It returns false if type was not recognized.
func AsValue(v interface{}) (out Value, ok bool) {
	if v == nil {
		return nil, true
	}
	switch v := v.(type) {
	case Value:
		out = v
	case string:
		out = String(v)
	case int:
		out = Int(v)
	case int64:
		out = Int(v)
	case int32:
		out = Int(v)
	case float64:
		out = Float(v)
	case float32:
		out = Float(v)
	case bool:
		out = Bool(v)
	case time.Time:
		out = Time(v)
	default:
		return nil, false
	}
	return out, true
}

// StringToValue is a function to convert strings to typed
// quad values.
//
// Warning: should not be used directly - will be deprecated.
func StringToValue(v string) Value {
	if v == "" {
		return nil
	}
	if len(v) > 2 {
		if v[0] == '<' && v[len(v)-1] == '>' {
			return IRI(v[1 : len(v)-1])
		} else if v[:2] == "_:" {
			return BNode(v[2:])
		}
	}
	return String(v)
}

// Raw is a Turtle/NQuads-encoded value.
type Raw string

func (s Raw) String() string      { return string(s) }
func (s Raw) Native() interface{} { return s }

// String is an RDF string value (ex: "name").
type String string

var escaper = strings.NewReplacer(
	"\\", "\\\\",
	"\"", "\\\"",
	"\n", "\\n",
	"\r", "\\r",
	"\t", "\\t",
)

func (s String) String() string {
	//TODO(barakmich): Proper escaping.
	return `"` + escaper.Replace(string(s)) + `"`
}
func (s String) Native() interface{} { return string(s) }

// TypedString is an RDF value with type (ex: "name"^^<type>).
type TypedString struct {
	Value String
	Type  IRI
}

func (s TypedString) String() string {
	return s.Value.String() + `^^` + s.Type.String()
}
func (s TypedString) Native() interface{} {
	if s.Type == "" {
		return s.Value.Native()
	}
	if v, err := s.ParseValue(); err == nil && v != s {
		return v.Native()
	}
	return s
}

// ParseValue will try to parse underlying string value using registered functions.
//
// It will return unchanged value if suitable function is not available.
//
// Error will be returned if the type was recognizes, but parsing failed.
func (s TypedString) ParseValue() (Value, error) {
	fnc := knownConversions[s.Type]
	if fnc == nil {
		return s, nil
	}
	return fnc(string(s.Value))
}

// LangString is an RDF string with language (ex: "name"@lang).
type LangString struct {
	Value String
	Lang  string
}

func (s LangString) String() string {
	return s.Value.String() + `@` + s.Lang
}
func (s LangString) Native() interface{} { return s.Value.Native() }

// IRI is an RDF Internationalized Resource Identifier (ex: <name>).
type IRI string

func (s IRI) String() string      { return `<` + string(s) + `>` }
func (s IRI) Native() interface{} { return s }

// BNode is an RDF Blank Node (ex: _:name).
type BNode string

func (s BNode) String() string      { return `_:` + string(s) }
func (s BNode) Native() interface{} { return s }

// Native support for basic types

// StringConversion is a function to convert string values with a
// specific IRI type to their native equivalents.
type StringConversion func(string) (Value, error)

const (
	nsXSD    = `http://www.w3.org/2001/XMLSchema#`
	nsSchema = `http://schema.org/`
)

var knownConversions = map[IRI]StringConversion{
	defaultIntType:    stringToInt,
	nsXSD + `integer`: stringToInt,
	nsXSD + `long`:    stringToInt,

	defaultBoolType:   stringToBool,
	nsXSD + `boolean`: stringToBool,

	defaultFloatType: stringToFloat,
	nsXSD + `double`: stringToFloat,

	defaultTimeType:    stringToTime,
	nsXSD + `dateTime`: stringToTime,
}

// RegisterStringConversion will register an automatic conversion of
// TypedString values with provided type to a native equivalent such as Int, Time, etc.
//
// If fnc is nil, automatic conversion from selected type will be removed.
func RegisterStringConversion(dataType IRI, fnc StringConversion) {
	if fnc == nil {
		delete(knownConversions, dataType)
	} else {
		knownConversions[dataType] = fnc
	}
}

func stringToInt(s string) (Value, error) {
	v, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return nil, err
	}
	return Int(v), nil
}

func stringToBool(s string) (Value, error) {
	v, err := strconv.ParseBool(s)
	if err != nil {
		return nil, err
	}
	return Bool(v), nil
}

func stringToFloat(s string) (Value, error) {
	v, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return nil, err
	}
	return Float(v), nil
}

func stringToTime(s string) (Value, error) {
	v, err := time.Parse(time.RFC3339, s)
	if err != nil {
		return nil, err
	}
	return Time(v), nil
}

// TODO(dennwc): make these configurable
const (
	defaultNamespace     = nsSchema
	defaultIntType   IRI = defaultNamespace + `Integer`
	defaultFloatType IRI = defaultNamespace + `Float`
	defaultBoolType  IRI = defaultNamespace + `Boolean`
	defaultTimeType  IRI = defaultNamespace + `DateTime`
)

// Int is a native wrapper for int64 type.
//
// It uses NQuad notation similar to TypedString.
type Int int64

func (s Int) String() string {
	return s.TypedString().String()
}
func (s Int) Native() interface{} { return int(s) }
func (s Int) TypedString() TypedString {
	return TypedString{
		Value: String(strconv.Itoa(int(s))),
		Type:  defaultIntType,
	}
}

// Float is a native wrapper for float64 type.
//
// It uses NQuad notation similar to TypedString.
type Float float64

func (s Float) String() string {
	return s.TypedString().String()
}
func (s Float) Native() interface{} { return float64(s) }
func (s Float) TypedString() TypedString {
	return TypedString{
		Value: String(strconv.FormatFloat(float64(s), 'E', -1, 64)),
		Type:  defaultFloatType,
	}
}

// Bool is a native wrapper for bool type.
//
// It uses NQuad notation similar to TypedString.
type Bool bool

func (s Bool) String() string {
	if bool(s) {
		return `"True"^^<` + string(defaultBoolType) + `>`
	}
	return `"False"^^<` + string(defaultBoolType) + `>`
}
func (s Bool) Native() interface{} { return bool(s) }
func (s Bool) TypedString() TypedString {
	v := "False"
	if bool(s) {
		v = "True"
	}
	return TypedString{
		Value: String(v),
		Type:  defaultBoolType,
	}
}

var _ Equaler = Time{}

// Time is a native wrapper for time.Time type.
//
// It uses NQuad notation similar to TypedString.
type Time time.Time

func (s Time) String() string {
	return s.TypedString().String()
}
func (s Time) Native() interface{} { return time.Time(s) }
func (s Time) Equal(v Value) bool {
	t, ok := v.(Time)
	if !ok {
		return false
	}
	return time.Time(s).Equal(time.Time(t))
}
func (s Time) TypedString() TypedString {
	return TypedString{
		// TODO(dennwc): this is used to compute hash, thus we might want to include nanos
		Value: String(time.Time(s).Format(time.RFC3339)),
		Type:  defaultTimeType,
	}
}

type ByValueString []Value

func (o ByValueString) Len() int           { return len(o) }
func (o ByValueString) Less(i, j int) bool { return StringOf(o[i]) < StringOf(o[j]) }
func (o ByValueString) Swap(i, j int)      { o[i], o[j] = o[j], o[i] }
<commit_msg>use vocabulary constants for value types, allow to shorten and expand IRIs<commit_after>package quad

import (
	"crypto/sha1"
	"hash"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/cayleygraph/cayley/voc"
	"github.com/cayleygraph/cayley/voc/schema"
)

// Value is a type used by all quad directions.
type Value interface {
	String() string
	// Native converts Value to a closest native Go type.
	//
	// If type has no analogs in Go, Native return an object itself.
	Native() interface{}
}

type TypedStringer interface {
	TypedString() TypedString
}

// Equaler interface is implemented by values, that needs a special equality check.
type Equaler interface {
	Equal(v Value) bool
}

// HashSize is a size of the slice, returned by HashOf.
const HashSize = sha1.Size

var hashPool = sync.Pool{
	New: func() interface{} { return sha1.New() },
}

// HashOf calculates a hash of value v.
func HashOf(v Value) []byte {
	key := make([]byte, HashSize)
	HashTo(v, key)
	return key
}

// HashTo calculates a hash of value v, storing it in a slice p.
func HashTo(v Value, p []byte) {
	h := hashPool.Get().(hash.Hash)
	h.Reset()
	defer hashPool.Put(h)
	if len(p) < HashSize {
		panic("buffer too small to fit the hash")
	}
	if v != nil {
		// TODO(kortschak,dennwc) Remove dependence on String() method.
		h.Write([]byte(v.String()))
	}
	h.Sum(p[:0])
}

// StringOf safely call v.String, returning empty string in case of nil Value.
func StringOf(v Value) string {
	if v == nil {
		return ""
	}
	return v.String()
}

// NativeOf safely call v.Native, returning nil in case of nil Value.
func NativeOf(v Value) interface{} {
	if v == nil {
		return nil
	}
	return v.Native()
}

// AsValue converts native type into closest Value representation.
// It returns false if type was not recognized.
func AsValue(v interface{}) (out Value, ok bool) {
	if v == nil {
		return nil, true
	}
	switch v := v.(type) {
	case Value:
		out = v
	case string:
		out = String(v)
	case int:
		out = Int(v)
	case int64:
		out = Int(v)
	case int32:
		out = Int(v)
	case float64:
		out = Float(v)
	case float32:
		out = Float(v)
	case bool:
		out = Bool(v)
	case time.Time:
		out = Time(v)
	default:
		return nil, false
	}
	return out, true
}

// StringToValue is a function to convert strings to typed
// quad values.
//
// Warning: should not be used directly - will be deprecated.
func StringToValue(v string) Value {
	if v == "" {
		return nil
	}
	if len(v) > 2 {
		if v[0] == '<' && v[len(v)-1] == '>' {
			return IRI(v[1 : len(v)-1])
		} else if v[:2] == "_:" {
			return BNode(v[2:])
		}
	}
	return String(v)
}

// Raw is a Turtle/NQuads-encoded value.
type Raw string

func (s Raw) String() string      { return string(s) }
func (s Raw) Native() interface{} { return s }

// String is an RDF string value (ex: "name").
type String string

var escaper = strings.NewReplacer(
	"\\", "\\\\",
	"\"", "\\\"",
	"\n", "\\n",
	"\r", "\\r",
	"\t", "\\t",
)

func (s String) String() string {
	//TODO(barakmich): Proper escaping.
	return `"` + escaper.Replace(string(s)) + `"`
}
func (s String) Native() interface{} { return string(s) }

// TypedString is an RDF value with type (ex: "name"^^<type>).
type TypedString struct {
	Value String
	Type  IRI
}

func (s TypedString) String() string {
	return s.Value.String() + `^^` + s.Type.String()
}
func (s TypedString) Native() interface{} {
	if s.Type == "" {
		return s.Value.Native()
	}
	if v, err := s.ParseValue(); err == nil && v != s {
		return v.Native()
	}
	return s
}

// ParseValue will try to parse underlying string value using registered functions.
//
// It will return unchanged value if suitable function is not available.
//
// Error will be returned if the type was recognizes, but parsing failed.
func (s TypedString) ParseValue() (Value, error) {
	fnc := knownConversions[s.Type.Full()]
	if fnc == nil {
		return s, nil
	}
	return fnc(string(s.Value))
}

// LangString is an RDF string with language (ex: "name"@lang).
type LangString struct {
	Value String
	Lang  string
}

func (s LangString) String() string {
	return s.Value.String() + `@` + s.Lang
}
func (s LangString) Native() interface{} { return s.Value.Native() }

// IRI is an RDF Internationalized Resource Identifier (ex: <name>).
type IRI string

func (s IRI) String() string      { return `<` + string(s) + `>` }
func (s IRI) Short() IRI          { return IRI(voc.ShortIRI(string(s))) }
func (s IRI) Full() IRI           { return IRI(voc.FullIRI(string(s))) }
func (s IRI) Native() interface{} { return s }

// BNode is an RDF Blank Node (ex: _:name).
type BNode string

func (s BNode) String() string      { return `_:` + string(s) }
func (s BNode) Native() interface{} { return s }

// Native support for basic types

// StringConversion is a function to convert string values with a
// specific IRI type to their native equivalents.
type StringConversion func(string) (Value, error)

const (
	nsXSD = `http://www.w3.org/2001/XMLSchema#`
)

var knownConversions = map[IRI]StringConversion{
	defaultIntType:    stringToInt,
	nsXSD + `integer`: stringToInt,
	nsXSD + `long`:    stringToInt,

	defaultBoolType:   stringToBool,
	nsXSD + `boolean`: stringToBool,

	defaultFloatType: stringToFloat,
	nsXSD + `double`: stringToFloat,

	defaultTimeType:    stringToTime,
	nsXSD + `dateTime`: stringToTime,
}

// RegisterStringConversion will register an automatic conversion of
// TypedString values with provided type to a native equivalent such as Int, Time, etc.
//
// If fnc is nil, automatic conversion from selected type will be removed.
func RegisterStringConversion(dataType IRI, fnc StringConversion) {
	dataType = dataType.Full()
	if fnc == nil {
		delete(knownConversions, dataType)
	} else {
		knownConversions[dataType] = fnc
	}
}

func stringToInt(s string) (Value, error) {
	v, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return nil, err
	}
	return Int(v), nil
}

func stringToBool(s string) (Value, error) {
	v, err := strconv.ParseBool(s)
	if err != nil {
		return nil, err
	}
	return Bool(v), nil
}

func stringToFloat(s string) (Value, error) {
	v, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return nil, err
	}
	return Float(v), nil
}

func stringToTime(s string) (Value, error) {
	v, err := time.Parse(time.RFC3339, s)
	if err != nil {
		return nil, err
	}
	return Time(v), nil
}

// TODO(dennwc): make these configurable
const (
	defaultIntType   IRI = schema.Integer
	defaultFloatType IRI = schema.Float
	defaultBoolType  IRI = schema.Boolean
	defaultTimeType  IRI = schema.DateTime
)

// Int is a native wrapper for int64 type.
//
// It uses NQuad notation similar to TypedString.
type Int int64

func (s Int) String() string {
	return s.TypedString().String()
}
func (s Int) Native() interface{} { return int(s) }
func (s Int) TypedString() TypedString {
	return TypedString{
		Value: String(strconv.Itoa(int(s))),
		Type:  defaultIntType,
	}
}

// Float is a native wrapper for float64 type.
//
// It uses NQuad notation similar to TypedString.
type Float float64

func (s Float) String() string {
	return s.TypedString().String()
}
func (s Float) Native() interface{} { return float64(s) }
func (s Float) TypedString() TypedString {
	return TypedString{
		Value: String(strconv.FormatFloat(float64(s), 'E', -1, 64)),
		Type:  defaultFloatType,
	}
}

// Bool is a native wrapper for bool type.
//
// It uses NQuad notation similar to TypedString.
type Bool bool

func (s Bool) String() string {
	if bool(s) {
		return `"True"^^<` + string(defaultBoolType) + `>`
	}
	return `"False"^^<` + string(defaultBoolType) + `>`
}
func (s Bool) Native() interface{} { return bool(s) }
func (s Bool) TypedString() TypedString {
	v := "False"
	if bool(s) {
		v = "True"
	}
	return TypedString{
		Value: String(v),
		Type:  defaultBoolType,
	}
}

var _ Equaler = Time{}

// Time is a native wrapper for time.Time type.
//
// It uses NQuad notation similar to TypedString.
type Time time.Time

func (s Time) String() string {
	return s.TypedString().String()
}
func (s Time) Native() interface{} { return time.Time(s) }
func (s Time) Equal(v Value) bool {
	t, ok := v.(Time)
	if !ok {
		return false
	}
	return time.Time(s).Equal(time.Time(t))
}
func (s Time) TypedString() TypedString {
	return TypedString{
		// TODO(dennwc): this is used to compute hash, thus we might want to include nanos
		Value: String(time.Time(s).Format(time.RFC3339)),
		Type:  defaultTimeType,
	}
}

type ByValueString []Value

func (o ByValueString) Len() int           { return len(o) }
func (o ByValueString) Less(i, j int) bool { return StringOf(o[i]) < StringOf(o[j]) }
func (o ByValueString) Swap(i, j int)      { o[i], o[j] = o[j], o[i] }
<|endoftext|>


<commit_before>package c3

import "testing"

//import "runtime"

func TestEmptyQueue(t *testing.T) {
	q := NewQueue()
	if q.Len() != 0 {
		t.Errorf("Expected 0, got %v", q.Len())
	}
}
func TestQueueIterator(t *testing.T) {
	q := QueueOf(0, 1, 2, 3)
	index := 0
	for i := q.Iterator(); i.MoveNext(); {
		val, ok := i.Value().(int)
		if !ok || val != index {
			t.Error("Expected ", index, " got ", val)
		}
		index++
	}
}

func TestQueue(t *testing.T) {
	q := NewQueue()
	assert(t, 0, q.Len(), "q.Len()")

	q.Enqueue(9999)
	assert(t, 1, q.Len(), "q.Len()")
	assert(t, true, q.Contains(9999), "q.Contains(9999)")

	result, ok := q.Peek()
	assert(t, 9999, result, "result")
	assert(t, true, ok, "ok")
	assert(t, 1, q.Len(), "q.Len()")

	result, ok = q.Dequeue()
	assert(t, 9999, result, "result")
	assert(t, true, ok, "ok")
	assert(t, 0, q.Len(), "q.Len()")

	result, ok = q.Dequeue()
	assert(t, false, ok, "ok")
	assert(t, 0, q.Len(), "q.Len()")
}

func BenchmarkEnqueue1000(b *testing.B) {
	value := wrap(1)
	q := NewQueue()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for n := 0; n < 1000; n++ {
			q.Enqueue(value)
		}
	}
}

func BenchmarkEnqDeq1000(b *testing.B) {
	value := wrap(1)
	q := NewQueue()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for n := 0; n < 1000; n++ {
			q.Enqueue(value)
		}
		for n := 0; n < 1000; n++ {
			q.Dequeue()
		}
	}
}

func BenchmarkEnqConsume1000(b *testing.B) {
	value := wrap(1)
	q := NewQueue()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for n := 0; n < 1000; n++ {
			q.Enqueue(value)
		}
		for i := q.Consumer(); i.MoveNext(); {
			i.Value()
		}
	}
}

func wrap(item interface{}) interface{} {
	return item
}
<commit_msg>test iteration count of queue iterator<commit_after>package c3

import "testing"

//import "runtime"

func TestEmptyQueue(t *testing.T) {
	q := NewQueue()
	if q.Len() != 0 {
		t.Errorf("Expected 0, got %v", q.Len())
	}
}
func TestQueueIterator(t *testing.T) {
	q := QueueOf(0, 1, 2, 3)
	index := 0
	for i := q.Iterator(); i.MoveNext(); {
		val, ok := i.Value().(int)
		if !ok || val != index {
			t.Error("Expected ", index, " got ", val)
		}
		index++
	}
	if index != 4 {
		t.Error("Too few iterations")
	}
}

func TestQueue(t *testing.T) {
	q := NewQueue()
	assert(t, 0, q.Len(), "q.Len()")

	q.Enqueue(9999)
	assert(t, 1, q.Len(), "q.Len()")
	assert(t, true, q.Contains(9999), "q.Contains(9999)")

	result, ok := q.Peek()
	assert(t, 9999, result, "result")
	assert(t, true, ok, "ok")
	assert(t, 1, q.Len(), "q.Len()")

	result, ok = q.Dequeue()
	assert(t, 9999, result, "result")
	assert(t, true, ok, "ok")
	assert(t, 0, q.Len(), "q.Len()")

	result, ok = q.Dequeue()
	assert(t, false, ok, "ok")
	assert(t, 0, q.Len(), "q.Len()")
}

func BenchmarkEnqueue1000(b *testing.B) {
	value := wrap(1)
	q := NewQueue()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for n := 0; n < 1000; n++ {
			q.Enqueue(value)
		}
	}
}

func BenchmarkEnqDeq1000(b *testing.B) {
	value := wrap(1)
	q := NewQueue()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for n := 0; n < 1000; n++ {
			q.Enqueue(value)
		}
		for n := 0; n < 1000; n++ {
			q.Dequeue()
		}
	}
}

func BenchmarkEnqConsume1000(b *testing.B) {
	value := wrap(1)
	q := NewQueue()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for n := 0; n < 1000; n++ {
			q.Enqueue(value)
		}
		for i := q.Consumer(); i.MoveNext(); {
			i.Value()
		}
	}
}

func wrap(item interface{}) interface{} {
	return item
}
<|endoftext|>