<commit_before>package test

import (
	"fmt"
	"testing"
	"time"

	peer "github.com/libp2p/go-libp2p-peer"
	pt "github.com/libp2p/go-libp2p-peer/test"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
)

var addressBookSuite = map[string]func(book pstore.AddrBook) func(*testing.T){
	"AddAddress":           testAddAddress,
	"Clear":                testClearWorks,
	"SetNegativeTTLClears": testSetNegativeTTLClears,
	"UpdateTTLs":           testUpdateTTLs,
	"NilAddrsDontBreak":    testNilAddrsDontBreak,
	"AddressesExpire":      testAddressesExpire,
	"ClearWithIter":        testClearWithIterator,
	"PeersWithAddresses":   testPeersWithAddrs,
}

type AddrBookFactory func() (pstore.AddrBook, func())

func TestAddrBook(t *testing.T, factory AddrBookFactory) {
	for name, test := range addressBookSuite {
		// Create a new peerstore.
		ab, closeFunc := factory()

		// Run the test.
		t.Run(name, test(ab))

		// Cleanup.
		if closeFunc != nil {
			closeFunc()
		}
	}
}

func generateAddrs(count int) []ma.Multiaddr {
	var addrs = make([]ma.Multiaddr, count)
	for i := 0; i < count; i++ {
		addrs[i] = multiaddr(fmt.Sprintf("/ip4/1.1.1.%d/tcp/1111", i))
	}
	return addrs
}

func generatePeerIds(count int) []peer.ID {
	var ids = make([]peer.ID, count)
	for i := 0; i < count; i++ {
		ids[i], _ = pt.RandPeerID()
	}
	return ids
}

func testAddAddress(ab pstore.AddrBook) func(*testing.T) {
	return func(t *testing.T) {
		t.Run("add a single address", func(t *testing.T) {
			id := generatePeerIds(1)[0]
			addrs := generateAddrs(1)

			ab.AddAddr(id, addrs[0], time.Hour)

			testHas(t, addrs, ab.Addrs(id))
		})

		t.Run("idempotent add single address", func(t *testing.T) {
			id := generatePeerIds(1)[0]
			addrs := generateAddrs(1)

			ab.AddAddr(id, addrs[0], time.Hour)
			ab.AddAddr(id, addrs[0], time.Hour)

			testHas(t, addrs, ab.Addrs(id))
		})

		t.Run("add multiple addresses", func(t *testing.T) {
			id := generatePeerIds(1)[0]
			addrs := generateAddrs(3)

			ab.AddAddrs(id, addrs, time.Hour)
			testHas(t, addrs, ab.Addrs(id))
		})

		t.Run("idempotent add multiple addresses", func(t *testing.T) {
			id := generatePeerIds(1)[0]
			addrs := generateAddrs(3)

			ab.AddAddrs(id, addrs, time.Hour)
			ab.AddAddrs(id, addrs, time.Hour)

			testHas(t, addrs, ab.Addrs(id))
		})
	}
}

func testClearWorks(ab pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		ids := generatePeerIds(2)
		addrs := generateAddrs(5)

		ab.AddAddrs(ids[0], addrs[0:3], time.Hour)
		ab.AddAddrs(ids[1], addrs[3:], time.Hour)

		testHas(t, addrs[0:3], ab.Addrs(ids[0]))
		testHas(t, addrs[3:], ab.Addrs(ids[1]))

		ab.ClearAddrs(ids[0])
		testHas(t, nil, ab.Addrs(ids[0]))
		testHas(t, addrs[3:], ab.Addrs(ids[1]))

		ab.ClearAddrs(ids[1])
		testHas(t, nil, ab.Addrs(ids[0]))
		testHas(t, nil, ab.Addrs(ids[1]))
	}
}

func testSetNegativeTTLClears(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		id := generatePeerIds(1)[0]
		addr := generateAddrs(1)[0]

		m.SetAddr(id, addr, time.Hour)
		testHas(t, []ma.Multiaddr{addr}, m.Addrs(id))

		m.SetAddr(id, addr, -1)
		testHas(t, nil, m.Addrs(id))
	}
}

func testUpdateTTLs(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		t.Run("update ttl of peer with no addrs", func(t *testing.T) {
			id := generatePeerIds(1)[0]

			// Shouldn't panic.
			m.UpdateAddrs(id, time.Hour, time.Minute)
		})

		t.Run("update ttls successfully", func(t *testing.T) {
			ids := generatePeerIds(2)
			addrs1, addrs2 := generateAddrs(2), generateAddrs(2)

			// set two keys with different ttls for each peer.
			m.SetAddr(ids[0], addrs1[0], time.Hour)
			m.SetAddr(ids[0], addrs1[1], time.Minute)
			m.SetAddr(ids[1], addrs2[0], time.Hour)
			m.SetAddr(ids[1], addrs2[1], time.Minute)

			// Sanity check.
			testHas(t, addrs1, m.Addrs(ids[0]))
			testHas(t, addrs2, m.Addrs(ids[1]))

			// Will only affect addrs1[0].
			m.UpdateAddrs(ids[0], time.Hour, 100*time.Microsecond)

			// No immediate effect.
			testHas(t, addrs1, m.Addrs(ids[0]))
			testHas(t, addrs2, m.Addrs(ids[1]))

			// After a wait, addrs[0] is gone.
			time.Sleep(100 * time.Millisecond)
			testHas(t, addrs1[1:2], m.Addrs(ids[0]))
			testHas(t, addrs2, m.Addrs(ids[1]))

			// Will only affect addrs2[0].
			m.UpdateAddrs(ids[1], time.Hour, 100*time.Microsecond)

			// No immediate effect.
			testHas(t, addrs1[1:2], m.Addrs(ids[0]))
			testHas(t, addrs2, m.Addrs(ids[1]))

			time.Sleep(100 * time.Millisecond)

			// First addrs is gone in both.
			testHas(t, addrs1[1:], m.Addrs(ids[0]))
			testHas(t, addrs2[1:], m.Addrs(ids[1]))
		})

	}
}

func testNilAddrsDontBreak(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		id := generatePeerIds(1)[0]

		m.SetAddr(id, nil, time.Hour)
		m.AddAddr(id, nil, time.Hour)
	}
}

func testAddressesExpire(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		ids := generatePeerIds(2)
		addrs1 := generateAddrs(3)
		addrs2 := generateAddrs(2)

		m.AddAddrs(ids[0], addrs1, time.Hour)
		m.AddAddrs(ids[1], addrs2, time.Hour)

		testHas(t, addrs1, m.Addrs(ids[0]))
		testHas(t, addrs2, m.Addrs(ids[1]))

		m.AddAddrs(ids[0], addrs1, 2*time.Hour)
		m.AddAddrs(ids[1], addrs2, 2*time.Hour)

		testHas(t, addrs1, m.Addrs(ids[0]))
		testHas(t, addrs2, m.Addrs(ids[1]))

		m.SetAddr(ids[0], addrs1[0], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, addrs1[1:3], m.Addrs(ids[0]))
		testHas(t, addrs2, m.Addrs(ids[1]))

		m.SetAddr(ids[0], addrs1[2], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, addrs1[1:2], m.Addrs(ids[0]))
		testHas(t, addrs2, m.Addrs(ids[1]))

		m.SetAddr(ids[1], addrs2[0], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, addrs1[1:2], m.Addrs(ids[0]))
		testHas(t, addrs2[1:], m.Addrs(ids[1]))

		m.SetAddr(ids[1], addrs2[1], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, addrs1[1:2], m.Addrs(ids[0]))
		testHas(t, nil, m.Addrs(ids[1]))

		m.SetAddr(ids[0], addrs1[1], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, nil, m.Addrs(ids[0]))
		testHas(t, nil, m.Addrs(ids[1]))
	}
}

func testClearWithIterator(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		ids := generatePeerIds(2)
		addrs := generateAddrs(100)

		// Add the peers with 50 addresses each.
		m.AddAddrs(ids[0], addrs[:50], pstore.PermanentAddrTTL)
		m.AddAddrs(ids[1], addrs[50:], pstore.PermanentAddrTTL)

		if all := append(m.Addrs(ids[0]), m.Addrs(ids[1])...); len(all) != 100 {
			t.Fatal("expected pstore to contain both peers with all their maddrs")
		}

		// Since we don't fetch these peers, they won't be present in cache.

		m.ClearAddrs(ids[0])
		if all := append(m.Addrs(ids[0]), m.Addrs(ids[1])...); len(all) != 50 {
			t.Fatal("expected pstore to contain only addrs of peer 2")
		}

		m.ClearAddrs(ids[1])
		if all := append(m.Addrs(ids[0]), m.Addrs(ids[1])...); len(all) != 0 {
			t.Fatal("expected pstore to contain no addresses")
		}
	}
}

func testPeersWithAddrs(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		// cannot run in parallel as the store is modified.
		// go runs sequentially in the specified order
		// see https://blog.golang.org/subtests

		t.Run("empty addrbook", func(t *testing.T) {
			if peers := m.PeersWithAddrs(); len(peers) != 0 {
				t.Fatal("expected to find no peers")
			}
		})

		t.Run("non-empty addrbook", func(t *testing.T) {
			ids := generatePeerIds(2)
			addrs := generateAddrs(10)

			m.AddAddrs(ids[0], addrs[:5], pstore.PermanentAddrTTL)
			m.AddAddrs(ids[1], addrs[5:], pstore.PermanentAddrTTL)

			if peers := m.PeersWithAddrs(); len(peers) != 2 {
				t.Fatal("expected to find 2 peers")
			}
		})
	}
}

func testHas(t *testing.T, exp, act []ma.Multiaddr) {
	t.Helper()
	if len(exp) != len(act) {
		t.Fatalf("lengths not the same. expected %d, got %d\n", len(exp), len(act))
	}

	for _, a := range exp {
		found := false

		for _, b := range act {
			if a.Equal(b) {
				found = true
				break
			}
		}

		if !found {
			t.Fatalf("expected address %s not found", a)
		}
	}
}
<commit_msg>adjust ttl tests as badger doesn't support sub-second ttl.<commit_after>package test

import (
	"fmt"
	"testing"
	"time"

	peer "github.com/libp2p/go-libp2p-peer"
	pt "github.com/libp2p/go-libp2p-peer/test"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
)

var addressBookSuite = map[string]func(book pstore.AddrBook) func(*testing.T){
	"AddAddress":           testAddAddress,
	"Clear":                testClearWorks,
	"SetNegativeTTLClears": testSetNegativeTTLClears,
	"UpdateTTLs":           testUpdateTTLs,
	"NilAddrsDontBreak":    testNilAddrsDontBreak,
	"AddressesExpire":      testAddressesExpire,
	"ClearWithIter":        testClearWithIterator,
	"PeersWithAddresses":   testPeersWithAddrs,
}

type AddrBookFactory func() (pstore.AddrBook, func())

func TestAddrBook(t *testing.T, factory AddrBookFactory) {
	for name, test := range addressBookSuite {
		// Create a new peerstore.
		ab, closeFunc := factory()

		// Run the test.
		t.Run(name, test(ab))

		// Cleanup.
		if closeFunc != nil {
			closeFunc()
		}
	}
}

func generateAddrs(count int) []ma.Multiaddr {
	var addrs = make([]ma.Multiaddr, count)
	for i := 0; i < count; i++ {
		addrs[i] = multiaddr(fmt.Sprintf("/ip4/1.1.1.%d/tcp/1111", i))
	}
	return addrs
}

func generatePeerIds(count int) []peer.ID {
	var ids = make([]peer.ID, count)
	for i := 0; i < count; i++ {
		ids[i], _ = pt.RandPeerID()
	}
	return ids
}

func testAddAddress(ab pstore.AddrBook) func(*testing.T) {
	return func(t *testing.T) {
		t.Run("add a single address", func(t *testing.T) {
			id := generatePeerIds(1)[0]
			addrs := generateAddrs(1)

			ab.AddAddr(id, addrs[0], time.Hour)

			testHas(t, addrs, ab.Addrs(id))
		})

		t.Run("idempotent add single address", func(t *testing.T) {
			id := generatePeerIds(1)[0]
			addrs := generateAddrs(1)

			ab.AddAddr(id, addrs[0], time.Hour)
			ab.AddAddr(id, addrs[0], time.Hour)

			testHas(t, addrs, ab.Addrs(id))
		})

		t.Run("add multiple addresses", func(t *testing.T) {
			id := generatePeerIds(1)[0]
			addrs := generateAddrs(3)

			ab.AddAddrs(id, addrs, time.Hour)
			testHas(t, addrs, ab.Addrs(id))
		})

		t.Run("idempotent add multiple addresses", func(t *testing.T) {
			id := generatePeerIds(1)[0]
			addrs := generateAddrs(3)

			ab.AddAddrs(id, addrs, time.Hour)
			ab.AddAddrs(id, addrs, time.Hour)

			testHas(t, addrs, ab.Addrs(id))
		})
	}
}

func testClearWorks(ab pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		ids := generatePeerIds(2)
		addrs := generateAddrs(5)

		ab.AddAddrs(ids[0], addrs[0:3], time.Hour)
		ab.AddAddrs(ids[1], addrs[3:], time.Hour)

		testHas(t, addrs[0:3], ab.Addrs(ids[0]))
		testHas(t, addrs[3:], ab.Addrs(ids[1]))

		ab.ClearAddrs(ids[0])
		testHas(t, nil, ab.Addrs(ids[0]))
		testHas(t, addrs[3:], ab.Addrs(ids[1]))

		ab.ClearAddrs(ids[1])
		testHas(t, nil, ab.Addrs(ids[0]))
		testHas(t, nil, ab.Addrs(ids[1]))
	}
}

func testSetNegativeTTLClears(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		id := generatePeerIds(1)[0]
		addr := generateAddrs(1)[0]

		m.SetAddr(id, addr, time.Hour)
		testHas(t, []ma.Multiaddr{addr}, m.Addrs(id))

		m.SetAddr(id, addr, -1)
		testHas(t, nil, m.Addrs(id))
	}
}

func testUpdateTTLs(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		t.Run("update ttl of peer with no addrs", func(t *testing.T) {
			id := generatePeerIds(1)[0]

			// Shouldn't panic.
			m.UpdateAddrs(id, time.Hour, time.Minute)
		})

		t.Run("update ttls successfully", func(t *testing.T) {
			ids := generatePeerIds(2)
			addrs1, addrs2 := generateAddrs(2), generateAddrs(2)

			// set two keys with different ttls for each peer.
			m.SetAddr(ids[0], addrs1[0], time.Hour)
			m.SetAddr(ids[0], addrs1[1], time.Minute)
			m.SetAddr(ids[1], addrs2[0], time.Hour)
			m.SetAddr(ids[1], addrs2[1], time.Minute)

			// Sanity check.
			testHas(t, addrs1, m.Addrs(ids[0]))
			testHas(t, addrs2, m.Addrs(ids[1]))

			// Will only affect addrs1[0].
			// Badger does not support subsecond TTLs.
			// https://github.com/dgraph-io/badger/issues/339
			m.UpdateAddrs(ids[0], time.Hour, 1*time.Second)

			// No immediate effect.
			testHas(t, addrs1, m.Addrs(ids[0]))
			testHas(t, addrs2, m.Addrs(ids[1]))

			// After a wait, addrs[0] is gone.
			time.Sleep(1500 * time.Millisecond)
			testHas(t, addrs1[1:2], m.Addrs(ids[0]))
			testHas(t, addrs2, m.Addrs(ids[1]))

			// Will only affect addrs2[0].
			m.UpdateAddrs(ids[1], time.Hour, 1*time.Second)

			// No immediate effect.
			testHas(t, addrs1[1:2], m.Addrs(ids[0]))
			testHas(t, addrs2, m.Addrs(ids[1]))

			time.Sleep(1500 * time.Millisecond)

			// First addrs is gone in both.
			testHas(t, addrs1[1:], m.Addrs(ids[0]))
			testHas(t, addrs2[1:], m.Addrs(ids[1]))
		})

	}
}

func testNilAddrsDontBreak(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		id := generatePeerIds(1)[0]

		m.SetAddr(id, nil, time.Hour)
		m.AddAddr(id, nil, time.Hour)
	}
}

func testAddressesExpire(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		ids := generatePeerIds(2)
		addrs1 := generateAddrs(3)
		addrs2 := generateAddrs(2)

		m.AddAddrs(ids[0], addrs1, time.Hour)
		m.AddAddrs(ids[1], addrs2, time.Hour)

		testHas(t, addrs1, m.Addrs(ids[0]))
		testHas(t, addrs2, m.Addrs(ids[1]))

		m.AddAddrs(ids[0], addrs1, 2*time.Hour)
		m.AddAddrs(ids[1], addrs2, 2*time.Hour)

		testHas(t, addrs1, m.Addrs(ids[0]))
		testHas(t, addrs2, m.Addrs(ids[1]))

		m.SetAddr(ids[0], addrs1[0], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, addrs1[1:3], m.Addrs(ids[0]))
		testHas(t, addrs2, m.Addrs(ids[1]))

		m.SetAddr(ids[0], addrs1[2], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, addrs1[1:2], m.Addrs(ids[0]))
		testHas(t, addrs2, m.Addrs(ids[1]))

		m.SetAddr(ids[1], addrs2[0], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, addrs1[1:2], m.Addrs(ids[0]))
		testHas(t, addrs2[1:], m.Addrs(ids[1]))

		m.SetAddr(ids[1], addrs2[1], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, addrs1[1:2], m.Addrs(ids[0]))
		testHas(t, nil, m.Addrs(ids[1]))

		m.SetAddr(ids[0], addrs1[1], 100*time.Microsecond)
		<-time.After(100 * time.Millisecond)
		testHas(t, nil, m.Addrs(ids[0]))
		testHas(t, nil, m.Addrs(ids[1]))
	}
}

func testClearWithIterator(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		ids := generatePeerIds(2)
		addrs := generateAddrs(100)

		// Add the peers with 50 addresses each.
		m.AddAddrs(ids[0], addrs[:50], pstore.PermanentAddrTTL)
		m.AddAddrs(ids[1], addrs[50:], pstore.PermanentAddrTTL)

		if all := append(m.Addrs(ids[0]), m.Addrs(ids[1])...); len(all) != 100 {
			t.Fatal("expected pstore to contain both peers with all their maddrs")
		}

		// Since we don't fetch these peers, they won't be present in cache.

		m.ClearAddrs(ids[0])
		if all := append(m.Addrs(ids[0]), m.Addrs(ids[1])...); len(all) != 50 {
			t.Fatal("expected pstore to contain only addrs of peer 2")
		}

		m.ClearAddrs(ids[1])
		if all := append(m.Addrs(ids[0]), m.Addrs(ids[1])...); len(all) != 0 {
			t.Fatal("expected pstore to contain no addresses")
		}
	}
}

func testPeersWithAddrs(m pstore.AddrBook) func(t *testing.T) {
	return func(t *testing.T) {
		// cannot run in parallel as the store is modified.
		// go runs sequentially in the specified order
		// see https://blog.golang.org/subtests

		t.Run("empty addrbook", func(t *testing.T) {
			if peers := m.PeersWithAddrs(); len(peers) != 0 {
				t.Fatal("expected to find no peers")
			}
		})

		t.Run("non-empty addrbook", func(t *testing.T) {
			ids := generatePeerIds(2)
			addrs := generateAddrs(10)

			m.AddAddrs(ids[0], addrs[:5], pstore.PermanentAddrTTL)
			m.AddAddrs(ids[1], addrs[5:], pstore.PermanentAddrTTL)

			if peers := m.PeersWithAddrs(); len(peers) != 2 {
				t.Fatal("expected to find 2 peers")
			}
		})
	}
}

func testHas(t *testing.T, exp, act []ma.Multiaddr) {
	t.Helper()
	if len(exp) != len(act) {
		t.Fatalf("lengths not the same. expected %d, got %d\n", len(exp), len(act))
	}

	for _, a := range exp {
		found := false

		for _, b := range act {
			if a.Equal(b) {
				found = true
				break
			}
		}

		if !found {
			t.Fatalf("expected address %s not found", a)
		}
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"net/http"

	"github.com/labstack/echo"
	coreMiddleware "github.com/labstack/echo/middleware"
)

// LockedDownCORSWithConfig is good
func LockedDownCORSWithConfig(config coreMiddleware.CORSConfig) echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		CORSWithConfig := coreMiddleware.CORSWithConfig(config)
		CORSWithConfigHandler := CORSWithConfig(next)

		return func(c echo.Context) error {

			req := c.Request()
			origin := req.Header.Get(echo.HeaderOrigin)
			allowOrigin := ""

			// Check allowed origins
			for _, o := range config.AllowOrigins {
				if o == "*" && config.AllowCredentials {
					allowOrigin = origin
					break
				}
				if o == "*" || o == origin {
					allowOrigin = o
					break
				}
			}

			if allowOrigin == "" {
				return c.NoContent(http.StatusForbidden)
			}

			return CORSWithConfigHandler(c)

		}
	}
}
<commit_msg>Log rejected request origins<commit_after>package middleware

import (
	"fmt"
	"net/http"

	"github.com/labstack/echo"
	coreMiddleware "github.com/labstack/echo/middleware"
)

// LockedDownCORSWithConfig is good
func LockedDownCORSWithConfig(config coreMiddleware.CORSConfig) echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		CORSWithConfig := coreMiddleware.CORSWithConfig(config)
		CORSWithConfigHandler := CORSWithConfig(next)

		return func(c echo.Context) error {

			req := c.Request()
			origin := req.Header.Get(echo.HeaderOrigin)
			allowOrigin := ""

			// Check allowed origins
			for _, o := range config.AllowOrigins {
				if o == "*" && config.AllowCredentials {
					allowOrigin = origin
					break
				}
				if o == "*" || o == origin {
					allowOrigin = o
					break
				}
			}

			if allowOrigin == "" {
				fmt.Printf("Rejected request from origin %s", origin)
				return c.NoContent(http.StatusForbidden)
			}

			return CORSWithConfigHandler(c)

		}
	}
}
<|endoftext|>


<commit_before>package period

import (
	"fmt"
	"reflect"
	"time"
)

const (
	UTS               = "1136239445"          //  unixtimestamp
	ICSFORMAT         = "20060102T150405Z"    //ics date time format
	YMDHIS            = "2006-01-02 15:04:05" // Y-m-d H:i:S time format
	ICSFORMATWHOLEDAY = "20060102"            // ics date format ( describes a whole day)
)

var StartWeek time.Weekday = time.Monday
var Timezone *time.Location = time.UTC

type Period struct {
	Start time.Time `json:"start"`
	End   time.Time `json:"end"`
}

// Compare DateTimeInterface objects including microseconds
func compareDate(date1, date2 time.Time) int {
	if date1.After(date2) {
		return 1
	}

	if date1.Before(date2) {
		return -1
	}

	return 0
}

// Create a Period object from a Year and a Week.
func CreateFromWeek(year, week int) (p Period, err error) {
	if week, err = validateRange(week, 1, 53); err != nil {
		return p, err
	}

	p.Start = time.Date(year, 0, 0, 0, 0, 0, 0, Timezone)
	isoYear, isoWeek := p.Start.ISOWeek()
	for p.Start.Weekday() != time.Monday { // iterate back to Monday (ISO_8601 first day of week = Monday)
		p.Start = p.Start.AddDate(0, 0, -1)
		isoYear, isoWeek = p.Start.ISOWeek()
	}
	for isoYear < year { // iterate forward to the first day of the first week
		p.Start = p.Start.AddDate(0, 0, 1)
		isoYear, isoWeek = p.Start.ISOWeek()
		// fmt.Printf("isoYear: %s, year: %s\n", isoYear, year)
	}
	for isoWeek < week { // iterate forward to the first day of the given week
		p.Start = p.Start.AddDate(0, 0, 1)
		isoYear, isoWeek = p.Start.ISOWeek()
	}
	for p.Start.Weekday() != StartWeek { // iterate back to StartWeek
		var diff int
		diff = int(StartWeek) - int(time.Monday)
		p.Start = p.Start.AddDate(0, 0, diff)
		isoYear, isoWeek = p.Start.ISOWeek()
	}

	// add 1 week
	p.End = p.Start.AddDate(0, 0, 7)

	return p, nil
}

func validateRange(value, min, max int) (int, error) {
	if value < min || value > max {
		return value, OutOfRangeError
	}
	return value, nil
}

// Create a Period object from a Year and a Month.
func CreateFromMonth(year, month int) (p Period, err error) {
	if month, err = validateRange(month, 1, 12); err != nil {
		return p, err
	}

	p.Start, err = time.Parse(YMDHIS, fmt.Sprintf("%d-%02d-01 00:00:00", year, month))
	if err != nil {
		return p, err
	}

	p.End = p.Start.AddDate(0, 1, 0)

	return p, nil
}

// Create a Period object from a Year and a Quarter.
func CreateFromQuarter(year, quarter int) (p Period, err error) {
	if quarter, err = validateRange(quarter, 1, 4); err != nil {
		return p, err
	}

	p.Start, err = time.Parse(YMDHIS, fmt.Sprintf("%d-%02d-01 00:00:00", year, ((quarter-1)*3)+1))
	if err != nil {
		return p, err
	}

	p.End = p.Start.AddDate(0, 3, 0)

	return p, nil
}

// Create a Period object from a Year and a Quarter.
func CreateFromSemester(year, semester int) (p Period, err error) {
	if semester, err = validateRange(semester, 1, 2); err != nil {
		return p, err
	}

	p.Start, err = time.Parse(YMDHIS, fmt.Sprintf("%d-%02d-01 00:00:00", year, ((semester-1)*6)+1))
	if err != nil {
		return p, err
	}

	p.End = p.Start.AddDate(0, 6, 0)

	return p, nil
}

// Create a Period object from a Year
func CreateFromYear(year int) (p Period, err error) {
	p.Start, err = time.Parse(YMDHIS, fmt.Sprintf("%d-01-01 00:00:00", year))
	if err != nil {
		return p, err
	}

	p.End = p.Start.AddDate(1, 0, 0)

	return p, nil
}

// Create a Period object from a starting point and an interval.
//                                              interpreted as the duration expressed in seconds.
//                                              If a string is passed, it must be parsable by
//                                              `Duration::createFromDateString`
func CreateFromDuration(start time.Time, duration time.Duration) (p Period, err error) {

	p.Start = start
	p.End = addDuration(p.Start, duration)

	return p, nil
}

func CreateFromDurationBeforeEnd(end time.Time, duration time.Duration) (p Period, err error) {
	p.Start = subDuration(end, duration)
	p.End = end

	return p, nil
}

func (p *Period) Contains(index time.Time) bool {
	return (-1 < compareDate(index, p.Start)) &&
		(-1 == compareDate(index, p.End))
}

func addDuration(date time.Time, duration time.Duration) time.Time {
	return date.Add(duration)
}

func subDuration(date time.Time, duration time.Duration) time.Time {
	sub := time.Duration(-duration.Nanoseconds()) * time.Nanosecond
	date = date.Add(sub)

	return date
}

func (p *Period) StartingOn(start time.Time) {
	p.Start = start
}
func (p *Period) EndingOn(end time.Time) {
	p.End = end
}

func (p *Period) WithDuration(duration time.Duration) {
	p.End = addDuration(p.Start, duration)
}

func (p *Period) Add(duration time.Duration) {
	p.End = addDuration(p.End, duration)
}

func (p *Period) Sub(duration time.Duration) {
	p.End = subDuration(p.End, duration)
}

func (p *Period) Next() {
	clone := *p
	duration := clone.GetDurationInterval()
	p.Start = clone.End
	p.End = addDuration(clone.End, duration)
}

func (p *Period) Previous() {
	clone := *p
	duration := clone.GetDurationInterval()
	p.Start = subDuration(clone.Start, duration)
	p.End = clone.Start
}

func (p *Period) GetDurationInterval() time.Duration {
	end := p.End.UnixNano()
	start := p.Start.UnixNano()
	return time.Duration(end-start) * time.Nanosecond
}

func (p *Period) Overlaps(period Period) bool {
	if abuts, _ := p.Abuts(period); abuts {
		return false
	}

	return (-1 == compareDate(p.Start, period.End)) &&
		(1 == compareDate(p.End, period.Start))
}

// Tells whether two Period share the same datepoints.
func (p *Period) SameValueAs(period Period) bool {
	return 0 == compareDate(p.Start, period.Start) &&
		0 == compareDate(p.End, period.End)
}

// Tells whether a Period is entirely after the specified index
func (p *Period) IsAfter(period Period) bool {
	return -1 < compareDate(p.Start, period.Start)
}

// Tells whether a Period is entirely before the specified index
func (p *Period) IsBefore(period Period) bool {
	return 1 > compareDate(p.End, period.End)
}

// Tells whether two Period object abuts
func (p *Period) Abuts(period Period) (bool, int) {
	found, pos := in_array(0, []int{
		compareDate(p.Start, period.End),
		compareDate(p.End, period.Start),
	})

	return found, pos
}

func (p *Period) Diff(period Period) ([]Period, error) {
	if p.Overlaps(period) == false {
		return nil, ShouldOverlapsError
	}

	var res = []Period{}
	var period1 Period = createFromDatepoints(p.Start, period.Start)
	var period2 Period = createFromDatepoints(p.End, period.End)

	if compareDate(period1.Start, period1.End) != 0 {
		res = append(res, period1)
	}

	if compareDate(period2.Start, period2.End) != 0 {
		res = append(res, period2)
	}

	return res, nil
}

// Merges one or more Period objects to return a new Period object.
// The resultant object englobes the largest duration possible.
func (p *Period) Merge(periods ...Period) {
	// allPeriods := []Period{}
	for _, period := range periods {
		if 1 == compareDate(p.Start, period.Start) {
			p.StartingOn(period.Start)
		}

		if -1 == compareDate(p.End, period.End) {
			p.EndingOn(period.End)
		}
	}
}

// Computes the intersection between two Period objects.
func (p *Period) Intersect(period Period) (Period, error) {
	var newPeriod Period
	if abuts, _ := p.Abuts(period); abuts {
		return newPeriod, BothShouldNotAbuts
	}

	if newPeriod.Start = p.Start; 1 == compareDate(period.Start, p.Start) {
		newPeriod.Start = period.Start
	}

	if newPeriod.End = p.End; -1 == compareDate(period.End, p.End) {
		newPeriod.End = period.End
	}

	return newPeriod, nil
}

func (p *Period) Gap(period Period) (newPeriod Period) {

	if 1 == compareDate(period.Start, p.Start) {
		newPeriod.Start = p.End
		newPeriod.End = period.Start
		return
	}

	newPeriod.Start = period.End
	newPeriod.End = p.Start
	return
}

// Compares two Period objects according to their duration.
func (p *Period) CompareDuration(period Period) int {
	return compareDate(p.End, period.End)
}

// Tells whether the current Period object duration
// is greater than the submitted one.
func (p *Period) DurationGreaterThan(period Period) bool {
	return 1 == p.CompareDuration(period)
}

// Tells whether the current Period object duration
// is less than the submitted one.
func (p *Period) DurationLessThan(period Period) bool {
	return -1 == p.CompareDuration(period)
}

// Tells whether the current Period object duration
// is equal to the submitted one
func (p *Period) SameDurationAs(period Period) bool {
	return 0 == p.CompareDuration(period)
}

// Create a Period object from a Year and a Quarter.
func (p *Period) DurationDiff(period Period) time.Duration {
	return time.Duration(p.TimestampDurationDiff(period)) * time.Nanosecond
}

func (p *Period) TimestampDurationDiff(period Period) int64 {
	return p.GetDurationInterval().Nanoseconds() - period.GetDurationInterval().Nanoseconds()
}

func createFromDatepoints(date1, date2 time.Time) Period {
	if 1 == compareDate(date1, date2) {
		return Period{date2, date1}
	}

	return Period{date1, date2}
}

// http://codereview.stackexchange.com/questions/60074/in-array-in-go
func in_array(val interface{}, array interface{}) (exists bool, index int) {
	exists = false
	index = -1

	switch reflect.TypeOf(array).Kind() {
	case reflect.Slice:
		s := reflect.ValueOf(array)

		for i := 0; i < s.Len(); i++ {
			if reflect.DeepEqual(val, s.Index(i).Interface()) == true {
				index = i
				exists = true
				return
			}
		}
	}

	return
}
<commit_msg>Remove comments<commit_after>package period

import (
	"fmt"
	"reflect"
	"time"
)

const (
	UTS               = "1136239445"          //  unixtimestamp
	ICSFORMAT         = "20060102T150405Z"    //ics date time format
	YMDHIS            = "2006-01-02 15:04:05" // Y-m-d H:i:S time format
	ICSFORMATWHOLEDAY = "20060102"            // ics date format ( describes a whole day)
)

var StartWeek time.Weekday = time.Monday
var Timezone *time.Location = time.UTC

type Period struct {
	Start time.Time `json:"start"`
	End   time.Time `json:"end"`
}

// Compare DateTimeInterface objects including microseconds
func compareDate(date1, date2 time.Time) int {
	if date1.After(date2) {
		return 1
	}

	if date1.Before(date2) {
		return -1
	}

	return 0
}

// Create a Period object from a Year and a Week.
func CreateFromWeek(year, week int) (p Period, err error) {
	if week, err = validateRange(week, 1, 53); err != nil {
		return p, err
	}

	p.Start = time.Date(year, 0, 0, 0, 0, 0, 0, Timezone)
	isoYear, isoWeek := p.Start.ISOWeek()
	for p.Start.Weekday() != time.Monday { // iterate back to Monday (ISO_8601 first day of week = Monday)
		p.Start = p.Start.AddDate(0, 0, -1)
		isoYear, isoWeek = p.Start.ISOWeek()
	}
	for isoYear < year { // iterate forward to the first day of the first week
		p.Start = p.Start.AddDate(0, 0, 1)
		isoYear, isoWeek = p.Start.ISOWeek()
		// fmt.Printf("isoYear: %s, year: %s\n", isoYear, year)
	}
	for isoWeek < week { // iterate forward to the first day of the given week
		p.Start = p.Start.AddDate(0, 0, 1)
		isoYear, isoWeek = p.Start.ISOWeek()
	}
	for p.Start.Weekday() != StartWeek { // iterate back to StartWeek
		var diff int
		diff = int(StartWeek) - int(time.Monday)
		p.Start = p.Start.AddDate(0, 0, diff)
		isoYear, isoWeek = p.Start.ISOWeek()
	}

	// add 1 week
	p.End = p.Start.AddDate(0, 0, 7)

	return p, nil
}

func validateRange(value, min, max int) (int, error) {
	if value < min || value > max {
		return value, OutOfRangeError
	}
	return value, nil
}

// Create a Period object from a Year and a Month.
func CreateFromMonth(year, month int) (p Period, err error) {
	if month, err = validateRange(month, 1, 12); err != nil {
		return p, err
	}

	p.Start, err = time.Parse(YMDHIS, fmt.Sprintf("%d-%02d-01 00:00:00", year, month))
	if err != nil {
		return p, err
	}

	p.End = p.Start.AddDate(0, 1, 0)

	return p, nil
}

// Create a Period object from a Year and a Quarter.
func CreateFromQuarter(year, quarter int) (p Period, err error) {
	if quarter, err = validateRange(quarter, 1, 4); err != nil {
		return p, err
	}

	p.Start, err = time.Parse(YMDHIS, fmt.Sprintf("%d-%02d-01 00:00:00", year, ((quarter-1)*3)+1))
	if err != nil {
		return p, err
	}

	p.End = p.Start.AddDate(0, 3, 0)

	return p, nil
}

// Create a Period object from a Year and a Quarter.
func CreateFromSemester(year, semester int) (p Period, err error) {
	if semester, err = validateRange(semester, 1, 2); err != nil {
		return p, err
	}

	p.Start, err = time.Parse(YMDHIS, fmt.Sprintf("%d-%02d-01 00:00:00", year, ((semester-1)*6)+1))
	if err != nil {
		return p, err
	}

	p.End = p.Start.AddDate(0, 6, 0)

	return p, nil
}

// Create a Period object from a Year
func CreateFromYear(year int) (p Period, err error) {
	p.Start, err = time.Parse(YMDHIS, fmt.Sprintf("%d-01-01 00:00:00", year))
	if err != nil {
		return p, err
	}

	p.End = p.Start.AddDate(1, 0, 0)

	return p, nil
}

// Create a Period object from a starting point and an interval.
func CreateFromDuration(start time.Time, duration time.Duration) (p Period, err error) {

	p.Start = start
	p.End = addDuration(p.Start, duration)

	return p, nil
}

func CreateFromDurationBeforeEnd(end time.Time, duration time.Duration) (p Period, err error) {
	p.Start = subDuration(end, duration)
	p.End = end

	return p, nil
}

func (p *Period) Contains(index time.Time) bool {
	return (-1 < compareDate(index, p.Start)) &&
		(-1 == compareDate(index, p.End))
}

func addDuration(date time.Time, duration time.Duration) time.Time {
	return date.Add(duration)
}

func subDuration(date time.Time, duration time.Duration) time.Time {
	sub := time.Duration(-duration.Nanoseconds()) * time.Nanosecond
	date = date.Add(sub)

	return date
}

func (p *Period) StartingOn(start time.Time) {
	p.Start = start
}
func (p *Period) EndingOn(end time.Time) {
	p.End = end
}

func (p *Period) WithDuration(duration time.Duration) {
	p.End = addDuration(p.Start, duration)
}

func (p *Period) Add(duration time.Duration) {
	p.End = addDuration(p.End, duration)
}

func (p *Period) Sub(duration time.Duration) {
	p.End = subDuration(p.End, duration)
}

func (p *Period) Next() {
	clone := *p
	duration := clone.GetDurationInterval()
	p.Start = clone.End
	p.End = addDuration(clone.End, duration)
}

func (p *Period) Previous() {
	clone := *p
	duration := clone.GetDurationInterval()
	p.Start = subDuration(clone.Start, duration)
	p.End = clone.Start
}

func (p *Period) GetDurationInterval() time.Duration {
	end := p.End.UnixNano()
	start := p.Start.UnixNano()
	return time.Duration(end-start) * time.Nanosecond
}

func (p *Period) Overlaps(period Period) bool {
	if abuts, _ := p.Abuts(period); abuts {
		return false
	}

	return (-1 == compareDate(p.Start, period.End)) &&
		(1 == compareDate(p.End, period.Start))
}

// Tells whether two Period share the same datepoints.
func (p *Period) SameValueAs(period Period) bool {
	return 0 == compareDate(p.Start, period.Start) &&
		0 == compareDate(p.End, period.End)
}

// Tells whether a Period is entirely after the specified index
func (p *Period) IsAfter(period Period) bool {
	return -1 < compareDate(p.Start, period.Start)
}

// Tells whether a Period is entirely before the specified index
func (p *Period) IsBefore(period Period) bool {
	return 1 > compareDate(p.End, period.End)
}

// Tells whether two Period object abuts
func (p *Period) Abuts(period Period) (bool, int) {
	found, pos := in_array(0, []int{
		compareDate(p.Start, period.End),
		compareDate(p.End, period.Start),
	})

	return found, pos
}

func (p *Period) Diff(period Period) ([]Period, error) {
	if p.Overlaps(period) == false {
		return nil, ShouldOverlapsError
	}

	var res = []Period{}
	var period1 Period = createFromDatepoints(p.Start, period.Start)
	var period2 Period = createFromDatepoints(p.End, period.End)

	if compareDate(period1.Start, period1.End) != 0 {
		res = append(res, period1)
	}

	if compareDate(period2.Start, period2.End) != 0 {
		res = append(res, period2)
	}

	return res, nil
}

// Merges one or more Period objects to return a new Period object.
// The resultant object englobes the largest duration possible.
func (p *Period) Merge(periods ...Period) {
	// allPeriods := []Period{}
	for _, period := range periods {
		if 1 == compareDate(p.Start, period.Start) {
			p.StartingOn(period.Start)
		}

		if -1 == compareDate(p.End, period.End) {
			p.EndingOn(period.End)
		}
	}
}

// Computes the intersection between two Period objects.
func (p *Period) Intersect(period Period) (Period, error) {
	var newPeriod Period
	if abuts, _ := p.Abuts(period); abuts {
		return newPeriod, BothShouldNotAbuts
	}

	if newPeriod.Start = p.Start; 1 == compareDate(period.Start, p.Start) {
		newPeriod.Start = period.Start
	}

	if newPeriod.End = p.End; -1 == compareDate(period.End, p.End) {
		newPeriod.End = period.End
	}

	return newPeriod, nil
}

func (p *Period) Gap(period Period) (newPeriod Period) {

	if 1 == compareDate(period.Start, p.Start) {
		newPeriod.Start = p.End
		newPeriod.End = period.Start
		return
	}

	newPeriod.Start = period.End
	newPeriod.End = p.Start
	return
}

// Compares two Period objects according to their duration.
func (p *Period) CompareDuration(period Period) int {
	return compareDate(p.End, period.End)
}

// Tells whether the current Period object duration
// is greater than the submitted one.
func (p *Period) DurationGreaterThan(period Period) bool {
	return 1 == p.CompareDuration(period)
}

// Tells whether the current Period object duration
// is less than the submitted one.
func (p *Period) DurationLessThan(period Period) bool {
	return -1 == p.CompareDuration(period)
}

// Tells whether the current Period object duration
// is equal to the submitted one
func (p *Period) SameDurationAs(period Period) bool {
	return 0 == p.CompareDuration(period)
}

// Create a Period object from a Year and a Quarter.
func (p *Period) DurationDiff(period Period) time.Duration {
	return time.Duration(p.TimestampDurationDiff(period)) * time.Nanosecond
}

func (p *Period) TimestampDurationDiff(period Period) int64 {
	return p.GetDurationInterval().Nanoseconds() - period.GetDurationInterval().Nanoseconds()
}

func createFromDatepoints(date1, date2 time.Time) Period {
	if 1 == compareDate(date1, date2) {
		return Period{date2, date1}
	}

	return Period{date1, date2}
}

// http://codereview.stackexchange.com/questions/60074/in-array-in-go
func in_array(val interface{}, array interface{}) (exists bool, index int) {
	exists = false
	index = -1

	switch reflect.TypeOf(array).Kind() {
	case reflect.Slice:
		s := reflect.ValueOf(array)

		for i := 0; i < s.Len(); i++ {
			if reflect.DeepEqual(val, s.Index(i).Interface()) == true {
				index = i
				exists = true
				return
			}
		}
	}

	return
}
<|endoftext|>


<commit_before>package stripe

import "encoding/json"

// VerificationDocumentDetailsCode is a machine-readable code specifying the verification state of
// a document associated with a person.
type VerificationDocumentDetailsCode string

// List of values that IdentityVerificationDetailsCode can take.
const (
	VerificationDocumentDetailsCodeDocumentCorrupt               VerificationDocumentDetailsCode = "document_corrupt"
	VerificationDocumentDetailsCodeDocumentFailedCopy            VerificationDocumentDetailsCode = "document_failed_copy"
	VerificationDocumentDetailsCodeDocumentFailedGreyscale       VerificationDocumentDetailsCode = "document_failed_greyscale"
	VerificationDocumentDetailsCodeDocumentFailedOther           VerificationDocumentDetailsCode = "document_failed_other"
	VerificationDocumentDetailsCodeDocumentFailedTestMode        VerificationDocumentDetailsCode = "document_failed_test_mode"
	VerificationDocumentDetailsCodeDocumentFraudulent            VerificationDocumentDetailsCode = "document_fraudulent"
	VerificationDocumentDetailsCodeDocumentIDTypeNotSupported    VerificationDocumentDetailsCode = "document_id_type_not_supported"
	VerificationDocumentDetailsCodeDocumentIDCountryNotSupported VerificationDocumentDetailsCode = "document_id_country_not_supported"
	VerificationDocumentDetailsCodeDocumentManipulated           VerificationDocumentDetailsCode = "document_manipulated"
	VerificationDocumentDetailsCodeDocumentMissingBack           VerificationDocumentDetailsCode = "document_missing_back"
	VerificationDocumentDetailsCodeDocumentMissingFront          VerificationDocumentDetailsCode = "document_missing_front"
	VerificationDocumentDetailsCodeDocumentNotReadable           VerificationDocumentDetailsCode = "document_not_readable"
	VerificationDocumentDetailsCodeDocumentNotUploaded           VerificationDocumentDetailsCode = "document_not_uploaded"
	VerificationDocumentDetailsCodeDocumentTooLarge              VerificationDocumentDetailsCode = "document_too_large"
)

// PersonVerificationDetailsCode is a machine-readable code specifying the verification state of a
// person.
type PersonVerificationDetailsCode string

// List of values that IdentityVerificationDetailsCode can take.
const (
	PersonVerificationDetailsCodeFailedKeyedIdentity PersonVerificationDetailsCode = "failed_keyed_identity"
	PersonVerificationDetailsCodeFailedOther         PersonVerificationDetailsCode = "failed_other"
	PersonVerificationDetailsCodeScanNameMismatch    PersonVerificationDetailsCode = "scan_name_mismatch"
)

// IdentityVerificationStatus describes the different statuses for identity verification.
type IdentityVerificationStatus string

// List of values that IdentityVerificationStatus can take.
const (
	IdentityVerificationStatusPending    IdentityVerificationStatus = "pending"
	IdentityVerificationStatusUnverified IdentityVerificationStatus = "unverified"
	IdentityVerificationStatusVerified   IdentityVerificationStatus = "verified"
)

// DOBParams represents a DOB during account creation/updates.
type DOBParams struct {
	Day   *int64 `form:"day"`
	Month *int64 `form:"month"`
	Year  *int64 `form:"year"`
}

// RelationshipParams is used to set the relationship between an account and a person.
type RelationshipParams struct {
	Director         *bool    `form:"director"`
	Executive        *bool    `form:"executive"`
	Owner            *bool    `form:"owner"`
	PercentOwnership *float64 `form:"percent_ownership"`
	Representative   *bool    `form:"representative"`
	Title            *string  `form:"title"`
}

// PersonVerificationDocumentParams represents the parameters available for the document verifying
// a person's identity.
type PersonVerificationDocumentParams struct {
	Back  *string `form:"back"`
	Front *string `form:"front"`
}

// PersonVerificationParams is used to represent parameters associated with a person's verification
// details.
type PersonVerificationParams struct {
	AdditionalDocument *PersonVerificationDocumentParams `form:"additional_document"`
	Document           *PersonVerificationDocumentParams `form:"document"`
}

// PersonParams is the set of parameters that can be used when creating or updating a person.
// For more details see https://stripe.com/docs/api#create_person.
type PersonParams struct {
	Params         `form:"*"`
	Account        *string                   `form:"-"` // Included in URL
	Address        *AccountAddressParams     `form:"address"`
	AddressKana    *AccountAddressParams     `form:"address_kana"`
	AddressKanji   *AccountAddressParams     `form:"address_kanji"`
	DOB            *DOBParams                `form:"dob"`
	Email          *string                   `form:"email"`
	FirstName      *string                   `form:"first_name"`
	FirstNameKana  *string                   `form:"first_name_kana"`
	FirstNameKanji *string                   `form:"first_name_kanji"`
	Gender         *string                   `form:"gender"`
	IDNumber       *string                   `form:"id_number"`
	LastName       *string                   `form:"last_name"`
	LastNameKana   *string                   `form:"last_name_kana"`
	LastNameKanji  *string                   `form:"last_name_kanji"`
	MaidenName     *string                   `form:"maiden_name"`
	PersonToken    *string                   `form:"person_token"`
	Phone          *string                   `form:"phone"`
	Relationship   *RelationshipParams       `form:"relationship"`
	SSNLast4       *string                   `form:"ssn_last_4"`
	Verification   *PersonVerificationParams `form:"verification"`
}

// RelationshipListParams is used to filter persons by the relationship
type RelationshipListParams struct {
	Director       *bool `form:"director"`
	Executive      *bool `form:"executive"`
	Owner          *bool `form:"owner"`
	Representative *bool `form:"representative"`
}

// PersonListParams is the set of parameters that can be used when listing persons.
// For more detail see https://stripe.com/docs/api#list_persons.
type PersonListParams struct {
	ListParams   `form:"*"`
	Account      *string                 `form:"-"` // Included in URL
	Relationship *RelationshipListParams `form:"relationship"`
}

// DOB represents a Person's date of birth.
type DOB struct {
	Day   int64 `json:"day"`
	Month int64 `json:"month"`
	Year  int64 `json:"year"`
}

// Relationship represents how the Person relates to the business.
type Relationship struct {
	Director         bool    `json:"director"`
	Executive        bool    `json:"executive"`
	Owner            bool    `json:"owner"`
	PercentOwnership float64 `json:"percent_ownership"`
	Representative   bool    `json:"representative"`
	Title            string  `json:"title"`
}

// Requirements represents what's missing to verify a Person.
type Requirements struct {
	CurrentlyDue        []string                    `json:"currently_due"`
	Errors              []*AccountRequirementsError `json:"errors"`
	EventuallyDue       []string                    `json:"eventually_due"`
	PastDue             []string                    `json:"past_due"`
	PendingVerification []string                    `json:"pending_verification"`
}

// PersonVerificationDocument represents the documents associated with a Person.
type PersonVerificationDocument struct {
	Back        *File                           `json:"back"`
	Details     string                          `json:"details"`
	DetailsCode VerificationDocumentDetailsCode `json:"details_code"`
	Front       *File                           `json:"front"`
}

// PersonVerification is the structure for a person's verification details.
type PersonVerification struct {
	AdditionalDocument *PersonVerificationDocument   `json:"additional_document"`
	Details            string                        `json:"details"`
	DetailsCode        PersonVerificationDetailsCode `json:"details_code"`
	Document           *PersonVerificationDocument   `json:"document"`
	Status             IdentityVerificationStatus    `json:"status"`
}

// Person is the resource representing a Stripe person.
// For more details see https://stripe.com/docs/api#persons.
type Person struct {
	APIResource
	Account          string              `json:"account"`
	Address          *AccountAddress     `json:"address"`
	AddressKana      *AccountAddress     `json:"address_kana"`
	AddressKanji     *AccountAddress     `json:"address_kanji"`
	Deleted          bool                `json:"deleted"`
	DOB              *DOB                `json:"dob"`
	Email            string              `json:"email"`
	FirstName        string              `json:"first_name"`
	FirstNameKana    string              `json:"first_name_kana"`
	FirstNameKanji   string              `json:"first_name_kanji"`
	Gender           string              `json:"gender"`
	ID               string              `json:"id"`
	IDNumberProvided bool                `json:"id_number_provided"`
	LastName         string              `json:"last_name"`
	LastNameKana     string              `json:"last_name_kana"`
	LastNameKanji    string              `json:"last_name_kanji"`
	MaidenName       string              `json:"maiden_name"`
	Metadata         map[string]string   `json:"metadata"`
	Object           string              `json:"object"`
	Phone            string              `json:"phone"`
	Relationship     *Relationship       `json:"relationship"`
	Requirements     *Requirements       `json:"requirements"`
	SSNLast4Provided bool                `json:"ssn_last_4_provided"`
	Verification     *PersonVerification `json:"verification"`
}

// PersonList is a list of persons as retrieved from a list endpoint.
type PersonList struct {
	APIResource
	ListMeta
	Data []*Person `json:"data"`
}

// UnmarshalJSON handles deserialization of a Person.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (c *Person) UnmarshalJSON(data []byte) error {
	if id, ok := ParseID(data); ok {
		c.ID = id
		return nil
	}

	type person Person
	var v person
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}

	*c = Person(v)
	return nil
}
<commit_msg>Add support for `PoliticalExposure` on `Person`<commit_after>package stripe

import "encoding/json"

// VerificationDocumentDetailsCode is a machine-readable code specifying the verification state of
// a document associated with a person.
type VerificationDocumentDetailsCode string

// List of values that IdentityVerificationDetailsCode can take.
const (
	VerificationDocumentDetailsCodeDocumentCorrupt               VerificationDocumentDetailsCode = "document_corrupt"
	VerificationDocumentDetailsCodeDocumentFailedCopy            VerificationDocumentDetailsCode = "document_failed_copy"
	VerificationDocumentDetailsCodeDocumentFailedGreyscale       VerificationDocumentDetailsCode = "document_failed_greyscale"
	VerificationDocumentDetailsCodeDocumentFailedOther           VerificationDocumentDetailsCode = "document_failed_other"
	VerificationDocumentDetailsCodeDocumentFailedTestMode        VerificationDocumentDetailsCode = "document_failed_test_mode"
	VerificationDocumentDetailsCodeDocumentFraudulent            VerificationDocumentDetailsCode = "document_fraudulent"
	VerificationDocumentDetailsCodeDocumentIDTypeNotSupported    VerificationDocumentDetailsCode = "document_id_type_not_supported"
	VerificationDocumentDetailsCodeDocumentIDCountryNotSupported VerificationDocumentDetailsCode = "document_id_country_not_supported"
	VerificationDocumentDetailsCodeDocumentManipulated           VerificationDocumentDetailsCode = "document_manipulated"
	VerificationDocumentDetailsCodeDocumentMissingBack           VerificationDocumentDetailsCode = "document_missing_back"
	VerificationDocumentDetailsCodeDocumentMissingFront          VerificationDocumentDetailsCode = "document_missing_front"
	VerificationDocumentDetailsCodeDocumentNotReadable           VerificationDocumentDetailsCode = "document_not_readable"
	VerificationDocumentDetailsCodeDocumentNotUploaded           VerificationDocumentDetailsCode = "document_not_uploaded"
	VerificationDocumentDetailsCodeDocumentTooLarge              VerificationDocumentDetailsCode = "document_too_large"
)

// PersonPoliticalExposure describes the political exposure of a given person.
type PersonPoliticalExposure string

// List of values that IdentityVerificationStatus can take.
const (
	PersonPoliticalExposureExisting PersonPoliticalExposure = "existing"
	PersonPoliticalExposureNone     PersonPoliticalExposure = "none"
)

// PersonVerificationDetailsCode is a machine-readable code specifying the verification state of a
// person.
type PersonVerificationDetailsCode string

// List of values that IdentityVerificationDetailsCode can take.
const (
	PersonVerificationDetailsCodeFailedKeyedIdentity PersonVerificationDetailsCode = "failed_keyed_identity"
	PersonVerificationDetailsCodeFailedOther         PersonVerificationDetailsCode = "failed_other"
	PersonVerificationDetailsCodeScanNameMismatch    PersonVerificationDetailsCode = "scan_name_mismatch"
)

// IdentityVerificationStatus describes the different statuses for identity verification.
type IdentityVerificationStatus string

// List of values that IdentityVerificationStatus can take.
const (
	IdentityVerificationStatusPending    IdentityVerificationStatus = "pending"
	IdentityVerificationStatusUnverified IdentityVerificationStatus = "unverified"
	IdentityVerificationStatusVerified   IdentityVerificationStatus = "verified"
)

// DOBParams represents a DOB during account creation/updates.
type DOBParams struct {
	Day   *int64 `form:"day"`
	Month *int64 `form:"month"`
	Year  *int64 `form:"year"`
}

// RelationshipParams is used to set the relationship between an account and a person.
type RelationshipParams struct {
	Director         *bool    `form:"director"`
	Executive        *bool    `form:"executive"`
	Owner            *bool    `form:"owner"`
	PercentOwnership *float64 `form:"percent_ownership"`
	Representative   *bool    `form:"representative"`
	Title            *string  `form:"title"`
}

// PersonVerificationDocumentParams represents the parameters available for the document verifying
// a person's identity.
type PersonVerificationDocumentParams struct {
	Back  *string `form:"back"`
	Front *string `form:"front"`
}

// PersonVerificationParams is used to represent parameters associated with a person's verification
// details.
type PersonVerificationParams struct {
	AdditionalDocument *PersonVerificationDocumentParams `form:"additional_document"`
	Document           *PersonVerificationDocumentParams `form:"document"`
}

// PersonParams is the set of parameters that can be used when creating or updating a person.
// For more details see https://stripe.com/docs/api#create_person.
type PersonParams struct {
	Params            `form:"*"`
	Account           *string                   `form:"-"` // Included in URL
	Address           *AccountAddressParams     `form:"address"`
	AddressKana       *AccountAddressParams     `form:"address_kana"`
	AddressKanji      *AccountAddressParams     `form:"address_kanji"`
	DOB               *DOBParams                `form:"dob"`
	Email             *string                   `form:"email"`
	FirstName         *string                   `form:"first_name"`
	FirstNameKana     *string                   `form:"first_name_kana"`
	FirstNameKanji    *string                   `form:"first_name_kanji"`
	Gender            *string                   `form:"gender"`
	IDNumber          *string                   `form:"id_number"`
	LastName          *string                   `form:"last_name"`
	LastNameKana      *string                   `form:"last_name_kana"`
	LastNameKanji     *string                   `form:"last_name_kanji"`
	MaidenName        *string                   `form:"maiden_name"`
	PersonToken       *string                   `form:"person_token"`
	Phone             *string                   `form:"phone"`
	PoliticalExposure *string                   `form:"political_exposure"`
	Relationship      *RelationshipParams       `form:"relationship"`
	SSNLast4          *string                   `form:"ssn_last_4"`
	Verification      *PersonVerificationParams `form:"verification"`
}

// RelationshipListParams is used to filter persons by the relationship
type RelationshipListParams struct {
	Director       *bool `form:"director"`
	Executive      *bool `form:"executive"`
	Owner          *bool `form:"owner"`
	Representative *bool `form:"representative"`
}

// PersonListParams is the set of parameters that can be used when listing persons.
// For more detail see https://stripe.com/docs/api#list_persons.
type PersonListParams struct {
	ListParams   `form:"*"`
	Account      *string                 `form:"-"` // Included in URL
	Relationship *RelationshipListParams `form:"relationship"`
}

// DOB represents a Person's date of birth.
type DOB struct {
	Day   int64 `json:"day"`
	Month int64 `json:"month"`
	Year  int64 `json:"year"`
}

// Relationship represents how the Person relates to the business.
type Relationship struct {
	Director         bool    `json:"director"`
	Executive        bool    `json:"executive"`
	Owner            bool    `json:"owner"`
	PercentOwnership float64 `json:"percent_ownership"`
	Representative   bool    `json:"representative"`
	Title            string  `json:"title"`
}

// Requirements represents what's missing to verify a Person.
type Requirements struct {
	CurrentlyDue        []string                    `json:"currently_due"`
	Errors              []*AccountRequirementsError `json:"errors"`
	EventuallyDue       []string                    `json:"eventually_due"`
	PastDue             []string                    `json:"past_due"`
	PendingVerification []string                    `json:"pending_verification"`
}

// PersonVerificationDocument represents the documents associated with a Person.
type PersonVerificationDocument struct {
	Back        *File                           `json:"back"`
	Details     string                          `json:"details"`
	DetailsCode VerificationDocumentDetailsCode `json:"details_code"`
	Front       *File                           `json:"front"`
}

// PersonVerification is the structure for a person's verification details.
type PersonVerification struct {
	AdditionalDocument *PersonVerificationDocument   `json:"additional_document"`
	Details            string                        `json:"details"`
	DetailsCode        PersonVerificationDetailsCode `json:"details_code"`
	Document           *PersonVerificationDocument   `json:"document"`
	Status             IdentityVerificationStatus    `json:"status"`
}

// Person is the resource representing a Stripe person.
// For more details see https://stripe.com/docs/api#persons.
type Person struct {
	APIResource
	Account           string                  `json:"account"`
	Address           *AccountAddress         `json:"address"`
	AddressKana       *AccountAddress         `json:"address_kana"`
	AddressKanji      *AccountAddress         `json:"address_kanji"`
	Deleted           bool                    `json:"deleted"`
	DOB               *DOB                    `json:"dob"`
	Email             string                  `json:"email"`
	FirstName         string                  `json:"first_name"`
	FirstNameKana     string                  `json:"first_name_kana"`
	FirstNameKanji    string                  `json:"first_name_kanji"`
	Gender            string                  `json:"gender"`
	ID                string                  `json:"id"`
	IDNumberProvided  bool                    `json:"id_number_provided"`
	LastName          string                  `json:"last_name"`
	LastNameKana      string                  `json:"last_name_kana"`
	LastNameKanji     string                  `json:"last_name_kanji"`
	MaidenName        string                  `json:"maiden_name"`
	Metadata          map[string]string       `json:"metadata"`
	Object            string                  `json:"object"`
	Phone             string                  `json:"phone"`
	PoliticalExposure PersonPoliticalExposure `json:"political_exposure"`
	Relationship      *Relationship           `json:"relationship"`
	Requirements      *Requirements           `json:"requirements"`
	SSNLast4Provided  bool                    `json:"ssn_last_4_provided"`
	Verification      *PersonVerification     `json:"verification"`
}

// PersonList is a list of persons as retrieved from a list endpoint.
type PersonList struct {
	APIResource
	ListMeta
	Data []*Person `json:"data"`
}

// UnmarshalJSON handles deserialization of a Person.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (c *Person) UnmarshalJSON(data []byte) error {
	if id, ok := ParseID(data); ok {
		c.ID = id
		return nil
	}

	type person Person
	var v person
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}

	*c = Person(v)
	return nil
}
<|endoftext|>


<commit_before>/**
 *  Copyright 2014 Paul Querna
 *
 *  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 prettytable

import (
	"bytes"
	"fmt"
	"github.com/pquerna/termchalk/runewidth"
	"sort"
	"strings"
)

type PrettyTableSorter func(n int, s InterfaceArray) sort.Interface

type PrettyTable struct {
	header      []string
	rows        [][]interface{}
	rowsStr     [][]string
	SortBy      string
	SortReverse bool
	Sorter      PrettyTableSorter
	Styler      Styler
}

func New(header []string) *PrettyTable {
	return &PrettyTable{
		rows:   make([][]interface{}, 0),
		header: header,
		Sorter: NewMungeSorter,
		Styler: &DefaultStyle{},
	}
}

func pos(needle string, haystack []string) int {
	for i, v := range haystack {
		if v == needle {
			return i
		}
	}

	return -1
}

func (pt *PrettyTable) AddRow(args ...interface{}) {
	pt.rows = append(pt.rows, args)
}

func intMax(a int, b int) int {
	if a > b {
		return a
	}
	return b
}

func cellStr(v interface{}) string {
	return fmt.Sprint(v)
}

func longestLine(s string) int {
	rv := 0
	for _, v := range strings.Split(s, "\n") {
		rv = intMax(runewidth.Width(v), rv)
	}
	return rv
}

func (pt *PrettyTable) styleData() {
	var headers = make([]string, len(pt.header))
	for i, v := range pt.header {
		headers[i] = pt.Styler.Header(i, v)
	}

	var rows = make([][]string, len(pt.rows))
	for i, row := range pt.rows {
		rows[i] = make([]string, len(row))
		for j, cell := range row {
			rows[i][j] = pt.Styler.Cell(pt.header[j], i, j, cellStr(cell))
		}
	}

	pt.header = headers
	pt.rowsStr = rows
}

func (pt *PrettyTable) colWidths() []int {
	widths := make([]int, len(pt.header))
	padding := pt.Styler.Padding() * 2
	for i, v := range pt.header {
		widths[i] = runewidth.Width(v) + padding
	}

	for _, row := range pt.rows {
		for j, cell := range row {
			if j > len(pt.header) {
				continue
			}

			s := cellStr(cell)
			widths[j] = intMax(longestLine(s)+padding, widths[j])
		}
	}

	return widths
}

func (pt *PrettyTable) String() string {
	b := bytes.Buffer{}

	if pt.SortBy != "" {
		n := pos(pt.SortBy, pt.header)
		if n != -1 {
			s := pt.Sorter(n, pt.rows)
			if pt.SortReverse {
				sort.Sort(sort.Reverse(s))
			} else {
				sort.Sort(s)
			}
		}
	}

	pt.styleData()

	colWidths := pt.colWidths()

	// TODO: refactor
	b.WriteString(pt.Styler.TopLeft())
	for i, v := range colWidths {
		b.WriteString(strings.Repeat(pt.Styler.Top(), v))
		if i < len(colWidths)-1 {
			b.WriteString(pt.Styler.TopMid())
		}
	}
	b.WriteString(pt.Styler.TopRight())
	b.WriteString("\n")

	b.WriteString(pt.Styler.Left())
	for i, v := range pt.header {
		// TODO: padding/centers
		cstr := padString(
			v,
			colWidths[i],
			" ",
			pt.Styler.Alignment())

		b.WriteString(cstr)
		if i < len(pt.header)-1 {
			b.WriteString(pt.Styler.Middle())
		}
	}
	b.WriteString(pt.Styler.Right())
	b.WriteString("\n")

	b.WriteString(pt.Styler.Left())
	for i, v := range colWidths {
		b.WriteString(strings.Repeat(pt.Styler.Mid(), v))
		if i < len(colWidths)-1 {
			b.WriteString(pt.Styler.MidMid())
		}
	}
	b.WriteString(pt.Styler.Right())
	b.WriteString("\n")

	for _, v := range pt.rowsStr {
		// TODO: padding/centers
		// TOOD: multi-line strings
		b.WriteString(pt.Styler.Left())
		for i, cell := range v {
			cstr := padString(
				cell,
				colWidths[i],
				" ",
				pt.Styler.Alignment())

			b.WriteString(cstr)
			if i < len(v)-1 {
				b.WriteString(pt.Styler.Middle())
			}
		}
		b.WriteString(pt.Styler.Right())
		b.WriteString("\n")
	}

	// TODO: refactor
	b.WriteString(pt.Styler.BottomLeft())
	for i, v := range colWidths {
		b.WriteString(strings.Repeat(pt.Styler.Bottom(), v))
		if i < len(colWidths)-1 {
			b.WriteString(pt.Styler.BottomMid())
		}
	}
	b.WriteString(pt.Styler.BottomRight())
	b.WriteString("\n")

	return b.String()
}
<commit_msg>Add writeLine func<commit_after>/**
 *  Copyright 2014 Paul Querna
 *
 *  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 prettytable

import (
	"bytes"
	"fmt"
	"github.com/pquerna/termchalk/runewidth"
	"github.com/pquerna/termchalk/terminfo"
	"sort"
	"strings"
)

type PrettyTableSorter func(n int, s InterfaceArray) sort.Interface

type PrettyTable struct {
	header      []string
	rows        [][]interface{}
	rowsStr     [][]string
	SortBy      string
	SortReverse bool
	Sorter      PrettyTableSorter
	Styler      Styler
}

func New(header []string) *PrettyTable {
	return &PrettyTable{
		rows:   make([][]interface{}, 0),
		header: header,
		Sorter: NewMungeSorter,
		Styler: &DefaultStyle{},
	}
}

func pos(needle string, haystack []string) int {
	for i, v := range haystack {
		if v == needle {
			return i
		}
	}

	return -1
}

func (pt *PrettyTable) AddRow(args ...interface{}) {
	pt.rows = append(pt.rows, args)
}

func intMax(a int, b int) int {
	if a > b {
		return a
	}
	return b
}

func cellStr(v interface{}) string {
	return fmt.Sprint(v)
}

func longestLine(s string) int {
	rv := 0
	for _, v := range strings.Split(s, "\n") {
		rv = intMax(runewidth.Width(v), rv)
	}
	return rv
}

func (pt *PrettyTable) styleData() {
	var headers = make([]string, len(pt.header))
	for i, v := range pt.header {
		headers[i] = pt.Styler.Header(i, v)
	}

	var rows = make([][]string, len(pt.rows))
	for i, row := range pt.rows {
		rows[i] = make([]string, len(row))
		for j, cell := range row {
			rows[i][j] = pt.Styler.Cell(pt.header[j], i, j, cellStr(cell))
		}
	}

	pt.header = headers
	pt.rowsStr = rows
	pt.rows = nil
}

func (pt *PrettyTable) colWidths() []int {
	widths := make([]int, len(pt.header))
	padding := pt.Styler.Padding() * 2
	for i, v := range pt.header {
		widths[i] = runewidth.Width(v) + padding
	}

	for _, row := range pt.rows {
		for j, cell := range row {
			if j > len(pt.header) {
				continue
			}

			s := cellStr(cell)
			widths[j] = intMax(longestLine(s)+padding, widths[j])
		}
	}

	return widths
}

type StringWriter interface {
	WriteString(s string) (n int, err error)
}

func (pt *PrettyTable) writeLine(b StringWriter, widths []int,
	left string, line string, mid string, right string) {

	b.WriteString(left)
	for i, v := range widths {
		b.WriteString(strings.Repeat(line, v))
		if i < len(widths)-1 {
			b.WriteString(mid)
		}
	}
	b.WriteString(right)
	b.WriteString("\n")
}

func (pt *PrettyTable) Outout(b StringWriter) {

	termwidth := terminfo.WindowWidth()

	// if stdout isn't a terminal, eg we are piped to a log
	// do the most reasonable thing: 80 characters wide.
	if termwidth == 0 {
		termwidth = 80
	}

	if pt.SortBy != "" {
		n := pos(pt.SortBy, pt.header)
		if n != -1 {
			s := pt.Sorter(n, pt.rows)
			if pt.SortReverse {
				sort.Sort(sort.Reverse(s))
			} else {
				sort.Sort(s)
			}
		}
	}

	pt.styleData()

	colWidths := pt.colWidths()

	pt.writeLine(b, colWidths,
		pt.Styler.TopLeft(),
		pt.Styler.Top(),
		pt.Styler.TopMid(),
		pt.Styler.TopRight())

	b.WriteString(pt.Styler.Left())
	for i, v := range pt.header {
		// TODO: padding/centers
		cstr := padString(
			v,
			colWidths[i],
			" ",
			pt.Styler.Alignment())

		b.WriteString(cstr)
		if i < len(pt.header)-1 {
			b.WriteString(pt.Styler.Middle())
		}
	}
	b.WriteString(pt.Styler.Right())
	b.WriteString("\n")

	pt.writeLine(b, colWidths,
		pt.Styler.Left(),
		pt.Styler.Mid(),
		pt.Styler.MidMid(),
		pt.Styler.Right())

	for _, v := range pt.rowsStr {
		// TODO: padding/centers
		// TOOD: multi-line strings
		b.WriteString(pt.Styler.Left())
		for i, cell := range v {
			cstr := padString(
				cell,
				colWidths[i],
				" ",
				pt.Styler.Alignment())

			b.WriteString(cstr)
			if i < len(v)-1 {
				b.WriteString(pt.Styler.Middle())
			}
		}
		b.WriteString(pt.Styler.Right())
		b.WriteString("\n")
	}

	pt.writeLine(b, colWidths,
		pt.Styler.BottomLeft(),
		pt.Styler.Bottom(),
		pt.Styler.BottomMid(),
		pt.Styler.BottomRight())

}

func (pt *PrettyTable) String() string {
	b := bytes.Buffer{}
	pt.Outout(&b)
	return b.String()
}
<|endoftext|>


<commit_before>// Copyright 2019 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package engine

import (
	"fmt"
	"sort"
	"strings"

	"github.com/keybase/client/go/kbun"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

// PassphraseRecover is an engine that implements the "password recovery" flow,
// where the user is shown instructions on how to either change their password
// on other devices or allows them to change the password using a paper key.
type PassphraseRecover struct {
	arg keybase1.RecoverPassphraseArg
	libkb.Contextified
	usernameFound bool
}

func NewPassphraseRecover(g *libkb.GlobalContext, arg keybase1.RecoverPassphraseArg) *PassphraseRecover {
	return &PassphraseRecover{
		arg:          arg,
		Contextified: libkb.NewContextified(g),
	}
}

// Name provides the name of the engine for the engine interface
func (e *PassphraseRecover) Name() string {
	return "PassphraseRecover"
}

// Prereqs returns engine prereqs
func (e *PassphraseRecover) Prereqs() Prereqs {
	return Prereqs{}
}

// RequiredUIs returns the required UIs.
func (e *PassphraseRecover) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{
		libkb.LoginUIKind,
		libkb.ProvisionUIKind,
		libkb.SecretUIKind,
	}
}

// SubConsumers requires the other UI consumers of this engine
func (e *PassphraseRecover) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{
		&LoginWithPaperKey{},
	}
}

// Run the engine
func (e *PassphraseRecover) Run(mctx libkb.MetaContext) (err error) {
	defer mctx.Trace("PassphraseRecover#Run", func() error { return err })()

	// Look up the passed username against the list of configured users
	if err := e.processUsername(mctx); err != nil {
		return err
	}

	// If the reset pipeline is not enabled, we'll want this to act exactly the same way as before
	// Autoreset hardcoded on for now.
	// TODO: Y2K-3 cleanup for autoreset.
	autoresetEnabled := true
	if !autoresetEnabled {
		// The device has to be preprovisioned for this account in this flow
		if !e.usernameFound {
			return libkb.NotProvisionedError{}
		}
		return e.legacyRecovery(mctx)
	}

	// In the new flow we noop if we're already logged in
	if loggedIn, _ := isLoggedIn(mctx); loggedIn {
		mctx.Warning("Already logged in with unlocked device keys")
		return libkb.LoggedInError{}
	}
	mctx.Debug("No device keys available, proceeding with recovery")

	// Load the user by username
	ueng := newLoginLoadUser(mctx.G(), e.arg.Username)
	if err := RunEngine2(mctx, ueng); err != nil {
		return err
	}

	// Now we're taking that user info and evaluating our options
	ckf := ueng.User().GetComputedKeyFamily()
	if ckf == nil {
		return libkb.NewNotFoundError("Account missing key family")
	}

	if !ckf.HasActiveDevice() {
		// Go directly to reset
		return e.resetPassword(mctx)
	}

	return e.chooseDevice(mctx, ckf)
}

func (e *PassphraseRecover) processUsername(mctx libkb.MetaContext) error {
	// Fetch usernames from user configs
	currentUsername, otherUsernames, err := mctx.G().GetAllUserNames()
	if err != nil {
		return err
	}
	usernamesMap := map[libkb.NormalizedUsername]struct{}{
		currentUsername: {},
	}
	for _, username := range otherUsernames {
		usernamesMap[username] = struct{}{}
	}

	var normalized kbun.NormalizedUsername
	if e.arg.Username != "" {
		normalized = libkb.NewNormalizedUsername(e.arg.Username)
	} else {
		normalized = currentUsername
	}
	e.arg.Username = normalized.String()

	// Check if the passed username is in the map
	_, ok := usernamesMap[normalized]
	e.usernameFound = ok
	return nil
}

// TODO CORE-10851: Remove
func (e *PassphraseRecover) legacyRecovery(mctx libkb.MetaContext) (err error) {
	if loggedIn, _ := isLoggedIn(mctx); loggedIn {
		return e.changePassword(mctx)
	}

	return e.loginWithPaperKey(mctx)
}

func (e *PassphraseRecover) chooseDevice(mctx libkb.MetaContext, ckf *libkb.ComputedKeyFamily) (err error) {
	defer mctx.Trace("PassphraseRecover#chooseDevice", func() error { return err })()

	// Reorder the devices for the list
	devices := partitionDeviceList(ckf.GetAllActiveDevices())
	sort.Sort(devices)

	// Choose an existing device
	expDevices := make([]keybase1.Device, 0, len(devices))
	idMap := make(map[keybase1.DeviceID]*libkb.Device)
	for _, d := range devices {
		// Don't show paper keys if the user has not provisioned on this device
		if !e.usernameFound && d.Type == libkb.DeviceTypePaper {
			continue
		}
		expDevices = append(expDevices, *d.ProtExport())
		idMap[d.ID] = d
	}
	id, err := mctx.UIs().ProvisionUI.ChooseDevice(mctx.Ctx(), keybase1.ChooseDeviceArg{
		Devices:           expDevices,
		CanSelectNoDevice: true,
	})
	if err != nil {
		return err
	}

	// No device chosen, we're going into the reset flow
	if len(id) == 0 {
		// Go directly to reset
		return e.suggestReset(mctx)
	}

	mctx.Debug("user selected device %s", id)
	selected, ok := idMap[id]
	if !ok {
		return fmt.Errorf("selected device %s not in local device map", id)
	}
	mctx.Debug("device details: %+v", selected)

	// Roughly the same flow as in provisioning
	switch selected.Type {
	case libkb.DeviceTypePaper:
		return e.loginWithPaperKey(mctx)
	case libkb.DeviceTypeDesktop, libkb.DeviceTypeMobile:
		return e.explainChange(mctx, selected)
	default:
		return fmt.Errorf("unknown device type: %v", selected.Type)
	}
}

func (e *PassphraseRecover) resetPassword(mctx libkb.MetaContext) (err error) {
	enterReset, err := mctx.UIs().LoginUI.PromptResetAccount(mctx.Ctx(), keybase1.PromptResetAccountArg{
		Prompt: keybase1.NewResetPromptDefault(keybase1.ResetPromptType_ENTER_RESET_PW),
	})
	if err != nil {
		return err
	}
	if !enterReset {
		// Flow cancelled
		return nil
	}

	// User wants a reset password email
	res, err := mctx.G().API.Post(mctx, libkb.APIArg{
		Endpoint:    "send-reset-pw",
		SessionType: libkb.APISessionTypeNONE,
		Args: libkb.HTTPArgs{
			"email_or_username": libkb.S{Val: e.arg.Username},
		},
		AppStatusCodes: []int{libkb.SCOk, libkb.SCBadLoginUserNotFound},
	})
	if err != nil {
		return err
	}
	if res.AppStatus.Code == libkb.SCBadLoginUserNotFound {
		return libkb.NotFoundError{Msg: "User not found"}
	}
	mctx.Info("A reset link has been sent to primary email")
	return nil
}

func (e *PassphraseRecover) suggestReset(mctx libkb.MetaContext) (err error) {
	enterReset, err := mctx.UIs().LoginUI.PromptResetAccount(mctx.Ctx(), keybase1.PromptResetAccountArg{
		Prompt: keybase1.NewResetPromptDefault(keybase1.ResetPromptType_ENTER_FORGOT_PW),
	})
	if err != nil {
		return err
	}
	if !enterReset {
		// Cancel the engine as it successfully resulted in the user entering the reset pipeline.
		return nil
	}

	// We are certain the user will not know their password, so we can disable that prompt.
	eng := NewAccountReset(mctx.G(), e.arg.Username)
	eng.skipPasswordPrompt = true
	if err := eng.Run(mctx); err != nil {
		return err
	}

	// We're ignoring eng.ResetPending() as we've disabled reset completion
	return nil
}

func (e *PassphraseRecover) loginWithPaperKey(mctx libkb.MetaContext) (err error) {
	// First log in using the paper key
	loginEng := NewLoginWithPaperKey(mctx.G(), e.arg.Username)
	if err := RunEngine2(mctx, loginEng); err != nil {
		return err
	}

	if err := e.changePassword(mctx); err != nil {
		// Log out before returning
		if err2 := RunEngine2(mctx, NewLogout(libkb.LogoutOptions{KeepSecrets: false, Force: true})); err2 != nil {
			mctx.Warning("Unable to log out after password change failed: %v", err2)
		}

		return err
	}

	mctx.Debug("PassphraseRecover with paper key success, sending login notification")
	mctx.G().NotifyRouter.HandleLogin(mctx.Ctx(), e.arg.Username)
	mctx.Debug("PassphraseRecover with paper key success, calling login hooks")
	mctx.G().CallLoginHooks(mctx)

	return nil
}

func (e *PassphraseRecover) changePassword(mctx libkb.MetaContext) (err error) {
	// Once logged in, check if there are any server keys
	hskEng := NewHasServerKeys(mctx.G())
	if err := RunEngine2(mctx, hskEng); err != nil {
		return err
	}
	if hskEng.GetResult().HasServerKeys {
		// Prompt the user explaining that they'll lose server keys
		proceed, err := mctx.UIs().LoginUI.PromptPassphraseRecovery(mctx.Ctx(), keybase1.PromptPassphraseRecoveryArg{
			Kind: keybase1.PassphraseRecoveryPromptType_ENCRYPTED_PGP_KEYS,
		})
		if err != nil {
			return err
		}
		if !proceed {
			mctx.Info("Password recovery canceled")
			return libkb.NewCanceledError("Password recovery canceled")
		}
	}

	// We either have no server keys or the user is OK with resetting them
	// Prompt the user for a new passphrase.
	passphrase, err := e.promptPassphrase(mctx)
	if err != nil {
		return err
	}

	// ppres.Passphrase contains our new password
	// Run passphrase change to finish the flow
	changeEng := NewPassphraseChange(mctx.G(), &keybase1.PassphraseChangeArg{
		Passphrase: passphrase,
		Force:      true,
	})
	if err := RunEngine2(mctx, changeEng); err != nil {
		return err
	}

	// We have a new passphrase!
	return nil
}

func (e *PassphraseRecover) explainChange(mctx libkb.MetaContext, device *libkb.Device) (err error) {
	var name string
	if device.Description != nil {
		name = *device.Description
	}

	// The actual contents of the shown prompt will depend on the UI impl
	return mctx.UIs().LoginUI.ExplainDeviceRecovery(mctx.Ctx(), keybase1.ExplainDeviceRecoveryArg{
		Name: name,
		Kind: keybase1.DeviceTypeMap[strings.ToUpper(device.Type)],
	})
}

func (e *PassphraseRecover) promptPassphrase(mctx libkb.MetaContext) (string, error) {
	arg := libkb.DefaultPassphraseArg(mctx)
	arg.WindowTitle = "Pick a new passphrase"
	arg.Prompt = fmt.Sprintf("Pick a new strong passphrase (%d+ characters)", libkb.MinPassphraseLength)
	arg.Type = keybase1.PassphraseType_VERIFY_PASS_PHRASE

	ppres, err := libkb.GetKeybasePassphrase(mctx, mctx.UIs().SecretUI, arg)
	if err != nil {
		return "", err
	}
	return ppres.Passphrase, nil
}
<commit_msg>fix passphrase recovery if no username is passed (#20336)<commit_after>// Copyright 2019 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package engine

import (
	"fmt"
	"sort"
	"strings"

	"github.com/keybase/client/go/kbun"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

// PassphraseRecover is an engine that implements the "password recovery" flow,
// where the user is shown instructions on how to either change their password
// on other devices or allows them to change the password using a paper key.
type PassphraseRecover struct {
	arg keybase1.RecoverPassphraseArg
	libkb.Contextified
	usernameFound bool
}

func NewPassphraseRecover(g *libkb.GlobalContext, arg keybase1.RecoverPassphraseArg) *PassphraseRecover {
	return &PassphraseRecover{
		arg:          arg,
		Contextified: libkb.NewContextified(g),
	}
}

// Name provides the name of the engine for the engine interface
func (e *PassphraseRecover) Name() string {
	return "PassphraseRecover"
}

// Prereqs returns engine prereqs
func (e *PassphraseRecover) Prereqs() Prereqs {
	return Prereqs{}
}

// RequiredUIs returns the required UIs.
func (e *PassphraseRecover) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{
		libkb.LoginUIKind,
		libkb.ProvisionUIKind,
		libkb.SecretUIKind,
	}
}

// SubConsumers requires the other UI consumers of this engine
func (e *PassphraseRecover) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{
		&LoginWithPaperKey{},
	}
}

// Run the engine
func (e *PassphraseRecover) Run(mctx libkb.MetaContext) (err error) {
	defer mctx.Trace("PassphraseRecover#Run", func() error { return err })()

	// If no username was passed, ask for one
	if e.arg.Username == "" {
		res, err := mctx.UIs().LoginUI.GetEmailOrUsername(mctx.Ctx(), 0)
		if err != nil {
			return err
		}
		e.arg.Username = res
	}

	// Look up the passed username against the list of configured users
	if err := e.processUsername(mctx); err != nil {
		return err
	}

	// If the reset pipeline is not enabled, we'll want this to act exactly the same way as before
	// Autoreset hardcoded on for now.
	// TODO: Y2K-3 cleanup for autoreset.
	autoresetEnabled := true
	if !autoresetEnabled {
		// The device has to be preprovisioned for this account in this flow
		if !e.usernameFound {
			return libkb.NotProvisionedError{}
		}
		return e.legacyRecovery(mctx)
	}

	// In the new flow we noop if we're already logged in
	if loggedIn, _ := isLoggedIn(mctx); loggedIn {
		mctx.Warning("Already logged in with unlocked device keys")
		return libkb.LoggedInError{}
	}
	mctx.Debug("No device keys available, proceeding with recovery")

	// Load the user by username
	ueng := newLoginLoadUser(mctx.G(), e.arg.Username)
	if err := RunEngine2(mctx, ueng); err != nil {
		return err
	}

	// Now we're taking that user info and evaluating our options
	ckf := ueng.User().GetComputedKeyFamily()
	if ckf == nil {
		return libkb.NewNotFoundError("Account missing key family")
	}

	if !ckf.HasActiveDevice() {
		// Go directly to reset
		return e.resetPassword(mctx)
	}

	return e.chooseDevice(mctx, ckf)
}

func (e *PassphraseRecover) processUsername(mctx libkb.MetaContext) error {
	// Fetch usernames from user configs
	currentUsername, otherUsernames, err := mctx.G().GetAllUserNames()
	if err != nil {
		return err
	}
	usernamesMap := map[libkb.NormalizedUsername]struct{}{
		currentUsername: {},
	}
	for _, username := range otherUsernames {
		usernamesMap[username] = struct{}{}
	}

	var normalized kbun.NormalizedUsername
	if e.arg.Username != "" {
		normalized = libkb.NewNormalizedUsername(e.arg.Username)
	} else {
		normalized = currentUsername
	}
	e.arg.Username = normalized.String()

	// Check if the passed username is in the map
	_, ok := usernamesMap[normalized]
	e.usernameFound = ok
	return nil
}

// TODO CORE-10851: Remove
func (e *PassphraseRecover) legacyRecovery(mctx libkb.MetaContext) (err error) {
	if loggedIn, _ := isLoggedIn(mctx); loggedIn {
		return e.changePassword(mctx)
	}

	return e.loginWithPaperKey(mctx)
}

func (e *PassphraseRecover) chooseDevice(mctx libkb.MetaContext, ckf *libkb.ComputedKeyFamily) (err error) {
	defer mctx.Trace("PassphraseRecover#chooseDevice", func() error { return err })()

	// Reorder the devices for the list
	devices := partitionDeviceList(ckf.GetAllActiveDevices())
	sort.Sort(devices)

	// Choose an existing device
	expDevices := make([]keybase1.Device, 0, len(devices))
	idMap := make(map[keybase1.DeviceID]*libkb.Device)
	for _, d := range devices {
		// Don't show paper keys if the user has not provisioned on this device
		if !e.usernameFound && d.Type == libkb.DeviceTypePaper {
			continue
		}
		expDevices = append(expDevices, *d.ProtExport())
		idMap[d.ID] = d
	}
	id, err := mctx.UIs().ProvisionUI.ChooseDevice(mctx.Ctx(), keybase1.ChooseDeviceArg{
		Devices:           expDevices,
		CanSelectNoDevice: true,
	})
	if err != nil {
		return err
	}

	// No device chosen, we're going into the reset flow
	if len(id) == 0 {
		// Go directly to reset
		return e.suggestReset(mctx)
	}

	mctx.Debug("user selected device %s", id)
	selected, ok := idMap[id]
	if !ok {
		return fmt.Errorf("selected device %s not in local device map", id)
	}
	mctx.Debug("device details: %+v", selected)

	// Roughly the same flow as in provisioning
	switch selected.Type {
	case libkb.DeviceTypePaper:
		return e.loginWithPaperKey(mctx)
	case libkb.DeviceTypeDesktop, libkb.DeviceTypeMobile:
		return e.explainChange(mctx, selected)
	default:
		return fmt.Errorf("unknown device type: %v", selected.Type)
	}
}

func (e *PassphraseRecover) resetPassword(mctx libkb.MetaContext) (err error) {
	enterReset, err := mctx.UIs().LoginUI.PromptResetAccount(mctx.Ctx(), keybase1.PromptResetAccountArg{
		Prompt: keybase1.NewResetPromptDefault(keybase1.ResetPromptType_ENTER_RESET_PW),
	})
	if err != nil {
		return err
	}
	if !enterReset {
		// Flow cancelled
		return nil
	}

	// User wants a reset password email
	res, err := mctx.G().API.Post(mctx, libkb.APIArg{
		Endpoint:    "send-reset-pw",
		SessionType: libkb.APISessionTypeNONE,
		Args: libkb.HTTPArgs{
			"email_or_username": libkb.S{Val: e.arg.Username},
		},
		AppStatusCodes: []int{libkb.SCOk, libkb.SCBadLoginUserNotFound},
	})
	if err != nil {
		return err
	}
	if res.AppStatus.Code == libkb.SCBadLoginUserNotFound {
		return libkb.NotFoundError{Msg: "User not found"}
	}
	mctx.Info("A reset link has been sent to primary email")
	return nil
}

func (e *PassphraseRecover) suggestReset(mctx libkb.MetaContext) (err error) {
	enterReset, err := mctx.UIs().LoginUI.PromptResetAccount(mctx.Ctx(), keybase1.PromptResetAccountArg{
		Prompt: keybase1.NewResetPromptDefault(keybase1.ResetPromptType_ENTER_FORGOT_PW),
	})
	if err != nil {
		return err
	}
	if !enterReset {
		// Cancel the engine as it successfully resulted in the user entering the reset pipeline.
		return nil
	}

	// We are certain the user will not know their password, so we can disable that prompt.
	eng := NewAccountReset(mctx.G(), e.arg.Username)
	eng.skipPasswordPrompt = true
	if err := eng.Run(mctx); err != nil {
		return err
	}

	// We're ignoring eng.ResetPending() as we've disabled reset completion
	return nil
}

func (e *PassphraseRecover) loginWithPaperKey(mctx libkb.MetaContext) (err error) {
	// First log in using the paper key
	loginEng := NewLoginWithPaperKey(mctx.G(), e.arg.Username)
	if err := RunEngine2(mctx, loginEng); err != nil {
		return err
	}

	if err := e.changePassword(mctx); err != nil {
		// Log out before returning
		if err2 := RunEngine2(mctx, NewLogout(libkb.LogoutOptions{KeepSecrets: false, Force: true})); err2 != nil {
			mctx.Warning("Unable to log out after password change failed: %v", err2)
		}

		return err
	}

	mctx.Debug("PassphraseRecover with paper key success, sending login notification")
	mctx.G().NotifyRouter.HandleLogin(mctx.Ctx(), e.arg.Username)
	mctx.Debug("PassphraseRecover with paper key success, calling login hooks")
	mctx.G().CallLoginHooks(mctx)

	return nil
}

func (e *PassphraseRecover) changePassword(mctx libkb.MetaContext) (err error) {
	// Once logged in, check if there are any server keys
	hskEng := NewHasServerKeys(mctx.G())
	if err := RunEngine2(mctx, hskEng); err != nil {
		return err
	}
	if hskEng.GetResult().HasServerKeys {
		// Prompt the user explaining that they'll lose server keys
		proceed, err := mctx.UIs().LoginUI.PromptPassphraseRecovery(mctx.Ctx(), keybase1.PromptPassphraseRecoveryArg{
			Kind: keybase1.PassphraseRecoveryPromptType_ENCRYPTED_PGP_KEYS,
		})
		if err != nil {
			return err
		}
		if !proceed {
			mctx.Info("Password recovery canceled")
			return libkb.NewCanceledError("Password recovery canceled")
		}
	}

	// We either have no server keys or the user is OK with resetting them
	// Prompt the user for a new passphrase.
	passphrase, err := e.promptPassphrase(mctx)
	if err != nil {
		return err
	}

	// ppres.Passphrase contains our new password
	// Run passphrase change to finish the flow
	changeEng := NewPassphraseChange(mctx.G(), &keybase1.PassphraseChangeArg{
		Passphrase: passphrase,
		Force:      true,
	})
	if err := RunEngine2(mctx, changeEng); err != nil {
		return err
	}

	// We have a new passphrase!
	return nil
}

func (e *PassphraseRecover) explainChange(mctx libkb.MetaContext, device *libkb.Device) (err error) {
	var name string
	if device.Description != nil {
		name = *device.Description
	}

	// The actual contents of the shown prompt will depend on the UI impl
	return mctx.UIs().LoginUI.ExplainDeviceRecovery(mctx.Ctx(), keybase1.ExplainDeviceRecoveryArg{
		Name: name,
		Kind: keybase1.DeviceTypeMap[strings.ToUpper(device.Type)],
	})
}

func (e *PassphraseRecover) promptPassphrase(mctx libkb.MetaContext) (string, error) {
	arg := libkb.DefaultPassphraseArg(mctx)
	arg.WindowTitle = "Pick a new passphrase"
	arg.Prompt = fmt.Sprintf("Pick a new strong passphrase (%d+ characters)", libkb.MinPassphraseLength)
	arg.Type = keybase1.PassphraseType_VERIFY_PASS_PHRASE

	ppres, err := libkb.GetKeybasePassphrase(mctx, mctx.UIs().SecretUI, arg)
	if err != nil {
		return "", err
	}
	return ppres.Passphrase, nil
}
<|endoftext|>


<commit_before>package models

type Setting struct {
	Database map[string]string
}
<commit_msg>Change map[string]string to include structure.<commit_after>package models

type Setting struct {
	Database struct {
		Host string
	}
}
<|endoftext|>


<commit_before>package sample

import (
	"math"
	"reflect"
	"testing"
)

const tolerance = 1e-3

func equals(a, b, tolerance float64) bool {
	if math.Abs(a-b) < tolerance {
		return true
	}
	return false
}

func TestNewErrors(t *testing.T) {
	for i, f := range [...][]float64{
		{},
		{1.0},
	} {
		s, err := New(f)
		if s != nil {
			t.Fatalf("%d) in=%v, should have returned nil, but got: %v", i, f, s)
		}
		if err != ErrBesselNeedsTwo {
			t.Fatalf("%d) in=%v, should have returned ErrBesselNeedsTwo", i, f)
		}
	}
}

func TestNew(t *testing.T) {
	for i, f := range [...][]float64{
		{1.0, 1},
		{1.0, 2, -3.1415952},
		{1.0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
	} {
		s, err := New(f)
		if err != nil {
			t.Fatalf("%d) in=%v, returned error: %v", i, f, err)
		}
		if !reflect.DeepEqual(f, s.data) {
			t.Errorf("%d) in=%v, expected=%[2]v, got=%v", i, f, s.data)
		}
	}
}

func TestMean(t *testing.T) {
	for i, f := range [...]struct {
		in  []float64
		out float64
	}{
		{in: []float64{-1.0, -1.0}, out: -1.0},
		{in: []float64{1, 2, 3, 4, 5, 6}, out: 3.5},
		{in: []float64{0, 1, -1, 2, -2}, out: 0.0},
		{in: []float64{3.005, 3.005, 3.005, 3.005, 3.005, 3.005002, 3.004998}, out: 3.005},
	} {
		s, err := New(f.in)
		if err != nil {
			t.Fatalf("%d) in=%v, New returned error: %v", i, f.in, err)
		}
		got := s.Mean()
		if !equals(got, f.out, tolerance) {
			t.Errorf("%d) in=%v, out=%f, got=%f",
				i, f.in, f.out, got)
		}
	}
}

func TestMeanAlreadyComputed(t *testing.T) {
	f := []float64{1.0, 1}
	s, err := New(f)
	if err != nil {
		t.Fatalf("in=%v, New returned error: %v", f, err)
	}
	first := s.Mean()
	second := s.Mean()
	if !equals(first, second, tolerance) {
		t.Errorf("precomputed mean and new mean differs: sample=%v, first mean=%f, second mean=%f",
			f, first, second)
	}
}

func TestStandardDeviation(t *testing.T) {
	for i, f := range [...]struct {
		in  []float64
		out float64
	}{
		{in: []float64{1.0, 1.0}, out: 0.0},
		{in: []float64{1.0, 2.0}, out: 0.707},
		{in: []float64{1.0, 2, 3, 4, 5, 6}, out: 1.870},
		{in: []float64{-2.0, -1, 0, 1, 2, 3}, out: 1.870},
	} {
		s, err := New(f.in)
		if err != nil {
			t.Fatalf("%d) in=%v, New returned error: %v", i, f.in, err)
		}
		got := s.StandardDeviation()
		if !equals(got, f.out, tolerance) {
			t.Errorf("%d) in=%v, out=%f, got=%f",
				i, f.in, f.out, got)
		}
	}
}

func TestStandardDeviationAlreadyComputed(t *testing.T) {
	f := []float64{1.0, 1}
	s, err := New(f)
	if err != nil {
		t.Fatalf("in=%v, New returned error: %v", f, err)
	}
	first := s.StandardDeviation()
	second := s.StandardDeviation()
	if !equals(first, second, tolerance) {
		t.Errorf("precomputed standard deviation and new one differs: sample=%v, first sd=%f, second sd=%f",
			f, first, second)
	}
}

func TestStandardError(t *testing.T) {
	for i, f := range [...]struct {
		in  []float64
		out float64
	}{
		{in: []float64{1.0, 1.0}, out: 0.0},
		{in: []float64{1.0, 2.0}, out: 0.5},
		{in: []float64{1.0, 2, 3, 4, 5, 6}, out: 0.763},
		{in: []float64{-2.0, -1, 0, 1, 2, 3}, out: 0.763},
	} {
		s, err := New(f.in)
		if err != nil {
			t.Fatalf("%d) in=%v, New returned error: %v", i, f.in, err)
		}
		got := s.StandardError()
		if !equals(got, f.out, tolerance) {
			t.Errorf("%d) in=%v, out=%f, got=%f",
				i, f.in, f.out, got)
		}
	}
}

func TestStandardErrorAlreadyComputed(t *testing.T) {
	f := []float64{1.0, 1}
	s, err := New(f)
	if err != nil {
		t.Fatalf("in=%v, New returned error: %v", f, err)
	}
	first := s.StandardError()
	second := s.StandardError()
	if !equals(first, second, tolerance) {
		t.Errorf("precomputed standard error and new one differs: sample=%v, first sd=%f, second sd=%f",
			f, first, second)
	}
}

func TestSum(t *testing.T) {
	for i, f := range [...]struct {
		input    []float64
		expected float64
	}{
		{input: []float64{}, expected: 0.0},
		{input: []float64{0.0}, expected: 0.0},
		{input: []float64{0.0, 0.0}, expected: 0.0},
		{input: []float64{0.0, 0.0, 0.0}, expected: 0.0},
		{input: []float64{1.0, -1.0, 0.0}, expected: 0.0},
		{input: []float64{1.0, 2.0, 3.0, 4.0}, expected: 10.0},
	} {
		output := sum(f.input)
		if !equals(output, f.expected, tolerance) {
			t.Errorf("%d) input=%v, expected=%f, output=%f",
				i, f.input, f.expected, output)
		}
	}
}

// TODO: Add benchmark for sum() before adding a concurrent version
<commit_msg>Adds tests for big sums and benchmark<commit_after>package sample

import (
	"math"
	"reflect"
	"testing"
)

const tolerance = 1e-3

func equals(a, b, tolerance float64) bool {
	if math.Abs(a-b) < tolerance {
		return true
	}
	return false
}

func TestNewErrors(t *testing.T) {
	for i, f := range [...][]float64{
		{},
		{1.0},
	} {
		s, err := New(f)
		if s != nil {
			t.Fatalf("%d) in=%v, should have returned nil, but got: %v", i, f, s)
		}
		if err != ErrBesselNeedsTwo {
			t.Fatalf("%d) in=%v, should have returned ErrBesselNeedsTwo", i, f)
		}
	}
}

func TestNew(t *testing.T) {
	for i, f := range [...][]float64{
		{1.0, 1},
		{1.0, 2, -3.1415952},
		{1.0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
	} {
		s, err := New(f)
		if err != nil {
			t.Fatalf("%d) in=%v, returned error: %v", i, f, err)
		}
		if !reflect.DeepEqual(f, s.data) {
			t.Errorf("%d) in=%v, expected=%[2]v, got=%v", i, f, s.data)
		}
	}
}

func TestMean(t *testing.T) {
	for i, f := range [...]struct {
		in  []float64
		out float64
	}{
		{in: []float64{-1.0, -1.0}, out: -1.0},
		{in: []float64{1, 2, 3, 4, 5, 6}, out: 3.5},
		{in: []float64{0, 1, -1, 2, -2}, out: 0.0},
		{in: []float64{3.005, 3.005, 3.005, 3.005, 3.005, 3.005002, 3.004998}, out: 3.005},
	} {
		s, err := New(f.in)
		if err != nil {
			t.Fatalf("%d) in=%v, New returned error: %v", i, f.in, err)
		}
		got := s.Mean()
		if !equals(got, f.out, tolerance) {
			t.Errorf("%d) in=%v, out=%f, got=%f",
				i, f.in, f.out, got)
		}
	}
}

func TestMeanAlreadyComputed(t *testing.T) {
	f := []float64{1.0, 1}
	s, err := New(f)
	if err != nil {
		t.Fatalf("in=%v, New returned error: %v", f, err)
	}
	first := s.Mean()
	second := s.Mean()
	if !equals(first, second, tolerance) {
		t.Errorf("precomputed mean and new mean differs: sample=%v, first mean=%f, second mean=%f",
			f, first, second)
	}
}

func TestStandardDeviation(t *testing.T) {
	for i, f := range [...]struct {
		in  []float64
		out float64
	}{
		{in: []float64{1.0, 1.0}, out: 0.0},
		{in: []float64{1.0, 2.0}, out: 0.707},
		{in: []float64{1.0, 2, 3, 4, 5, 6}, out: 1.870},
		{in: []float64{-2.0, -1, 0, 1, 2, 3}, out: 1.870},
	} {
		s, err := New(f.in)
		if err != nil {
			t.Fatalf("%d) in=%v, New returned error: %v", i, f.in, err)
		}
		got := s.StandardDeviation()
		if !equals(got, f.out, tolerance) {
			t.Errorf("%d) in=%v, out=%f, got=%f",
				i, f.in, f.out, got)
		}
	}
}

func TestStandardDeviationAlreadyComputed(t *testing.T) {
	f := []float64{1.0, 1}
	s, err := New(f)
	if err != nil {
		t.Fatalf("in=%v, New returned error: %v", f, err)
	}
	first := s.StandardDeviation()
	second := s.StandardDeviation()
	if !equals(first, second, tolerance) {
		t.Errorf("precomputed standard deviation and new one differs: sample=%v, first sd=%f, second sd=%f",
			f, first, second)
	}
}

func TestStandardError(t *testing.T) {
	for i, f := range [...]struct {
		in  []float64
		out float64
	}{
		{in: []float64{1.0, 1.0}, out: 0.0},
		{in: []float64{1.0, 2.0}, out: 0.5},
		{in: []float64{1.0, 2, 3, 4, 5, 6}, out: 0.763},
		{in: []float64{-2.0, -1, 0, 1, 2, 3}, out: 0.763},
	} {
		s, err := New(f.in)
		if err != nil {
			t.Fatalf("%d) in=%v, New returned error: %v", i, f.in, err)
		}
		got := s.StandardError()
		if !equals(got, f.out, tolerance) {
			t.Errorf("%d) in=%v, out=%f, got=%f",
				i, f.in, f.out, got)
		}
	}
}

func TestStandardErrorAlreadyComputed(t *testing.T) {
	f := []float64{1.0, 1}
	s, err := New(f)
	if err != nil {
		t.Fatalf("in=%v, New returned error: %v", f, err)
	}
	first := s.StandardError()
	second := s.StandardError()
	if !equals(first, second, tolerance) {
		t.Errorf("precomputed standard error and new one differs: sample=%v, first sd=%f, second sd=%f",
			f, first, second)
	}
}

func TestSumSamll(t *testing.T) {
	for i, f := range [...]struct {
		input    []float64
		expected float64
	}{
		{input: []float64{}, expected: 0.0},
		{input: []float64{0.0}, expected: 0.0},
		{input: []float64{0.0, 0.0}, expected: 0.0},
		{input: []float64{0.0, 0.0, 0.0}, expected: 0.0},
		{input: []float64{1.0, -1.0, 0.0}, expected: 0.0},
		{input: []float64{1.0, 2.0, 3.0, 4.0}, expected: 10.0},
	} {
		output := sum(f.input)
		if !equals(output, f.expected, tolerance) {
			t.Errorf("%d) input=%v, expected=%f, output=%f",
				i, f.input, f.expected, output)
		}
	}
}

func oneToN(n int) []float64 {
	s := make([]float64, n)
	for i := 0; i < n; i++ {
		s[i] = float64(i + 1)
	}
	return s
}

// this will tests the sum of big slices, using simple finite arithmetic
// progressions as the input data.
func TestSumBig(t *testing.T) {
	for i, n := range [...]int{
		10,
		100,
		1000,
		10000,
		100000,
	} {
		expected := float64(n*(1+n)) / 2
		input := oneToN(n)
		output := sum(input)
		if !equals(output, expected, tolerance) {
			t.Errorf("%d) n=%d, expected=%f, output=%f",
				i, n, expected, output)
		}
	}
}

var benchmarkResult float64 // avoid compiler optimization to elimitate tests

func benchmarkSum(n int, b *testing.B) {
	b.StopTimer()
	var r float64
	input := oneToN(n)
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		r = sum(input)
	}
	benchmarkResult = r
}

func BenchmarkSum2(b *testing.B) { benchmarkSum(10, b) }
func BenchmarkSum3(b *testing.B) { benchmarkSum(100, b) }
func BenchmarkSum4(b *testing.B) { benchmarkSum(1000, b) }
func BenchmarkSum5(b *testing.B) { benchmarkSum(10000, b) }
func BenchmarkSum6(b *testing.B) { benchmarkSum(100000, b) }

// TODO: Add benchmark for sum() before adding a concurrent version
<|endoftext|>