<commit_before>package aws

import (
	"errors"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/awslabs/aws-sdk-go/aws/credentials/ec2rolecreds"
	"github.com/bobtfish/AWSnycast/healthcheck"
	"log"
	"net"
	"net/http"
	"strings"
	"time"
)

type MyEC2Conn interface {
	CreateRoute(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error)
	ReplaceRoute(*ec2.ReplaceRouteInput) (*ec2.ReplaceRouteOutput, error)
	DescribeRouteTables(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error)
	DeleteRoute(*ec2.DeleteRouteInput) (*ec2.DeleteRouteOutput, error)
}

type MetadataFetcher interface {
	Available() bool
	GetMetadata(string) (string, error)
}

func NewMetadataFetcher(debug bool) MetadataFetcher {
	c := ec2metadata.Config{}
	if debug {
		c.LogLevel = aws.LogLevel(aws.LogDebug)
	}
	return ec2metadata.New(&c)
}

type ManageRoutesSpec struct {
	Cidr            string `yaml:"cidr"`
	Instance        string `yaml:"instance"`
	HealthcheckName string `yaml:"healthcheck"`
	healthcheck     *healthcheck.Healthcheck
	IfUnhealthy     bool `yaml:"if_unhealthy"`
}

func (r *ManageRoutesSpec) Default(instance string) {
	if !strings.Contains(r.Cidr, "/") {
		r.Cidr = fmt.Sprintf("%s/32", r.Cidr)
	}
	if r.Instance == "" {
		r.Instance = "SELF"
	}
	if r.Instance == "SELF" {
		r.Instance = instance
	}
}
func (r *ManageRoutesSpec) Validate(name string, healthchecks map[string]*healthcheck.Healthcheck) error {
	if r.Cidr == "" {
		return errors.New(fmt.Sprintf("cidr is not defined in %s", name))
	}
	if _, _, err := net.ParseCIDR(r.Cidr); err != nil {
		return errors.New(fmt.Sprintf("Could not parse %s in %s", err.Error(), name))
	}
	if r.HealthcheckName != "" {
		hc, ok := healthchecks[r.HealthcheckName]
		if !ok {
			return errors.New(fmt.Sprintf("Route table %s, upsert %s cannot find healthcheck '%s'", name, r.Cidr, r.HealthcheckName))
		}
		r.healthcheck = hc
	}
	return nil
}

type RouteTableFetcher interface {
	GetRouteTables() ([]*ec2.RouteTable, error)
	ManageInstanceRoute(ec2.RouteTable, ManageRoutesSpec, bool) error
}

type RouteTableFetcherEC2 struct {
	Region string
	conn   MyEC2Conn
}

func getCreateRouteInput(rtb ec2.RouteTable, cidr string, instance string) ec2.CreateRouteInput {
	return ec2.CreateRouteInput{
		RouteTableId:         rtb.RouteTableId,
		DestinationCidrBlock: aws.String(cidr),
		InstanceId:           aws.String(instance),
	}
}

func (r RouteTableFetcherEC2) ManageInstanceRoute(rtb ec2.RouteTable, rs ManageRoutesSpec, noop bool) error {
	if err := r.ReplaceInstanceRoute(rtb, rs.Cidr, rs.Instance, rs.IfUnhealthy, noop); err != nil {
		if err.Error() != "Never found CIDR in route table to replace" {
			return err
		}
	} else {
		return nil
	}
	opts := getCreateRouteInput(rtb, rs.Cidr, rs.Instance)

	log.Printf("[INFO] Creating route for %s: %#v", *rtb.RouteTableId, opts)
	if !noop {
		if _, err := r.conn.CreateRoute(&opts); err != nil {
			return err
		}
	}
	return nil
}

func (r RouteTableFetcherEC2) ReplaceInstanceRoute(rtb ec2.RouteTable, cidr string, instance string, ifUnhealthy bool, noop bool) error {
	for _, route := range rtb.Routes {
		if *(route.DestinationCidrBlock) == cidr {
			if route.InstanceId != nil && *(route.InstanceId) == instance {
				log.Printf("Skipping doing anything, %s is already routed via %s", cidr, instance)
				return nil
			}
			params := &ec2.ReplaceRouteInput{
				DestinationCidrBlock: aws.String(cidr),
				RouteTableId:         rtb.RouteTableId,
				InstanceId:           aws.String(instance),
			}
			if ifUnhealthy && *(route.State) == "active" {
				log.Printf("Not replacing route, as current route is active/healthy")
				return nil
			}
			if !noop {
				resp, err := r.conn.ReplaceRoute(params)
				if err != nil {
					// Print the error, cast err to awserr.Error to get the Code and
					// Message from an error.
					fmt.Println(err.Error())
					return err
				}
				fmt.Println(resp)
			}
			return nil
		}
	}
	return errors.New("Never found CIDR in route table to replace")
}

func (r RouteTableFetcherEC2) GetRouteTables() ([]*ec2.RouteTable, error) {
	resp, err := r.conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{})
	if err != nil {
		log.Printf("Error on DescribeRouteTables: %s", err)
		return []*ec2.RouteTable{}, err
	}
	return resp.RouteTables, nil
}

func NewRouteTableFetcher(region string, debug bool) (RouteTableFetcher, error) {
	r := RouteTableFetcherEC2{}
	providers := []credentials.Provider{
		&credentials.EnvProvider{},
		&ec2rolecreds.EC2RoleProvider{
			Client: ec2metadata.New(&ec2metadata.Config{
				HTTPClient: &http.Client{
					Timeout: 2 * time.Second,
				},
			}),
		},
	}
	cred := credentials.NewChainCredentials(providers)
	_, credErr := cred.Get()
	if credErr != nil {
		return r, credErr
	}
	awsConfig := &aws.Config{
		Credentials: cred,
		Region:      aws.String(region),
		MaxRetries:  aws.Int(3),
	}
	iamconn := iam.New(awsConfig)
	_, err := iamconn.GetUser(nil)
	if awsErr, ok := err.(awserr.Error); ok {
		if awsErr.Code() == "SignatureDoesNotMatch" {
			return r, fmt.Errorf("Failed authenticating with AWS: please verify credentials")
		}
	}
	r.conn = ec2.New(awsConfig)
	return r, nil
}

type RouteTableFilter interface {
	Keep(*ec2.RouteTable) bool
}

type RouteTableFilterAlways struct{}

func (fs RouteTableFilterAlways) Keep(rt *ec2.RouteTable) bool {
	return false
}

type RouteTableFilterNever struct{}

func (fs RouteTableFilterNever) Keep(rt *ec2.RouteTable) bool {
	return true
}

type RouteTableFilterAnd struct {
	RouteTableFilters []RouteTableFilter
}

func (fs RouteTableFilterAnd) Keep(rt *ec2.RouteTable) bool {
	for _, f := range fs.RouteTableFilters {
		if !f.Keep(rt) {
			return false
		}
	}
	return true
}

type RouteTableFilterOr struct {
	RouteTableFilters []RouteTableFilter
}

func (fs RouteTableFilterOr) Keep(rt *ec2.RouteTable) bool {
	for _, f := range fs.RouteTableFilters {
		if f.Keep(rt) {
			return true
		}
	}
	return false
}

type RouteTableFilterMain struct{}

func (fs RouteTableFilterMain) Keep(rt *ec2.RouteTable) bool {
	for _, a := range rt.Associations {
		if *(a.Main) {
			return true
		}
	}
	return false
}

func FilterRouteTables(f RouteTableFilter, tables []*ec2.RouteTable) []*ec2.RouteTable {
	out := make([]*ec2.RouteTable, 0, len(tables))
	for _, rtb := range tables {
		if f.Keep(rtb) {
			out = append(out, rtb)
		}
	}
	return out
}

func RouteTableForSubnet(subnet string, tables []*ec2.RouteTable) *ec2.RouteTable {
	subnet_rtb := FilterRouteTables(RouteTableFilterSubnet{SubnetId: subnet}, tables)
	if len(subnet_rtb) == 0 {
		main_rtbs := FilterRouteTables(RouteTableFilterMain{}, tables)
		if len(main_rtbs) == 0 {
			return nil
		}
		return main_rtbs[0]
	}
	return subnet_rtb[0]
}

type RouteTableFilterSubnet struct {
	SubnetId string
}

func (fs RouteTableFilterSubnet) Keep(rt *ec2.RouteTable) bool {
	for _, a := range rt.Associations {
		if a.SubnetId != nil && *(a.SubnetId) == fs.SubnetId {
			return true
		}
	}
	return false
}

type RouteTableFilterDestinationCidrBlock struct {
	DestinationCidrBlock string
	ViaIGW               bool
	ViaInstance          bool
	InstanceNotActive    bool
}

func (fs RouteTableFilterDestinationCidrBlock) Keep(rt *ec2.RouteTable) bool {
	for _, r := range rt.Routes {
		if r.DestinationCidrBlock != nil && *(r.DestinationCidrBlock) == fs.DestinationCidrBlock {
			if fs.ViaIGW {
				if r.GatewayId != nil && strings.HasPrefix(*(r.GatewayId), "igw-") {
					return true
				}
			} else {
				if fs.ViaInstance {
					if r.InstanceId != nil {
						if fs.InstanceNotActive {
							if *(r.State) != "active" {
								return true
							}
						} else {
							return true
						}
					}
				} else {
					return true
				}
			}
		}
	}
	return false
}

type RouteTableFilterTagMatch struct {
	Key   string
	Value string
}

func (fs RouteTableFilterTagMatch) Keep(rt *ec2.RouteTable) bool {
	for _, t := range rt.Tags {
		if *(t.Key) == fs.Key && *(t.Value) == fs.Value {
			return true
		}
	}
	return false
}
<commit_msg>Refactoring<commit_after>package aws

import (
	"errors"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/awslabs/aws-sdk-go/aws/credentials/ec2rolecreds"
	"github.com/bobtfish/AWSnycast/healthcheck"
	"log"
	"net"
	"net/http"
	"strings"
	"time"
)

type MyEC2Conn interface {
	CreateRoute(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error)
	ReplaceRoute(*ec2.ReplaceRouteInput) (*ec2.ReplaceRouteOutput, error)
	DescribeRouteTables(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error)
	DeleteRoute(*ec2.DeleteRouteInput) (*ec2.DeleteRouteOutput, error)
}

type MetadataFetcher interface {
	Available() bool
	GetMetadata(string) (string, error)
}

func NewMetadataFetcher(debug bool) MetadataFetcher {
	c := ec2metadata.Config{}
	if debug {
		c.LogLevel = aws.LogLevel(aws.LogDebug)
	}
	return ec2metadata.New(&c)
}

type ManageRoutesSpec struct {
	Cidr            string `yaml:"cidr"`
	Instance        string `yaml:"instance"`
	InstanceIsSelf  bool   `yaml:"-"`
	HealthcheckName string `yaml:"healthcheck"`
	healthcheck     *healthcheck.Healthcheck
	IfUnhealthy     bool `yaml:"if_unhealthy"`
}

func (r *ManageRoutesSpec) Default(instance string) {
	if !strings.Contains(r.Cidr, "/") {
		r.Cidr = fmt.Sprintf("%s/32", r.Cidr)
	}
	if r.Instance == "" {
		r.Instance = "SELF"
	}
	if r.Instance == "SELF" {
		r.InstanceIsSelf = true
		r.Instance = instance
	}
}

func (r *ManageRoutesSpec) Validate(name string, healthchecks map[string]*healthcheck.Healthcheck) error {
	if r.Cidr == "" {
		return errors.New(fmt.Sprintf("cidr is not defined in %s", name))
	}
	if _, _, err := net.ParseCIDR(r.Cidr); err != nil {
		return errors.New(fmt.Sprintf("Could not parse %s in %s", err.Error(), name))
	}
	/*if r.HealthcheckName != "" {
				hc, ok := healthchecks[r.HealthcheckName]
				if !ok {
					return errors.New(fmt.Sprintf("Route table %s, upsert %s cannot find healthcheck '%s'", name, r.Cidr, r.HealthcheckName))
				}
				r.healthcheck = hc
	}*/
	return nil
}

type RouteTableFetcher interface {
	GetRouteTables() ([]*ec2.RouteTable, error)
	ManageInstanceRoute(ec2.RouteTable, ManageRoutesSpec, bool) error
}

type RouteTableFetcherEC2 struct {
	Region string
	conn   MyEC2Conn
}

func getCreateRouteInput(rtb ec2.RouteTable, cidr string, instance string) ec2.CreateRouteInput {
	return ec2.CreateRouteInput{
		RouteTableId:         rtb.RouteTableId,
		DestinationCidrBlock: aws.String(cidr),
		InstanceId:           aws.String(instance),
	}
}

func (r RouteTableFetcherEC2) ManageInstanceRoute(rtb ec2.RouteTable, rs ManageRoutesSpec, noop bool) error {
	/*if rs.HealthcheckName != "" {
		if rs.InstanceIsSelf {
		}
	}*/
	route := findRouteFromRouteTable(rtb, rs.Cidr)
	if route != nil {
		if err := r.ReplaceInstanceRoute(rtb, rs.Cidr, rs.Instance, rs.IfUnhealthy, noop); err != nil {
			return err
		}
		return nil
	}
	opts := getCreateRouteInput(rtb, rs.Cidr, rs.Instance)

	log.Printf("[INFO] Creating route for %s: %#v", *rtb.RouteTableId, opts)
	if !noop {
		if _, err := r.conn.CreateRoute(&opts); err != nil {
			return err
		}
	}
	return nil
}

func findRouteFromRouteTable(rtb ec2.RouteTable, cidr string) *ec2.Route {
	for _, route := range rtb.Routes {
		if *(route.DestinationCidrBlock) == cidr {
			return route
		}
	}
	return nil
}

func (r RouteTableFetcherEC2) ReplaceInstanceRoute(rtb ec2.RouteTable, cidr string, instance string, ifUnhealthy bool, noop bool) error {
	route := findRouteFromRouteTable(rtb, cidr)
	if route == nil {
		return errors.New("Never found CIDR in route table to replace")
	}
	return r.ReplaceInstanceRouteReal(rtb.RouteTableId, route, cidr, instance, ifUnhealthy, noop)
}
func (r RouteTableFetcherEC2) ReplaceInstanceRouteReal(routeTableId *string, route *ec2.Route, cidr string, instance string, ifUnhealthy bool, noop bool) error {
	if route.InstanceId != nil && *(route.InstanceId) == instance {
		log.Printf("Skipping doing anything, %s is already routed via %s", cidr, instance)
		return nil
	}
	params := &ec2.ReplaceRouteInput{
		DestinationCidrBlock: aws.String(cidr),
		RouteTableId:         routeTableId,
		InstanceId:           aws.String(instance),
	}
	if ifUnhealthy && *(route.State) == "active" {
		log.Printf("Not replacing route, as current route is active/healthy")
		return nil
	}
	if !noop {
		resp, err := r.conn.ReplaceRoute(params)
		if err != nil {
			// Print the error, cast err to awserr.Error to get the Code and
			// Message from an error.
			fmt.Println(err.Error())
			return err
		}
		fmt.Println(resp)
	}
	return nil
}

func (r RouteTableFetcherEC2) GetRouteTables() ([]*ec2.RouteTable, error) {
	resp, err := r.conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{})
	if err != nil {
		log.Printf("Error on DescribeRouteTables: %s", err)
		return []*ec2.RouteTable{}, err
	}
	return resp.RouteTables, nil
}

func NewRouteTableFetcher(region string, debug bool) (RouteTableFetcher, error) {
	r := RouteTableFetcherEC2{}
	providers := []credentials.Provider{
		&credentials.EnvProvider{},
		&ec2rolecreds.EC2RoleProvider{
			Client: ec2metadata.New(&ec2metadata.Config{
				HTTPClient: &http.Client{
					Timeout: 2 * time.Second,
				},
			}),
		},
	}
	cred := credentials.NewChainCredentials(providers)
	_, credErr := cred.Get()
	if credErr != nil {
		return r, credErr
	}
	awsConfig := &aws.Config{
		Credentials: cred,
		Region:      aws.String(region),
		MaxRetries:  aws.Int(3),
	}
	iamconn := iam.New(awsConfig)
	_, err := iamconn.GetUser(nil)
	if awsErr, ok := err.(awserr.Error); ok {
		if awsErr.Code() == "SignatureDoesNotMatch" {
			return r, fmt.Errorf("Failed authenticating with AWS: please verify credentials")
		}
	}
	r.conn = ec2.New(awsConfig)
	return r, nil
}

type RouteTableFilter interface {
	Keep(*ec2.RouteTable) bool
}

type RouteTableFilterAlways struct{}

func (fs RouteTableFilterAlways) Keep(rt *ec2.RouteTable) bool {
	return false
}

type RouteTableFilterNever struct{}

func (fs RouteTableFilterNever) Keep(rt *ec2.RouteTable) bool {
	return true
}

type RouteTableFilterAnd struct {
	RouteTableFilters []RouteTableFilter
}

func (fs RouteTableFilterAnd) Keep(rt *ec2.RouteTable) bool {
	for _, f := range fs.RouteTableFilters {
		if !f.Keep(rt) {
			return false
		}
	}
	return true
}

type RouteTableFilterOr struct {
	RouteTableFilters []RouteTableFilter
}

func (fs RouteTableFilterOr) Keep(rt *ec2.RouteTable) bool {
	for _, f := range fs.RouteTableFilters {
		if f.Keep(rt) {
			return true
		}
	}
	return false
}

type RouteTableFilterMain struct{}

func (fs RouteTableFilterMain) Keep(rt *ec2.RouteTable) bool {
	for _, a := range rt.Associations {
		if *(a.Main) {
			return true
		}
	}
	return false
}

func FilterRouteTables(f RouteTableFilter, tables []*ec2.RouteTable) []*ec2.RouteTable {
	out := make([]*ec2.RouteTable, 0, len(tables))
	for _, rtb := range tables {
		if f.Keep(rtb) {
			out = append(out, rtb)
		}
	}
	return out
}

func RouteTableForSubnet(subnet string, tables []*ec2.RouteTable) *ec2.RouteTable {
	subnet_rtb := FilterRouteTables(RouteTableFilterSubnet{SubnetId: subnet}, tables)
	if len(subnet_rtb) == 0 {
		main_rtbs := FilterRouteTables(RouteTableFilterMain{}, tables)
		if len(main_rtbs) == 0 {
			return nil
		}
		return main_rtbs[0]
	}
	return subnet_rtb[0]
}

type RouteTableFilterSubnet struct {
	SubnetId string
}

func (fs RouteTableFilterSubnet) Keep(rt *ec2.RouteTable) bool {
	for _, a := range rt.Associations {
		if a.SubnetId != nil && *(a.SubnetId) == fs.SubnetId {
			return true
		}
	}
	return false
}

type RouteTableFilterDestinationCidrBlock struct {
	DestinationCidrBlock string
	ViaIGW               bool
	ViaInstance          bool
	InstanceNotActive    bool
}

func (fs RouteTableFilterDestinationCidrBlock) Keep(rt *ec2.RouteTable) bool {
	for _, r := range rt.Routes {
		if r.DestinationCidrBlock != nil && *(r.DestinationCidrBlock) == fs.DestinationCidrBlock {
			if fs.ViaIGW {
				if r.GatewayId != nil && strings.HasPrefix(*(r.GatewayId), "igw-") {
					return true
				}
			} else {
				if fs.ViaInstance {
					if r.InstanceId != nil {
						if fs.InstanceNotActive {
							if *(r.State) != "active" {
								return true
							}
						} else {
							return true
						}
					}
				} else {
					return true
				}
			}
		}
	}
	return false
}

type RouteTableFilterTagMatch struct {
	Key   string
	Value string
}

func (fs RouteTableFilterTagMatch) Keep(rt *ec2.RouteTable) bool {
	for _, t := range rt.Tags {
		if *(t.Key) == fs.Key && *(t.Value) == fs.Value {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Package snowflake provides a very simple Twitter snowflake generator and parser.
package snowflake

import (
	"encoding/base64"
	"errors"
	"strconv"
	"sync"
	"time"
)

const (
	nodeBits        = 10
	stepBits        = 12
	nodeMax         = -1 ^ (-1 << nodeBits)
	stepMask  int64 = -1 ^ (-1 << stepBits)
	timeShift uint8 = nodeBits + stepBits
	nodeShift uint8 = stepBits
)

// Epoch is set to the twitter snowflake epoch of 2006-03-21:20:50:14 GMT
// You may customize this to set a different epoch for your application.
var Epoch int64 = 1288834974657

// A Node struct holds the basic information needed for a snowflake generator
// node
type Node struct {
	sync.Mutex
	time int64
	node int64
	step int64
}

// An ID is a custom type used for a snowflake ID.  This is used so we can
// attach methods onto the ID.
type ID int64

// NewNode returns a new snowflake node that can be used to generate snowflake
// IDs
func NewNode(node int64) (*Node, error) {

	if node < 0 || node > nodeMax {
		return nil, errors.New("Node number must be between 0 and 1024")
	}

	return &Node{
		time: 0,
		node: node,
		step: 0,
	}, nil
}

// Generate creates and returns a unique snowflake ID
func (n *Node) Generate() ID {

	n.Lock()
	defer n.Unlock()

	now := time.Now().UnixNano() / 1000000

	if n.time == now {
		n.step = (n.step + 1) & stepMask

		if n.step == 0 {
			for now <= n.time {
				now = time.Now().UnixNano() / 1000000
			}
		}
	} else {
		n.step = 0
	}

	n.time = now

	return ID((now-Epoch)<<timeShift |
		(n.node << nodeShift) |
		(n.step),
	)
}

// Int64 returns an int64 of the snowflake ID
func (f ID) Int64() int64 {
	return int64(f)
}

// String returns a string of the snowflake ID
func (f ID) String() string {
	return strconv.FormatInt(int64(f), 10)
}

// Base2 returns a string base2 of the snowflake ID
func (f ID) Base2() string {
	return strconv.FormatInt(int64(f), 2)
}

// Base36 returns a base36 string of the snowflake ID
func (f ID) Base36() string {
	return strconv.FormatInt(int64(f), 36)
}

// Base64 returns a base64 string of the snowflake ID
func (f ID) Base64() string {
	return base64.StdEncoding.EncodeToString(f.Bytes())
}

// Bytes returns a byte array of the snowflake ID
func (f ID) Bytes() []byte {
	return []byte(f.String())
}

// Time returns an int64 unix timestamp of the snowflake ID time
func (f ID) Time() int64 {
	return (int64(f) >> 22) + Epoch
}

// Node returns an int64 of the snowflake ID node number
func (f ID) Node() int64 {
	return int64(f) & 0x00000000003FF000 >> 12
}

// Step returns an int64 of the snowflake step (or sequence) number
func (f ID) Step() int64 {
	return int64(f) & 0x0000000000000FFF
}

// MarshalJSON returns a json byte array string of the snowflake ID.
func (f ID) MarshalJSON() ([]byte, error) {
	buff := []byte("\"")
	buff = strconv.AppendInt(buff, int64(f), 10)
	buff = append(buff, '"')
	return buff, nil
}

// UnmarshalJSON converts a json byte array of a snowflake ID into an ID type.
func (f *ID) UnmarshalJSON(b []byte) error {
	i, err := strconv.ParseInt(string(b[1:len(b)-1]), 10, 64)
	if err != nil {
		return err
	}

	*f = ID(i)
	return nil
}
<commit_msg>Don't defer.<commit_after>// Package snowflake provides a very simple Twitter snowflake generator and parser.
package snowflake

import (
	"encoding/base64"
	"errors"
	"strconv"
	"sync"
	"time"
)

const (
	nodeBits        = 10
	stepBits        = 12
	nodeMax         = -1 ^ (-1 << nodeBits)
	stepMask  int64 = -1 ^ (-1 << stepBits)
	timeShift uint8 = nodeBits + stepBits
	nodeShift uint8 = stepBits
)

// Epoch is set to the twitter snowflake epoch of 2006-03-21:20:50:14 GMT
// You may customize this to set a different epoch for your application.
var Epoch int64 = 1288834974657

// A Node struct holds the basic information needed for a snowflake generator
// node
type Node struct {
	sync.Mutex
	time int64
	node int64
	step int64
}

// An ID is a custom type used for a snowflake ID.  This is used so we can
// attach methods onto the ID.
type ID int64

// NewNode returns a new snowflake node that can be used to generate snowflake
// IDs
func NewNode(node int64) (*Node, error) {

	if node < 0 || node > nodeMax {
		return nil, errors.New("Node number must be between 0 and 1024")
	}

	return &Node{
		time: 0,
		node: node,
		step: 0,
	}, nil
}

// Generate creates and returns a unique snowflake ID
func (n *Node) Generate() ID {

	n.Lock()

	now := time.Now().UnixNano() / 1000000

	if n.time == now {
		n.step = (n.step + 1) & stepMask

		if n.step == 0 {
			for now <= n.time {
				now = time.Now().UnixNano() / 1000000
			}
		}
	} else {
		n.step = 0
	}

	n.time = now

	r := ID((now-Epoch)<<timeShift |
		(n.node << nodeShift) |
		(n.step),
	)

	n.Unlock()
	return r
}

// Int64 returns an int64 of the snowflake ID
func (f ID) Int64() int64 {
	return int64(f)
}

// String returns a string of the snowflake ID
func (f ID) String() string {
	return strconv.FormatInt(int64(f), 10)
}

// Base2 returns a string base2 of the snowflake ID
func (f ID) Base2() string {
	return strconv.FormatInt(int64(f), 2)
}

// Base36 returns a base36 string of the snowflake ID
func (f ID) Base36() string {
	return strconv.FormatInt(int64(f), 36)
}

// Base64 returns a base64 string of the snowflake ID
func (f ID) Base64() string {
	return base64.StdEncoding.EncodeToString(f.Bytes())
}

// Bytes returns a byte array of the snowflake ID
func (f ID) Bytes() []byte {
	return []byte(f.String())
}

// Time returns an int64 unix timestamp of the snowflake ID time
func (f ID) Time() int64 {
	return (int64(f) >> 22) + Epoch
}

// Node returns an int64 of the snowflake ID node number
func (f ID) Node() int64 {
	return int64(f) & 0x00000000003FF000 >> 12
}

// Step returns an int64 of the snowflake step (or sequence) number
func (f ID) Step() int64 {
	return int64(f) & 0x0000000000000FFF
}

// MarshalJSON returns a json byte array string of the snowflake ID.
func (f ID) MarshalJSON() ([]byte, error) {
	buff := []byte("\"")
	buff = strconv.AppendInt(buff, int64(f), 10)
	buff = append(buff, '"')
	return buff, nil
}

// UnmarshalJSON converts a json byte array of a snowflake ID into an ID type.
func (f *ID) UnmarshalJSON(b []byte) error {
	i, err := strconv.ParseInt(string(b[1:len(b)-1]), 10, 64)
	if err != nil {
		return err
	}

	*f = ID(i)
	return nil
}
<|endoftext|>


<commit_before>package appenders

// TODO add tests

import (
	"github.com/ian-kent/go-log/layout"
	"github.com/ian-kent/go-log/levels"
	"github.com/t-k/fluent-logger-golang/fluent"
)

type fluentdAppender struct {
	Appender
	layout       layout.Layout
	fluent       *fluent.Fluent
	fluentConfig fluent.Config
}

func Fluentd(config fluent.Config) *fluentdAppender {
	a := &fluentdAppender{
		layout:       layout.Default(),
		fluentConfig: config,
	}
	a.Open()
	return a
}

func (a *fluentdAppender) Close() {
	a.fluent.Close()
	a.fluent = nil
}

func (a *fluentdAppender) Open() error {
	f, err := fluent.New(a.fluentConfig)
	if err != nil {
		return err
	}
	a.fluent = f
	return nil
}

func (a *fluentdAppender) Write(level levels.LogLevel, message string, args ...interface{}) {
	// FIXME
	// - use tag instead of "go-log"
	// - get layout to return the map
	var data = map[string]string{
		"message": a.Layout().Format(level, message, args...),
	}
	a.fluent.Post("go-log", data)
}

func (a *fluentdAppender) Layout() layout.Layout {
	return a.layout
}

func (a *fluentdAppender) SetLayout(layout layout.Layout) {
	a.layout = layout
}
<commit_msg>SafeFluentd allows users to get error status from fluent.Open<commit_after>package appenders

// TODO add tests

import (
	"github.com/ian-kent/go-log/layout"
	"github.com/ian-kent/go-log/levels"
	"github.com/t-k/fluent-logger-golang/fluent"
)

type fluentdAppender struct {
	Appender
	layout       layout.Layout
	fluent       *fluent.Fluent
	fluentConfig fluent.Config
}

func SafeFluentd(config fluent.Config) (*fluentdAppender, error) {
	a := &fluentdAppender{
		layout:       layout.Default(),
		fluentConfig: config,
	}
	if err := a.Open(); err != nil {
		return nil, err
	}
	return a, nil
}

func Fluentd(config fluent.Config) *fluentdAppender {
	a, _ := SafeFluentd(config)
	return a
}

func (a *fluentdAppender) Close() {
	a.fluent.Close()
	a.fluent = nil
}

func (a *fluentdAppender) Open() error {
	f, err := fluent.New(a.fluentConfig)
	if err != nil {
		return err
	}
	a.fluent = f
	return nil
}

func (a *fluentdAppender) Write(level levels.LogLevel, message string, args ...interface{}) {
	// FIXME
	// - use tag instead of "go-log"
	// - get layout to return the map
	var data = map[string]string{
		"message": a.Layout().Format(level, message, args...),
	}
	a.fluent.Post("go-log", data)
}

func (a *fluentdAppender) Layout() layout.Layout {
	return a.layout
}

func (a *fluentdAppender) SetLayout(layout layout.Layout) {
	a.layout = layout
}
<|endoftext|>


<commit_before>package applets

import (
	"encoding/binary"
	"fmt"
	"net"
	"syscall"
	"time"
)

type mode byte
type ntpTime uint64

const (
	reserved mode = 0 + iota
	symmetricActive
	symmetricPassive
	client
	server
	broadcast
	controlMessage
	reservedPrivate
)
const nanoPerSec = 1e9

var ntpEpoch = time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)

// Duration interprets the fixed-point ntpTime as a number of elapsed seconds
// and returns the corresponding time.Duration value.
func (t ntpTime) Duration() time.Duration {
	sec := (t >> 32) * nanoPerSec
	frac := (t & 0xffffffff) * nanoPerSec >> 32
	return time.Duration(sec + frac)
}

// Decode interprets the fixed-point ntpTime and returns a time.Time
func (t ntpTime) Decode() time.Time {
	return ntpEpoch.Add(t.Duration())
}

// Encode encodes a time.Time in a ntpTime format
func Encode(t time.Time) ntpTime {
	nsec := uint64(t.Sub(ntpEpoch))
	sec := nsec / nanoPerSec
	frac := (nsec - sec*nanoPerSec) << 32 / nanoPerSec
	return ntpTime(sec<<32 | frac)
}

// Sub subtracts two ntpTime values
func (t ntpTime) Sub(tt ntpTime) time.Duration {
	return t.Decode().Sub(tt.Decode())
}

type msg struct {
	LiVnMode       byte // Leap Indicator (2) + Version (3) + Mode (3)
	Stratum        byte
	Poll           byte
	Precision      byte
	RootDelay      uint32
	RootDispersion uint32
	ReferenceId    uint32
	ReferenceTime  ntpTime
	OriginateTime  ntpTime
	ReceiveTime    ntpTime
	TransmitTime   ntpTime
}

// SetVersion sets the NTP protocol version on the message.
func (m *msg) SetVersion(v byte) {
	m.LiVnMode = (m.LiVnMode & 0xc7) | v<<3
}

// SetMode sets the NTP protocol mode on the message.
func (m *msg) SetMode(md mode) {
	m.LiVnMode = (m.LiVnMode & 0xf8) | byte(md)
}

// durtoTV transforms a time.Duration in two 64 bit integers
// suitable for setting Timevalue values
func durtoTV(d time.Duration) (int64, int64) {
	sec := int64(d / nanoPerSec)
	micro := int64((int64(d) - sec*nanoPerSec) / 1000)

	return sec, micro
}

// GetTime returns the "receive time" from the remote NTP server
// specified as host.  NTP client mode is used.
func GetTime(host string) (msg, ntpTime, error) {
	raddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(host, "123"))
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	con, err := net.DialUDP("udp", nil, raddr)
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	defer con.Close()
	con.SetDeadline(time.Now().Add(5 * time.Second))

	m := new(msg)
	m.SetMode(client)
	m.SetVersion(4)
	m.TransmitTime = Encode(time.Now())

	err = binary.Write(con, binary.BigEndian, m)
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	err = binary.Read(con, binary.BigEndian, m)
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	dest := Encode(time.Now())
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	return *m, dest, nil
}

// GetParams returns two time.Durations the time offset and rtt time
func GetParams(m msg, dest ntpTime) (offset time.Duration, rtt time.Duration) {
	T1 := m.OriginateTime
	T2 := m.ReceiveTime
	T3 := m.TransmitTime
	T4 := dest
	offset = (T2.Sub(T1) + T3.Sub(T4)) / 2
	rtt = T4.Sub(T1) - T2.Sub(T3)
	return
}

func GNTPClockRun(args []string) int {
	var servIP net.IP
	var saveClock bool
	switch len(args) {
	case 1:
		servIP = net.ParseIP(args[0])
		if servIP == nil {
			return 111
		}
	case 2:
		servIP = net.ParseIP(args[0])
		if servIP == nil {
			return 111
		}
		saveClock = args[1] == "saveclock"
	}

	m, dst, err := GetTime(servIP.String())
	if err != nil {
		fmt.Println(err)
		return 111
	}

	offset, rtt := GetParams(m, dst)

	fmt.Println("System time", time.Now())
	fmt.Println("Offset ", offset, "RTT ", rtt)

	if saveClock {
		t := time.Now().Add(offset)
		tv := syscall.NsecToTimeval(t.UnixNano())
		err := syscall.Settimeofday(&tv)

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

	}
	return 0
}
<commit_msg>gtclock: fixed gntpclock to not print monotonic when Go is >=1.9<commit_after>package applets

import (
	"encoding/binary"
	"fmt"
	"net"
	"syscall"
	"time"
)

type mode byte
type ntpTime uint64

const (
	reserved mode = 0 + iota
	symmetricActive
	symmetricPassive
	client
	server
	broadcast
	controlMessage
	reservedPrivate
)
const nanoPerSec = 1e9

var ntpEpoch = time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)

// Duration interprets the fixed-point ntpTime as a number of elapsed seconds
// and returns the corresponding time.Duration value.
func (t ntpTime) Duration() time.Duration {
	sec := (t >> 32) * nanoPerSec
	frac := (t & 0xffffffff) * nanoPerSec >> 32
	return time.Duration(sec + frac)
}

// Decode interprets the fixed-point ntpTime and returns a time.Time
func (t ntpTime) Decode() time.Time {
	return ntpEpoch.Add(t.Duration())
}

// Encode encodes a time.Time in a ntpTime format
func Encode(t time.Time) ntpTime {
	nsec := uint64(t.Sub(ntpEpoch))
	sec := nsec / nanoPerSec
	frac := (nsec - sec*nanoPerSec) << 32 / nanoPerSec
	return ntpTime(sec<<32 | frac)
}

// Sub subtracts two ntpTime values
func (t ntpTime) Sub(tt ntpTime) time.Duration {
	return t.Decode().Sub(tt.Decode())
}

type msg struct {
	LiVnMode       byte // Leap Indicator (2) + Version (3) + Mode (3)
	Stratum        byte
	Poll           byte
	Precision      byte
	RootDelay      uint32
	RootDispersion uint32
	ReferenceId    uint32
	ReferenceTime  ntpTime
	OriginateTime  ntpTime
	ReceiveTime    ntpTime
	TransmitTime   ntpTime
}

// SetVersion sets the NTP protocol version on the message.
func (m *msg) SetVersion(v byte) {
	m.LiVnMode = (m.LiVnMode & 0xc7) | v<<3
}

// SetMode sets the NTP protocol mode on the message.
func (m *msg) SetMode(md mode) {
	m.LiVnMode = (m.LiVnMode & 0xf8) | byte(md)
}

// durtoTV transforms a time.Duration in two 64 bit integers
// suitable for setting Timevalue values
func durtoTV(d time.Duration) (int64, int64) {
	sec := int64(d / nanoPerSec)
	micro := int64((int64(d) - sec*nanoPerSec) / 1000)

	return sec, micro
}

// GetTime returns the "receive time" from the remote NTP server
// specified as host.  NTP client mode is used.
func GetTime(host string) (msg, ntpTime, error) {
	raddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(host, "123"))
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	con, err := net.DialUDP("udp", nil, raddr)
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	defer con.Close()
	con.SetDeadline(time.Now().Add(5 * time.Second))

	m := new(msg)
	m.SetMode(client)
	m.SetVersion(4)
	m.TransmitTime = Encode(time.Now())

	err = binary.Write(con, binary.BigEndian, m)
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	err = binary.Read(con, binary.BigEndian, m)
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	dest := Encode(time.Now())
	if err != nil {
		fmt.Println(err)
		return msg{}, 0, err
	}

	return *m, dest, nil
}

// GetParams returns two time.Durations the time offset and rtt time
func GetParams(m msg, dest ntpTime) (offset time.Duration, rtt time.Duration) {
	T1 := m.OriginateTime
	T2 := m.ReceiveTime
	T3 := m.TransmitTime
	T4 := dest
	offset = (T2.Sub(T1) + T3.Sub(T4)) / 2
	rtt = T4.Sub(T1) - T2.Sub(T3)
	return
}

func GNTPClockRun(args []string) int {
	var servIP net.IP
	var saveClock bool
	switch len(args) {
	case 1:
		servIP = net.ParseIP(args[0])
		if servIP == nil {
			return 111
		}
	case 2:
		servIP = net.ParseIP(args[0])
		if servIP == nil {
			return 111
		}
		saveClock = args[1] == "saveclock"
	}

	m, dst, err := GetTime(servIP.String())
	if err != nil {
		fmt.Println(err)
		return 111
	}

	offset, rtt := GetParams(m, dst)
	fmt.Println("System time", time.Now().AddDate(0, 0, 0)) // We need this in order to remove possible monotonic part
	fmt.Println("Offset ", offset, "RTT ", rtt)

	if saveClock {
		t := time.Now().Add(offset)
		tv := syscall.NsecToTimeval(t.UnixNano())
		err := syscall.Settimeofday(&tv)

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

	}
	return 0
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 com

import (
	"fmt"
	"log"
	"strconv"
	"strings"
)

func Int64(i interface{}) int64 {
	if v, y := i.(int64); y {
		return v
	}
	if v, y := i.(int32); y {
		return int64(v)
	}
	if v, y := i.(uint32); y {
		return int64(v)
	}
	if v, y := i.(int); y {
		return int64(v)
	}
	if v, y := i.(uint); y {
		return int64(v)
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseInt(v, 10, 64)
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseInt(in, 10, 64)
	if err != nil {
		log.Printf("string[%s] covert int64 fail. %s", in, err)
		return 0
	}
	return out
}

func Int(i interface{}) int {
	if v, y := i.(int); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.Atoi(v)
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.Atoi(in)
	if err != nil {
		log.Printf("string[%s] covert int fail. %s", in, err)
		return 0
	}
	return out
}

func Int32(i interface{}) int32 {
	if v, y := i.(int32); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseInt(v, 10, 32)
		return int32(v)
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseInt(in, 10, 32)
	if err != nil {
		log.Printf("string[%s] covert int32 fail. %s", in, err)
		return 0
	}
	return int32(out)
}

func Uint64(i interface{}) uint64 {
	if v, y := i.(uint64); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseUint(v, 10, 64)
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseUint(in, 10, 64)
	if err != nil {
		log.Printf("string[%s] covert uint64 fail. %s", in, err)
		return 0
	}
	return out
}

func Uint(i interface{}) uint {
	if v, y := i.(uint); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseUint(v, 10, 32)
		return uint(v)
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseUint(in, 10, 32)
	if err != nil {
		log.Printf("string[%s] covert uint fail. %s", in, err)
		return 0
	}
	return uint(out)
}

func Uint32(i interface{}) uint32 {
	if v, y := i.(uint32); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseUint(v, 10, 32)
		return uint32(v)
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseUint(in, 10, 32)
	if err != nil {
		log.Printf("string[%s] covert uint32 fail. %s", in, err)
		return 0
	}
	return uint32(out)
}

func Float32(i interface{}) float32 {
	if v, y := i.(float32); y {
		return v
	}
	if v, y := i.(int32); y {
		return float32(v)
	}
	if v, y := i.(uint32); y {
		return float32(v)
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseFloat(v, 32)
		return float32(v)
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseFloat(in, 32)
	if err != nil {
		log.Printf("string[%s] covert float32 fail. %s", in, err)
		return 0
	}
	return float32(out)
}

func Float64(i interface{}) float64 {
	if v, y := i.(float64); y {
		return v
	}
	if v, y := i.(int64); y {
		return float64(v)
	}
	if v, y := i.(uint64); y {
		return float64(v)
	}
	if v, y := i.(float32); y {
		return float64(v)
	}
	if v, y := i.(int32); y {
		return float64(v)
	}
	if v, y := i.(uint32); y {
		return float64(v)
	}
	if v, y := i.(int); y {
		return float64(v)
	}
	if v, y := i.(uint); y {
		return float64(v)
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseFloat(v, 64)
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseFloat(in, 64)
	if err != nil {
		log.Printf("string[%s] covert float64 fail. %s", in, err)
		return 0
	}
	return out
}

func Bool(i interface{}) bool {
	if v, y := i.(bool); y {
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return false
	}
	out, err := strconv.ParseBool(in)
	if err != nil {
		log.Printf("string[%s] covert bool fail. %s", in, err)
		return false
	}
	return out
}

func Str(v interface{}) string {
	if v, y := v.(string); y {
		return v
	}
	return fmt.Sprintf("%v", v)
}

func String(v interface{}) string {
	return Str(v)
}

// SeekRangeNumbers 遍历范围数值，支持设置步进值。格式例如：1-2,2-3:2
func SeekRangeNumbers(expr string, fn func(int) bool) {
	expa := strings.SplitN(expr, ":", 2)
	step := 1
	switch len(expa) {
	case 2:
		if i, _ := strconv.Atoi(strings.TrimSpace(expa[1])); i > 0 {
			step = i
		}
		fallthrough
	case 1:
		for _, exp := range strings.Split(strings.TrimSpace(expa[0]), `,`) {
			exp = strings.TrimSpace(exp)
			if len(exp) == 0 {
				continue
			}
			expb := strings.SplitN(exp, `-`, 2)
			var minN, maxN int
			switch len(expb) {
			case 2:
				maxN, _ = strconv.Atoi(strings.TrimSpace(expb[1]))
				fallthrough
			case 1:
				minN, _ = strconv.Atoi(strings.TrimSpace(expb[0]))
			}
			if maxN == 0 {
				if !fn(minN) {
					return
				}
				continue
			}
			for ; minN <= maxN; minN += step {
				if !fn(minN) {
					return
				}
			}
		}
	}
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 com

import (
	"fmt"
	"log"
	"strconv"
	"strings"
)

func Int64(i interface{}) int64 {
	if v, y := i.(int64); y {
		return v
	}
	if v, y := i.(int32); y {
		return int64(v)
	}
	if v, y := i.(uint32); y {
		return int64(v)
	}
	if v, y := i.(int); y {
		return int64(v)
	}
	if v, y := i.(uint); y {
		return int64(v)
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseInt(v, 10, 64)
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseInt(in, 10, 64)
	if err != nil {
		log.Printf("string[%s] covert int64 fail. %s", in, err)
		return 0
	}
	return out
}

func Int(i interface{}) int {
	if v, y := i.(int); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.Atoi(v)
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.Atoi(in)
	if err != nil {
		log.Printf("string[%s] covert int fail. %s", in, err)
		return 0
	}
	return out
}

func Int32(i interface{}) int32 {
	if v, y := i.(int32); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseInt(v, 10, 32)
		return int32(v)
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseInt(in, 10, 32)
	if err != nil {
		log.Printf("string[%s] covert int32 fail. %s", in, err)
		return 0
	}
	return int32(out)
}

func Uint64(i interface{}) uint64 {
	if v, y := i.(uint64); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseUint(v, 10, 64)
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseUint(in, 10, 64)
	if err != nil {
		log.Printf("string[%s] covert uint64 fail. %s", in, err)
		return 0
	}
	return out
}

func Uint(i interface{}) uint {
	if v, y := i.(uint); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseUint(v, 10, 32)
		return uint(v)
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseUint(in, 10, 32)
	if err != nil {
		log.Printf("string[%s] covert uint fail. %s", in, err)
		return 0
	}
	return uint(out)
}

func Uint32(i interface{}) uint32 {
	if v, y := i.(uint32); y {
		return v
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseUint(v, 10, 32)
		return uint32(v)
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseUint(in, 10, 32)
	if err != nil {
		log.Printf("string[%s] covert uint32 fail. %s", in, err)
		return 0
	}
	return uint32(out)
}

func Float32(i interface{}) float32 {
	if v, y := i.(float32); y {
		return v
	}
	if v, y := i.(int32); y {
		return float32(v)
	}
	if v, y := i.(uint32); y {
		return float32(v)
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseFloat(v, 32)
		return float32(v)
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseFloat(in, 32)
	if err != nil {
		log.Printf("string[%s] covert float32 fail. %s", in, err)
		return 0
	}
	return float32(out)
}

func Float64(i interface{}) float64 {
	if v, y := i.(float64); y {
		return v
	}
	if v, y := i.(int64); y {
		return float64(v)
	}
	if v, y := i.(uint64); y {
		return float64(v)
	}
	if v, y := i.(float32); y {
		return float64(v)
	}
	if v, y := i.(int32); y {
		return float64(v)
	}
	if v, y := i.(uint32); y {
		return float64(v)
	}
	if v, y := i.(int); y {
		return float64(v)
	}
	if v, y := i.(uint); y {
		return float64(v)
	}
	if v, y := i.(string); y {
		v, _ := strconv.ParseFloat(v, 64)
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return 0
	}
	out, err := strconv.ParseFloat(in, 64)
	if err != nil {
		log.Printf("string[%s] covert float64 fail. %s", in, err)
		return 0
	}
	return out
}

func Bool(i interface{}) bool {
	if v, y := i.(bool); y {
		return v
	}
	in := Str(i)
	if len(in) == 0 {
		return false
	}
	out, err := strconv.ParseBool(in)
	if err != nil {
		log.Printf("string[%s] covert bool fail. %s", in, err)
		return false
	}
	return out
}

func Str(v interface{}) string {
	if v, y := v.(string); y {
		return v
	}
	return fmt.Sprintf("%v", v)
}

func String(v interface{}) string {
	return Str(v)
}

// SeekRangeNumbers 遍历范围数值，支持设置步进值。格式例如：1-2,2-3:2
func SeekRangeNumbers(expr string, fn func(int) bool) {
	expa := strings.SplitN(expr, ":", 2)
	step := 1
	switch len(expa) {
	case 2:
		if i, e := strconv.Atoi(strings.TrimSpace(expa[1])); e == nil {
			step = i
		}
		fallthrough
	case 1:
		for _, exp := range strings.Split(strings.TrimSpace(expa[0]), `,`) {
			exp = strings.TrimSpace(exp)
			if len(exp) == 0 {
				continue
			}
			expb := strings.SplitN(exp, `-`, 2)
			var minN, maxN int
			switch len(expb) {
			case 2:
				maxN, _ = strconv.Atoi(strings.TrimSpace(expb[1]))
				fallthrough
			case 1:
				minN, _ = strconv.Atoi(strings.TrimSpace(expb[0]))
			}
			if maxN == 0 {
				if !fn(minN) {
					return
				}
				continue
			}
			for ; minN <= maxN; minN += step {
				if !fn(minN) {
					return
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package stl

// This file contains generic 3D transformation stuff

import (
	"math"
)

// Calculates a 4x4 rotation matrix for a rotation of angle in radians
// around a rotation axis defined by a point on it (pos) and its direction (dir).
// The result is written into *rotationMatrix.
func RotationMatrix(pos Vec3, dir Vec3, angle float64, rotationMatrix *Mat4) {
	dirN := dir.unitVec()
	sinA := math.Sin(angle)
	sinAd0 := sinA * float64(dirN[0])
	sinAd1 := sinA * float64(dirN[1])
	sinAd2 := sinA * float64(dirN[2])
	cosA := math.Cos(angle)
	icosA := 1 - cosA
	icosAd0 := icosA * float64(dirN[0])
	icosAd00 := icosAd0 * float64(dirN[0])
	icosAd01 := icosAd0 * float64(dirN[1])
	icosAd02 := icosAd0 * float64(dirN[2])
	icosAd1 := icosA * float64(dirN[1])
	icosAd11 := icosAd1 * float64(dirN[1])
	icosAd12 := icosAd1 * float64(dirN[2])
	icosAd2 := icosA * float64(dirN[2])
	icosAd22 := icosAd2 * float64(dirN[2])

	mRotate := Mat4{
		Vec4{icosAd00 + cosA, icosAd01 - sinAd2, icosAd02 + sinAd1, 0},
		Vec4{icosAd01 + sinAd2, icosAd11 + cosA, icosAd12 - sinAd0, 0},
		Vec4{icosAd02 - sinAd1, icosAd12 + sinAd0, icosAd22 + cosA, 0},
		Vec4{0, 0, 0, 1},
	}

	mTranslateForward := Mat4{
		Vec4{1, 0, 0, float64(pos[0])},
		Vec4{0, 1, 0, float64(pos[1])},
		Vec4{0, 0, 1, float64(pos[2])},
		Vec4{0, 0, 0, 1},
	}

	mTranslateBackward := Mat4{
		Vec4{1, 0, 0, float64(-pos[0])},
		Vec4{0, 1, 0, float64(-pos[1])},
		Vec4{0, 0, 1, float64(-pos[2])},
		Vec4{0, 0, 0, 1},
	}

	var mTmp Mat4
	mRotate.MultMat4(&mTranslateForward, &mTmp)
	mTranslateBackward.MultMat4(&mTmp, rotationMatrix)
}
<commit_msg>Make RotationMatrix() more readable.<commit_after>package stl

// This file contains generic 3D transformation stuff

import (
	"math"
)

// Calculates a 4x4 rotation matrix for a rotation of angle in radians
// around a rotation axis defined by a point on it (pos) and its direction (dir).
// The result is written into *rotationMatrix.
func RotationMatrix(pos Vec3, dir Vec3, angle float64, rotationMatrix *Mat4) {
	dirN := dir.unitVec()

	s := math.Sin(angle)
	c := math.Cos(angle)

	u := float64(dirN[0])
	v := float64(dirN[1])
	w := float64(dirN[2])

	su := s * u
	sv := s * v
	sw := s * w

	ic := 1 - c

	ic_u := ic * u

	ic_uu := ic_u * u
	ic_uv := ic_u * v
	ic_uw := ic_u * w

	ic_v := ic * v

	ic_vv := ic_v * v
	ic_vw := ic_v * w

	ic_w := ic * w
	ic_ww := ic_w * w

	mRotate := Mat4{
		Vec4{ic_uu + c, ic_uv - sw, ic_uw + sv, 0},
		Vec4{ic_uv + sw, ic_vv + c, ic_vw - su, 0},
		Vec4{ic_uw - sv, ic_vw + su, ic_ww + c, 0},
		Vec4{0, 0, 0, 1},
	}

	mTranslateForward := Mat4{
		Vec4{1, 0, 0, float64(pos[0])},
		Vec4{0, 1, 0, float64(pos[1])},
		Vec4{0, 0, 1, float64(pos[2])},
		Vec4{0, 0, 0, 1},
	}

	mTranslateBackward := Mat4{
		Vec4{1, 0, 0, float64(-pos[0])},
		Vec4{0, 1, 0, float64(-pos[1])},
		Vec4{0, 0, 1, float64(-pos[2])},
		Vec4{0, 0, 0, 1},
	}

	var mTmp Mat4
	mRotate.MultMat4(&mTranslateForward, &mTmp)
	mTranslateBackward.MultMat4(&mTmp, rotationMatrix)
}
<|endoftext|>


<commit_before>package assetfs

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

var (
	defaultFileTimestamp = time.Now()
)

// FakeFile implements os.FileInfo interface for a given path and size
type FakeFile struct {
	// Path is the path of this file
	Path string
	// Dir marks of the path is a directory
	Dir bool
	// Len is the length of the fake file, zero if it is a directory
	Len int64
	// Timestamp is the ModTime of this file
	Timestamp time.Time
}

func (f *FakeFile) Name() string {
	_, name := filepath.Split(f.Path)
	return name
}

func (f *FakeFile) Mode() os.FileMode {
	mode := os.FileMode(0644)
	if f.Dir {
		return mode | os.ModeDir
	}
	return mode
}

func (f *FakeFile) ModTime() time.Time {
	return f.Timestamp
}

func (f *FakeFile) Size() int64 {
	return f.Len
}

func (f *FakeFile) IsDir() bool {
	return f.Mode().IsDir()
}

func (f *FakeFile) Sys() interface{} {
	return nil
}

// AssetFile implements http.File interface for a no-directory file with content
type AssetFile struct {
	*bytes.Reader
	io.Closer
	FakeFile
}

func NewAssetFile(name string, content []byte, timestamp time.Time) *AssetFile {
	if timestamp.IsZero() {
		timestamp = defaultFileTimestamp
	}
	return &AssetFile{
		bytes.NewReader(content),
		ioutil.NopCloser(nil),
		FakeFile{name, false, int64(len(content)), timestamp}}
}

func (f *AssetFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, errors.New("not a directory")
}

func (f *AssetFile) Size() int64 {
	return f.FakeFile.Size()
}

func (f *AssetFile) Stat() (os.FileInfo, error) {
	return f, nil
}

// AssetDirectory implements http.File interface for a directory
type AssetDirectory struct {
	AssetFile
	ChildrenRead int
	Children     []os.FileInfo
}

func NewAssetDirectory(name string, children []string, fs *AssetFS) *AssetDirectory {
	fileinfos := make([]os.FileInfo, 0, len(children))
	for _, child := range children {
		_, err := fs.AssetDir(filepath.Join(name, child))
		fileinfos = append(fileinfos, &FakeFile{child, err == nil, 0, time.Time{}})
	}
	return &AssetDirectory{
		AssetFile{
			bytes.NewReader(nil),
			ioutil.NopCloser(nil),
			FakeFile{name, true, 0, time.Time{}},
		},
		0,
		fileinfos}
}

func (f *AssetDirectory) Readdir(count int) ([]os.FileInfo, error) {
	if count <= 0 {
		return f.Children, nil
	}
	if f.ChildrenRead+count > len(f.Children) {
		count = len(f.Children) - f.ChildrenRead
	}
	rv := f.Children[f.ChildrenRead : f.ChildrenRead+count]
	f.ChildrenRead += count
	return rv, nil
}

func (f *AssetDirectory) Stat() (os.FileInfo, error) {
	return f, nil
}

// AssetFS implements http.FileSystem, allowing
// embedded files to be served from net/http package.
type AssetFS struct {
	// Asset should return content of file in path if exists
	Asset func(path string) ([]byte, error)
	// AssetDir should return list of files in the path
	AssetDir func(path string) ([]string, error)
	// AssetInfo should return the info of file in path if exists
	AssetInfo func(path string) (os.FileInfo, error)
	// Prefix would be prepended to http requests
	Prefix string
}

func (fs *AssetFS) Open(name string) (http.File, error) {
	name = path.Join(fs.Prefix, name)
	if len(name) > 0 && name[0] == '/' {
		name = name[1:]
	}
	if b, err := fs.Asset(name); err == nil {
		timestamp := defaultFileTimestamp
		if info, err := fs.AssetInfo(name); err == nil {
			timestamp = info.ModTime()
		}
		return NewAssetFile(name, b, timestamp), nil
	}
	if children, err := fs.AssetDir(name); err == nil {
		return NewAssetDirectory(name, children, fs), nil
	} else {
		return nil, err
	}
}
<commit_msg>Don't panic if AssetInfo has not been defined<commit_after>package assetfs

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

var (
	defaultFileTimestamp = time.Now()
)

// FakeFile implements os.FileInfo interface for a given path and size
type FakeFile struct {
	// Path is the path of this file
	Path string
	// Dir marks of the path is a directory
	Dir bool
	// Len is the length of the fake file, zero if it is a directory
	Len int64
	// Timestamp is the ModTime of this file
	Timestamp time.Time
}

func (f *FakeFile) Name() string {
	_, name := filepath.Split(f.Path)
	return name
}

func (f *FakeFile) Mode() os.FileMode {
	mode := os.FileMode(0644)
	if f.Dir {
		return mode | os.ModeDir
	}
	return mode
}

func (f *FakeFile) ModTime() time.Time {
	return f.Timestamp
}

func (f *FakeFile) Size() int64 {
	return f.Len
}

func (f *FakeFile) IsDir() bool {
	return f.Mode().IsDir()
}

func (f *FakeFile) Sys() interface{} {
	return nil
}

// AssetFile implements http.File interface for a no-directory file with content
type AssetFile struct {
	*bytes.Reader
	io.Closer
	FakeFile
}

func NewAssetFile(name string, content []byte, timestamp time.Time) *AssetFile {
	if timestamp.IsZero() {
		timestamp = defaultFileTimestamp
	}
	return &AssetFile{
		bytes.NewReader(content),
		ioutil.NopCloser(nil),
		FakeFile{name, false, int64(len(content)), timestamp}}
}

func (f *AssetFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, errors.New("not a directory")
}

func (f *AssetFile) Size() int64 {
	return f.FakeFile.Size()
}

func (f *AssetFile) Stat() (os.FileInfo, error) {
	return f, nil
}

// AssetDirectory implements http.File interface for a directory
type AssetDirectory struct {
	AssetFile
	ChildrenRead int
	Children     []os.FileInfo
}

func NewAssetDirectory(name string, children []string, fs *AssetFS) *AssetDirectory {
	fileinfos := make([]os.FileInfo, 0, len(children))
	for _, child := range children {
		_, err := fs.AssetDir(filepath.Join(name, child))
		fileinfos = append(fileinfos, &FakeFile{child, err == nil, 0, time.Time{}})
	}
	return &AssetDirectory{
		AssetFile{
			bytes.NewReader(nil),
			ioutil.NopCloser(nil),
			FakeFile{name, true, 0, time.Time{}},
		},
		0,
		fileinfos}
}

func (f *AssetDirectory) Readdir(count int) ([]os.FileInfo, error) {
	if count <= 0 {
		return f.Children, nil
	}
	if f.ChildrenRead+count > len(f.Children) {
		count = len(f.Children) - f.ChildrenRead
	}
	rv := f.Children[f.ChildrenRead : f.ChildrenRead+count]
	f.ChildrenRead += count
	return rv, nil
}

func (f *AssetDirectory) Stat() (os.FileInfo, error) {
	return f, nil
}

// AssetFS implements http.FileSystem, allowing
// embedded files to be served from net/http package.
type AssetFS struct {
	// Asset should return content of file in path if exists
	Asset func(path string) ([]byte, error)
	// AssetDir should return list of files in the path
	AssetDir func(path string) ([]string, error)
	// AssetInfo should return the info of file in path if exists
	AssetInfo func(path string) (os.FileInfo, error)
	// Prefix would be prepended to http requests
	Prefix string
}

func (fs *AssetFS) Open(name string) (http.File, error) {
	name = path.Join(fs.Prefix, name)
	if len(name) > 0 && name[0] == '/' {
		name = name[1:]
	}
	if b, err := fs.Asset(name); err == nil {
		timestamp := defaultFileTimestamp
		if fs.AssetInfo != nil {
			if info, err := fs.AssetInfo(name); err == nil {
				timestamp = info.ModTime()
			}
		}
		return NewAssetFile(name, b, timestamp), nil
	}
	if children, err := fs.AssetDir(name); err == nil {
		return NewAssetDirectory(name, children, fs), nil
	} else {
		return nil, err
	}
}
<|endoftext|>


<commit_before>package proto

import(
	pb "goprotobuf.googlecode.com/hg/proto"
	"io/ioutil"
	"path/filepath"
	"fmt"
)

func NewMixer(path string) (*Mixer) {
	version, err := ioutil.ReadFile(path + "/VERSION")

	if err != nil {
		panic("Couldn't find a version for mixer:" + path + ":" + err.String() )
	}

	_, name := filepath.Split(path)

	return &Mixer{
	Name: pb.String(name),
	Version: pb.String( string(version) ),
	Assets: make([]*File,0),
	Features: make([]*Feature,0),
	Recipes: make([]*Recipe,0),
	Rewriters: make([]*File,0),
	Package: nil,
	}

}

func (m *Mixer) Write(path string) (outputPath string) {

	name := pb.GetString(m.Name)
	version := pb.GetString(m.Version)
	outputFilename := filepath.Join(path, name + "-" + version + ".mxr")

	bytes, err := pb.Marshal(m)

	if err != nil {
		panic("Could not marshal mixer (" + name + "), " + err.String())
	}

	//bytes = crypto.Encrypt(bytes)

	ioutil.WriteFile(outputFilename, bytes, uint32(0666) )

	return outputFilename
}

func OpenMixer(location string) (m *Mixer) {

	data, err := ioutil.ReadFile(location)

	if err != nil {
		panic("Could not find mixer file:" + location)
	}

	//data = crypto.Decrypt(data)

	thisMixer := &Mixer{}
	err = pb.Unmarshal(data, thisMixer)

	if err != nil {
		panic("Error unmarshalling mixer at:" + location)
	}

	return thisMixer
}

func (m *Mixer) Inspect() {
	fmt.Printf(" \tFeatures: \n\t\t%v\n", m.Features)

	println("\tAssets:")
	for _, asset := range(m.Assets) {
		fmt.Printf("\t\t -- %v\n", pb.GetString(asset.Path) )
	}

	println("\tRecipes:")
	for _, recipe := range(m.Recipes) {
		fmt.Printf("\t\t -- Recipe (%v) contains (%v) files.\n", pb.GetString(recipe.Name), len(recipe.Files) )
	}

	println("\tRewriters:")
	for _, rewriter := range(m.Rewriters) {
		fmt.Printf("\t\t -- %v\n", pb.GetString(rewriter.Path) )
	}

	println("\tRoot Package:")
	if m.Package != nil {
		fmt.Printf("\t\t -- Name: %v\n", pb.GetString(m.Package.Name) )
		fmt.Printf("\t\t -- Types: %v\n", m.Package.Types )
		fmt.Printf("\t\t -- Dependencies:  %v\n", m.Package.Dependencies )
	}

}<commit_msg>Added ResolveMixer() function<commit_after>package proto

import(
	pb "goprotobuf.googlecode.com/hg/proto"
	"io/ioutil"
	"path/filepath"
	"fmt"
	"os"
	"strings"
)

func NewMixer(path string) (*Mixer) {
	version, err := ioutil.ReadFile(path + "/VERSION")

	if err != nil {
		panic("Couldn't find a version for mixer:" + path + ":" + err.String() )
	}

	_, name := filepath.Split(path)

	return &Mixer{
	Name: pb.String(name),
	Version: pb.String( string(version) ),
	Assets: make([]*File,0),
	Features: make([]*Feature,0),
	Recipes: make([]*Recipe,0),
	Rewriters: make([]*File,0),
	Package: nil,
	}

}

func ResolveMixer(name string) (*Mixer) {
	path := os.ShellExpand("$GOHATTAN_DATA/mixers/")

	if !strings.Contains(name, ".mxr") {
		name = name + ".mxr"
	}

	fullPath := filepath.Join(path, name)
	return OpenMixer(fullPath)
}

func (m *Mixer) Write(path string) (outputPath string) {

	name := pb.GetString(m.Name)
	version := pb.GetString(m.Version)
	outputFilename := filepath.Join(path, name + "-" + version + ".mxr")

	bytes, err := pb.Marshal(m)

	if err != nil {
		panic("Could not marshal mixer (" + name + "), " + err.String())
	}

	//bytes = crypto.Encrypt(bytes)

	ioutil.WriteFile(outputFilename, bytes, uint32(0666) )

	return outputFilename
}

func OpenMixer(location string) (m *Mixer) {

	data, err := ioutil.ReadFile(location)

	if err != nil {
		panic("Could not find mixer file:" + location)
	}

	//data = crypto.Decrypt(data)

	thisMixer := &Mixer{}
	err = pb.Unmarshal(data, thisMixer)

	if err != nil {
		panic("Error unmarshalling mixer at:" + location)
	}

	return thisMixer
}

func (m *Mixer) Inspect() {
	fmt.Printf(" \tFeatures: \n\t\t%v\n", m.Features)

	println("\tAssets:")
	for _, asset := range(m.Assets) {
		fmt.Printf("\t\t -- %v\n", pb.GetString(asset.Path) )
	}

	println("\tRecipes:")
	for _, recipe := range(m.Recipes) {
		fmt.Printf("\t\t -- Recipe (%v) contains (%v) files.\n", pb.GetString(recipe.Name), len(recipe.Files) )
	}

	println("\tRewriters:")
	for _, rewriter := range(m.Rewriters) {
		fmt.Printf("\t\t -- %v\n", pb.GetString(rewriter.Path) )
	}

	println("\tRoot Package:")
	if m.Package != nil {
		fmt.Printf("\t\t -- Name: %v\n", pb.GetString(m.Package.Name) )
		fmt.Printf("\t\t -- Types: %v\n", m.Package.Types )
		fmt.Printf("\t\t -- Dependencies:  %v\n", m.Package.Dependencies )
	}

}<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 s3

import (
	"github.com/jacobsa/aws/s3/auth/mock"
	"github.com/jacobsa/aws/s3/http/mock"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestBucket(t *testing.T) { RunTests(t) }

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

type bucketTest struct {
	httpConn mock_http.MockConn
	signer mock_auth.MockSigner
	bucket Bucket
}

func (t *bucketTest) SetUp(i *TestInfo) {
	var err error

	t.httpConn = mock_http.NewMockConn(i.MockController, "httpConn")
	t.signer = mock_auth.NewMockSigner(i.MockController, "signer")
	t.bucket, err = openBucket("some.bucket", t.httpConn, t.signer)
	AssertEq(nil, err)
}

////////////////////////////////////////////////////////////////////////
// GetObject
////////////////////////////////////////////////////////////////////////

type GetObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&GetObjectTest{}) }

func (t *GetObjectTest) DoesFoo() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// StoreObject
////////////////////////////////////////////////////////////////////////

type StoreObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&StoreObjectTest{}) }

func (t *StoreObjectTest) KeyNotValidUtf8() {
	ExpectEq("TODO", "")
}

func (t *StoreObjectTest) KeyTooLong() {
	ExpectEq("TODO", "")
}

func (t *StoreObjectTest) CallsSignerAndConn() {
	ExpectEq("TODO", "")
}

func (t *StoreObjectTest) ConnReturnsError() {
	ExpectEq("TODO", "")
}

func (t *StoreObjectTest) ServerReturnsError() {
	ExpectEq("TODO", "")
}

func (t *StoreObjectTest) ServerSaysOkay() {
	ExpectEq("TODO", "")
}
<commit_msg>StoreObjectTest.KeyNotValidUtf8<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 s3

import (
	"github.com/jacobsa/aws/s3/auth/mock"
	"github.com/jacobsa/aws/s3/http/mock"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestBucket(t *testing.T) { RunTests(t) }

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

type bucketTest struct {
	httpConn mock_http.MockConn
	signer mock_auth.MockSigner
	bucket Bucket
}

func (t *bucketTest) SetUp(i *TestInfo) {
	var err error

	t.httpConn = mock_http.NewMockConn(i.MockController, "httpConn")
	t.signer = mock_auth.NewMockSigner(i.MockController, "signer")
	t.bucket, err = openBucket("some.bucket", t.httpConn, t.signer)
	AssertEq(nil, err)
}

////////////////////////////////////////////////////////////////////////
// GetObject
////////////////////////////////////////////////////////////////////////

type GetObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&GetObjectTest{}) }

func (t *GetObjectTest) DoesFoo() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// StoreObject
////////////////////////////////////////////////////////////////////////

type StoreObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&StoreObjectTest{}) }

func (t *StoreObjectTest) KeyNotValidUtf8() {
	key := "\x80\x81\x82"
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("valid")))
	ExpectThat(err, Error(HasSubstr("UTF-8")))
}

func (t *StoreObjectTest) KeyTooLong() {
	ExpectEq("TODO", "")
}

func (t *StoreObjectTest) CallsSignerAndConn() {
	ExpectEq("TODO", "")
}

func (t *StoreObjectTest) ConnReturnsError() {
	ExpectEq("TODO", "")
}

func (t *StoreObjectTest) ServerReturnsError() {
	ExpectEq("TODO", "")
}

func (t *StoreObjectTest) ServerSaysOkay() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>// Application that captures webpage archives on a CT worker and uploads it to
// Google Storage.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"

	"github.com/skia-dev/glog"

	"strings"
	"time"

	"go.skia.org/infra/ct/go/util"
	"go.skia.org/infra/go/common"
	skutil "go.skia.org/infra/go/util"
)

var (
	workerNum     = flag.Int("worker_num", 1, "The number of this CT worker. It will be in the {1..100} range.")
	pagesetType   = flag.String("pageset_type", util.PAGESET_TYPE_MOBILE_10k, "The type of pagesets to create from the Alexa CSV list. Eg: 10k, Mobile10k, All.")
	chromiumBuild = flag.String("chromium_build", "", "The chromium build to use for this capture_archives run.")
)

func main() {
	common.Init()
	defer util.TimeTrack(time.Now(), "Capturing Archives")
	defer glog.Flush()

	// Create the task file so that the master knows this worker is still busy.
	skutil.LogErr(util.CreateTaskFile(util.ACTIVITY_CAPTURING_ARCHIVES))
	defer util.DeleteTaskFile(util.ACTIVITY_CAPTURING_ARCHIVES)

	if *chromiumBuild == "" {
		glog.Error("Must specify --chromium_build")
		return
	}

	// Reset the local chromium checkout.
	if err := util.ResetCheckout(util.ChromiumSrcDir); err != nil {
		glog.Errorf("Could not reset %s: %s", util.ChromiumSrcDir, err)
		return
	}
	// Sync the local chromium checkout.
	if err := util.SyncDir(util.ChromiumSrcDir); err != nil {
		glog.Errorf("Could not gclient sync %s: %s", util.ChromiumSrcDir, err)
		return
	}

	// Delete and remake the local webpage archives directory.
	pathToArchives := filepath.Join(util.WebArchivesDir, *pagesetType)
	skutil.RemoveAll(pathToArchives)
	skutil.MkdirAll(pathToArchives, 0700)

	// Instantiate GsUtil object.
	gs, err := util.NewGsUtil(nil)
	if err != nil {
		glog.Error(err)
		return
	}

	// Download the specified chromium build if it does not exist locally.
	if err := gs.DownloadChromiumBuild(*chromiumBuild); err != nil {
		glog.Error(err)
		return
	}

	// Download pagesets if they do not exist locally.
	if err := gs.DownloadWorkerArtifacts(util.PAGESETS_DIR_NAME, *pagesetType, *workerNum); err != nil {
		glog.Error(err)
		return
	}

	pathToPagesets := filepath.Join(util.PagesetsDir, *pagesetType)
	chromiumBinary := filepath.Join(util.ChromiumBuildsDir, *chromiumBuild, util.BINARY_CHROME)
	recordWprBinary := filepath.Join(util.TelemetryBinariesDir, util.BINARY_RECORD_WPR)
	timeoutSecs := util.PagesetTypeToInfo[*pagesetType].CaptureArchivesTimeoutSecs
	// Loop through all pagesets.
	fileInfos, err := ioutil.ReadDir(pathToPagesets)
	if err != nil {
		glog.Errorf("Unable to read the pagesets dir %s: %s", pathToPagesets, err)
		return
	}
	// TODO(rmistry): Remove this hack once the 1M webpage archives have been captured.
	fileInfos = fileInfos[2999:3500]
	for _, fileInfo := range fileInfos {
		pagesetBaseName := filepath.Base(fileInfo.Name())
		if pagesetBaseName == util.TIMESTAMP_FILE_NAME || filepath.Ext(pagesetBaseName) == ".pyc" {
			// Ignore timestamp files and .pyc files.
			continue
		}

		// Convert the filename into a format consumable by the record_wpr binary.
		pagesetArchiveName := strings.TrimSuffix(pagesetBaseName, filepath.Ext(pagesetBaseName))
		pagesetPath := filepath.Join(pathToPagesets, fileInfo.Name())

		glog.Infof("===== Processing %s =====", pagesetPath)
		args := []string{
			"--extra-browser-args=--disable-setuid-sandbox",
			"--browser=exact",
			"--browser-executable=" + chromiumBinary,
			fmt.Sprintf("%s_page_set", pagesetArchiveName),
			"--page-set-base-dir=" + pathToPagesets,
		}
		env := []string{
			fmt.Sprintf("PYTHONPATH=%s:$PYTHONPATH", pathToPagesets),
			"DISPLAY=:0",
		}
		skutil.LogErr(util.ExecuteCmd(recordWprBinary, args, env, time.Duration(timeoutSecs)*time.Second, nil, nil))
	}

	// Write timestamp to the webpage archives dir.
	skutil.LogErr(util.CreateTimestampFile(pathToArchives))

	// Upload webpage archives dir to Google Storage.
	if err := gs.UploadWorkerArtifacts(util.WEB_ARCHIVES_DIR_NAME, *pagesetType, *workerNum); err != nil {
		glog.Error(err)
		return
	}
}
<commit_msg>Capture CT archives from 3500-3999<commit_after>// Application that captures webpage archives on a CT worker and uploads it to
// Google Storage.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"

	"github.com/skia-dev/glog"

	"strings"
	"time"

	"go.skia.org/infra/ct/go/util"
	"go.skia.org/infra/go/common"
	skutil "go.skia.org/infra/go/util"
)

var (
	workerNum     = flag.Int("worker_num", 1, "The number of this CT worker. It will be in the {1..100} range.")
	pagesetType   = flag.String("pageset_type", util.PAGESET_TYPE_MOBILE_10k, "The type of pagesets to create from the Alexa CSV list. Eg: 10k, Mobile10k, All.")
	chromiumBuild = flag.String("chromium_build", "", "The chromium build to use for this capture_archives run.")
)

func main() {
	common.Init()
	defer util.TimeTrack(time.Now(), "Capturing Archives")
	defer glog.Flush()

	// Create the task file so that the master knows this worker is still busy.
	skutil.LogErr(util.CreateTaskFile(util.ACTIVITY_CAPTURING_ARCHIVES))
	defer util.DeleteTaskFile(util.ACTIVITY_CAPTURING_ARCHIVES)

	if *chromiumBuild == "" {
		glog.Error("Must specify --chromium_build")
		return
	}

	// Reset the local chromium checkout.
	if err := util.ResetCheckout(util.ChromiumSrcDir); err != nil {
		glog.Errorf("Could not reset %s: %s", util.ChromiumSrcDir, err)
		return
	}
	// Sync the local chromium checkout.
	if err := util.SyncDir(util.ChromiumSrcDir); err != nil {
		glog.Errorf("Could not gclient sync %s: %s", util.ChromiumSrcDir, err)
		return
	}

	// Delete and remake the local webpage archives directory.
	pathToArchives := filepath.Join(util.WebArchivesDir, *pagesetType)
	skutil.RemoveAll(pathToArchives)
	skutil.MkdirAll(pathToArchives, 0700)

	// Instantiate GsUtil object.
	gs, err := util.NewGsUtil(nil)
	if err != nil {
		glog.Error(err)
		return
	}

	// Download the specified chromium build if it does not exist locally.
	if err := gs.DownloadChromiumBuild(*chromiumBuild); err != nil {
		glog.Error(err)
		return
	}

	// Download pagesets if they do not exist locally.
	if err := gs.DownloadWorkerArtifacts(util.PAGESETS_DIR_NAME, *pagesetType, *workerNum); err != nil {
		glog.Error(err)
		return
	}

	pathToPagesets := filepath.Join(util.PagesetsDir, *pagesetType)
	chromiumBinary := filepath.Join(util.ChromiumBuildsDir, *chromiumBuild, util.BINARY_CHROME)
	recordWprBinary := filepath.Join(util.TelemetryBinariesDir, util.BINARY_RECORD_WPR)
	timeoutSecs := util.PagesetTypeToInfo[*pagesetType].CaptureArchivesTimeoutSecs
	// Loop through all pagesets.
	fileInfos, err := ioutil.ReadDir(pathToPagesets)
	if err != nil {
		glog.Errorf("Unable to read the pagesets dir %s: %s", pathToPagesets, err)
		return
	}
	// TODO(rmistry): Remove this hack once the 1M webpage archives have been captured.
	fileInfos = fileInfos[3500:4000]
	for _, fileInfo := range fileInfos {
		pagesetBaseName := filepath.Base(fileInfo.Name())
		if pagesetBaseName == util.TIMESTAMP_FILE_NAME || filepath.Ext(pagesetBaseName) == ".pyc" {
			// Ignore timestamp files and .pyc files.
			continue
		}

		// Convert the filename into a format consumable by the record_wpr binary.
		pagesetArchiveName := strings.TrimSuffix(pagesetBaseName, filepath.Ext(pagesetBaseName))
		pagesetPath := filepath.Join(pathToPagesets, fileInfo.Name())

		glog.Infof("===== Processing %s =====", pagesetPath)
		args := []string{
			"--extra-browser-args=--disable-setuid-sandbox",
			"--browser=exact",
			"--browser-executable=" + chromiumBinary,
			fmt.Sprintf("%s_page_set", pagesetArchiveName),
			"--page-set-base-dir=" + pathToPagesets,
		}
		env := []string{
			fmt.Sprintf("PYTHONPATH=%s:$PYTHONPATH", pathToPagesets),
			"DISPLAY=:0",
		}
		skutil.LogErr(util.ExecuteCmd(recordWprBinary, args, env, time.Duration(timeoutSecs)*time.Second, nil, nil))
	}

	// Write timestamp to the webpage archives dir.
	skutil.LogErr(util.CreateTimestampFile(pathToArchives))

	// Upload webpage archives dir to Google Storage.
	if err := gs.UploadWorkerArtifacts(util.WEB_ARCHIVES_DIR_NAME, *pagesetType, *workerNum); err != nil {
		glog.Error(err)
		return
	}
}
<|endoftext|>


<commit_before>package autotls

import (
	"context"
	"crypto/tls"
	"log"
	"net/http"

	"golang.org/x/crypto/acme/autocert"
	"golang.org/x/sync/errgroup"
)

type tlsContextKey string

var ctxKey = tlsContextKey("autls")

func run(ctx context.Context, r http.Handler, domain ...string) error {
	var g errgroup.Group

	s1 := &http.Server{
		Addr:    ":http",
		Handler: http.HandlerFunc(redirect),
	}
	s2 := &http.Server{
		Handler: r,
	}

	g.Go(func() error {
		return s1.ListenAndServe()
	})
	g.Go(func() error {
		return s2.Serve(autocert.NewListener(domain...))
	})

	g.Go(func() error {
		if v := ctx.Value(ctxKey); v != nil {
			return nil
		}

		<-ctx.Done()

		var gShutdown errgroup.Group
		gShutdown.Go(func() error {
			return s1.Shutdown(context.Background())
		})
		gShutdown.Go(func() error {
			return s2.Shutdown(context.Background())
		})

		return gShutdown.Wait()
	})
	return g.Wait()
}

// Run support 1-line LetsEncrypt HTTPS servers with graceful shutdown
func RunWithContext(ctx context.Context, r http.Handler, domain ...string) error {
	return run(ctx, r, domain...)
}

// Run support 1-line LetsEncrypt HTTPS servers
func Run(r http.Handler, domain ...string) error {
	ctx := context.WithValue(context.Background(), ctxKey, "done")
	return run(ctx, r, domain...)
}

// RunWithManager support custom autocert manager
func RunWithManager(r http.Handler, m *autocert.Manager) error {
	return RunWithManagerAndTLSConfig(r, m, *m.TLSConfig())
}

// RunWithManagerAndTLSConfig support custom autocert manager and tls.Config
func RunWithManagerAndTLSConfig(r http.Handler, m *autocert.Manager, tlsc tls.Config) error {
	var g errgroup.Group
	if m.Cache == nil {
		var e error
		m.Cache, e = getCacheDir()
		if e != nil {
			log.Println(e)
		}
	}
	defaultTLSConfig := m.TLSConfig()
	tlsc.GetCertificate = defaultTLSConfig.GetCertificate
	tlsc.NextProtos = defaultTLSConfig.NextProtos
	s := &http.Server{
		Addr:      ":https",
		TLSConfig: &tlsc,
		Handler:   r,
	}
	g.Go(func() error {
		return http.ListenAndServe(":http", m.HTTPHandler(http.HandlerFunc(redirect)))
	})
	g.Go(func() error {
		return s.ListenAndServeTLS("", "")
	})
	return g.Wait()
}

func redirect(w http.ResponseWriter, req *http.Request) {
	target := "https://" + req.Host + req.RequestURI

	http.Redirect(w, req, target, http.StatusMovedPermanently)
}
<commit_msg>fix: passes lock by value: crypto/tls.Config contains sync.RWMutex<commit_after>package autotls

import (
	"context"
	"crypto/tls"
	"log"
	"net/http"

	"golang.org/x/crypto/acme/autocert"
	"golang.org/x/sync/errgroup"
)

type tlsContextKey string

var (
	ctxKey  = tlsContextKey("autls")
	todoCtx = context.WithValue(context.Background(), ctxKey, "done")
)

func run(ctx context.Context, r http.Handler, domain ...string) error {
	var g errgroup.Group

	s1 := &http.Server{
		Addr:    ":http",
		Handler: http.HandlerFunc(redirect),
	}
	s2 := &http.Server{
		Handler: r,
	}

	g.Go(func() error {
		return s1.ListenAndServe()
	})
	g.Go(func() error {
		return s2.Serve(autocert.NewListener(domain...))
	})

	g.Go(func() error {
		if v := ctx.Value(ctxKey); v != nil {
			return nil
		}

		<-ctx.Done()

		var gShutdown errgroup.Group
		gShutdown.Go(func() error {
			return s1.Shutdown(context.Background())
		})
		gShutdown.Go(func() error {
			return s2.Shutdown(context.Background())
		})

		return gShutdown.Wait()
	})
	return g.Wait()
}

// Run support 1-line LetsEncrypt HTTPS servers with graceful shutdown
func RunWithContext(ctx context.Context, r http.Handler, domain ...string) error {
	return run(ctx, r, domain...)
}

// Run support 1-line LetsEncrypt HTTPS servers
func Run(r http.Handler, domain ...string) error {
	return run(todoCtx, r, domain...)
}

// RunWithManager support custom autocert manager
func RunWithManager(r http.Handler, m *autocert.Manager) error {
	return RunWithManagerAndTLSConfig(r, m, m.TLSConfig())
}

// RunWithManagerAndTLSConfig support custom autocert manager and tls.Config
func RunWithManagerAndTLSConfig(r http.Handler, m *autocert.Manager, tlsc *tls.Config) error {
	var g errgroup.Group
	if m.Cache == nil {
		var e error
		m.Cache, e = getCacheDir()
		if e != nil {
			log.Println(e)
		}
	}
	defaultTLSConfig := m.TLSConfig()
	tlsc.GetCertificate = defaultTLSConfig.GetCertificate
	tlsc.NextProtos = defaultTLSConfig.NextProtos
	s := &http.Server{
		Addr:      ":https",
		TLSConfig: tlsc,
		Handler:   r,
	}
	g.Go(func() error {
		return http.ListenAndServe(":http", m.HTTPHandler(http.HandlerFunc(redirect)))
	})
	g.Go(func() error {
		return s.ListenAndServeTLS("", "")
	})
	return g.Wait()
}

func redirect(w http.ResponseWriter, req *http.Request) {
	target := "https://" + req.Host + req.RequestURI

	http.Redirect(w, req, target, http.StatusMovedPermanently)
}
<|endoftext|>


<commit_before>// Copyright 2019 The gVisor Authors
//
// 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
//
//     https://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.

// Binary syscalldocs generates system call markdown.
package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"text/template"
)

// CompatibilityInfo is the collection of all information.
type CompatibilityInfo map[string]map[string]ArchInfo

// ArchInfo is compatbility doc for an architecture.
type ArchInfo struct {
	// Syscalls maps syscall number for the architecture to the doc.
	Syscalls map[uintptr]SyscallDoc `json:"syscalls"`
}

// SyscallDoc represents a single item of syscall documentation.
type SyscallDoc struct {
	Name    string   `json:"name"`
	Support string   `json:"support"`
	Note    string   `json:"note,omitempty"`
	URLs    []string `json:"urls,omitempty"`
}

var mdTemplate = template.Must(template.New("out").Parse(`---
title: {{.OS}}/{{.Arch}}
description: Syscall Compatibility Reference Documentation for {{.OS}}/{{.Arch}}
layout: docs
category: Compatibility
weight: 50
permalink: /docs/user_guide/compatibility/{{.OS}}/{{.Arch}}/
---

This table is a reference of {{.OS}} syscalls for the {{.Arch}} architecture and
their compatibility status in gVisor. gVisor does not support all syscalls and
some syscalls may have a partial implementation.

This page is automatically generated from the source code.

Of {{.Total}} syscalls, {{.Supported}} syscalls have a full or partial
implementation. There are currently {{.Unsupported}} unsupported
syscalls. {{if .Undocumented}}{{.Undocumented}} syscalls are not yet documented.{{end}}

      #
      Name
      Support
      Notes

 	{{range $i, $syscall := .Syscalls}}

      {{.Number}}
      {{.Name}}
      {{.Support}}
	  {{.Note}} {{range $i, $url := .URLs}}
See: {{.}}{{end}}

	{{end}}

`))

// Fatalf writes a message to stderr and exits with error code 1
func Fatalf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
	os.Exit(1)
}

func main() {
	inputFlag := flag.String("in", "-", "File to input ('-' for stdin)")
	outputDir := flag.String("out", ".", "Directory to output files.")

	flag.Parse()

	var input io.Reader
	if *inputFlag == "-" {
		input = os.Stdin
	} else {
		i, err := os.Open(*inputFlag)
		if err != nil {
			Fatalf("Error opening %q: %v", *inputFlag, err)
		}
		input = i
	}
	input = bufio.NewReader(input)

	var info CompatibilityInfo
	d := json.NewDecoder(input)
	if err := d.Decode(&info); err != nil {
		Fatalf("Error reading json: %v", err)
	}

	weight := 0
	for osName, osInfo := range info {
		for archName, archInfo := range osInfo {
			outDir := filepath.Join(*outputDir, osName)
			outFile := filepath.Join(outDir, archName+".md")

			if err := os.MkdirAll(outDir, 0755); err != nil {
				Fatalf("Error creating directory %q: %v", *outputDir, err)
			}

			f, err := os.OpenFile(outFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
			if err != nil {
				Fatalf("Error opening file %q: %v", outFile, err)
			}
			defer f.Close()

			weight += 10
			data := struct {
				OS           string
				Arch         string
				Weight       int
				Total        int
				Supported    int
				Unsupported  int
				Undocumented int
				Syscalls     []struct {
					Name    string
					Number  uintptr
					Support string
					Note    string
					URLs    []string
				}
			}{
				OS:           strings.Title(osName),
				Arch:         archName,
				Weight:       weight,
				Total:        0,
				Supported:    0,
				Unsupported:  0,
				Undocumented: 0,
				Syscalls: []struct {
					Name    string
					Number  uintptr
					Support string
					Note    string
					URLs    []string
				}{},
			}

			for num, s := range archInfo.Syscalls {
				switch s.Support {
				case "Full Support", "Partial Support":
					data.Supported++
				case "Unimplemented":
					data.Unsupported++
				default:
					data.Undocumented++
				}
				data.Total++

				for i := range s.URLs {
					if !strings.HasPrefix(s.URLs[i], "http://") && !strings.HasPrefix(s.URLs[i], "https://") {
						s.URLs[i] = "https://" + s.URLs[i]
					}
				}

				data.Syscalls = append(data.Syscalls, struct {
					Name    string
					Number  uintptr
					Support string
					Note    string
					URLs    []string
				}{
					Name:    s.Name,
					Number:  num,
					Support: s.Support,
					Note:    s.Note, // TODO urls
					URLs:    s.URLs,
				})
			}

			sort.Slice(data.Syscalls, func(i, j int) bool {
				return data.Syscalls[i].Number < data.Syscalls[j].Number
			})

			if err := mdTemplate.Execute(f, data); err != nil {
				Fatalf("Error writing file %q: %v", outFile, err)
			}
		}
	}
}
<commit_msg>Unbreak permalink.<commit_after>// Copyright 2019 The gVisor Authors
//
// 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
//
//     https://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.

// Binary syscalldocs generates system call markdown.
package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"text/template"
)

// CompatibilityInfo is the collection of all information.
type CompatibilityInfo map[string]map[string]ArchInfo

// ArchInfo is compatbility doc for an architecture.
type ArchInfo struct {
	// Syscalls maps syscall number for the architecture to the doc.
	Syscalls map[uintptr]SyscallDoc `json:"syscalls"`
}

// SyscallDoc represents a single item of syscall documentation.
type SyscallDoc struct {
	Name    string   `json:"name"`
	Support string   `json:"support"`
	Note    string   `json:"note,omitempty"`
	URLs    []string `json:"urls,omitempty"`
}

var mdTemplate = template.Must(template.New("out").Parse(`---
title: {{.Title}}
description: Syscall Compatibility Reference Documentation for {{.OS}}/{{.Arch}}
layout: docs
category: Compatibility
weight: 50
permalink: /docs/user_guide/compatibility/{{.OS}}/{{.Arch}}/
---

This table is a reference of {{.OS}} syscalls for the {{.Arch}} architecture and
their compatibility status in gVisor. gVisor does not support all syscalls and
some syscalls may have a partial implementation.

This page is automatically generated from the source code.

Of {{.Total}} syscalls, {{.Supported}} syscalls have a full or partial
implementation. There are currently {{.Unsupported}} unsupported
syscalls. {{if .Undocumented}}{{.Undocumented}} syscalls are not yet documented.{{end}}

      #
      Name
      Support
      Notes

 	{{range $i, $syscall := .Syscalls}}

      {{.Number}}
      {{.Name}}
      {{.Support}}
	  {{.Note}} {{range $i, $url := .URLs}}
See: {{.}}{{end}}

	{{end}}

`))

// Fatalf writes a message to stderr and exits with error code 1
func Fatalf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
	os.Exit(1)
}

func main() {
	inputFlag := flag.String("in", "-", "File to input ('-' for stdin)")
	outputDir := flag.String("out", ".", "Directory to output files.")

	flag.Parse()

	var input io.Reader
	if *inputFlag == "-" {
		input = os.Stdin
	} else {
		i, err := os.Open(*inputFlag)
		if err != nil {
			Fatalf("Error opening %q: %v", *inputFlag, err)
		}
		input = i
	}
	input = bufio.NewReader(input)

	var info CompatibilityInfo
	d := json.NewDecoder(input)
	if err := d.Decode(&info); err != nil {
		Fatalf("Error reading json: %v", err)
	}

	weight := 0
	for osName, osInfo := range info {
		for archName, archInfo := range osInfo {
			outDir := filepath.Join(*outputDir, osName)
			outFile := filepath.Join(outDir, archName+".md")

			if err := os.MkdirAll(outDir, 0755); err != nil {
				Fatalf("Error creating directory %q: %v", *outputDir, err)
			}

			f, err := os.OpenFile(outFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
			if err != nil {
				Fatalf("Error opening file %q: %v", outFile, err)
			}
			defer f.Close()

			weight += 10
			data := struct {
				Title        string
				OS           string
				Arch         string
				Weight       int
				Total        int
				Supported    int
				Unsupported  int
				Undocumented int
				Syscalls     []struct {
					Name    string
					Number  uintptr
					Support string
					Note    string
					URLs    []string
				}
			}{
				Title:        strings.Title(osName) + "/" + archName,
				OS:           osName,
				Arch:         archName,
				Weight:       weight,
				Total:        0,
				Supported:    0,
				Unsupported:  0,
				Undocumented: 0,
				Syscalls: []struct {
					Name    string
					Number  uintptr
					Support string
					Note    string
					URLs    []string
				}{},
			}

			for num, s := range archInfo.Syscalls {
				switch s.Support {
				case "Full Support", "Partial Support":
					data.Supported++
				case "Unimplemented":
					data.Unsupported++
				default:
					data.Undocumented++
				}
				data.Total++

				for i := range s.URLs {
					if !strings.HasPrefix(s.URLs[i], "http://") && !strings.HasPrefix(s.URLs[i], "https://") {
						s.URLs[i] = "https://" + s.URLs[i]
					}
				}

				data.Syscalls = append(data.Syscalls, struct {
					Name    string
					Number  uintptr
					Support string
					Note    string
					URLs    []string
				}{
					Name:    s.Name,
					Number:  num,
					Support: s.Support,
					Note:    s.Note, // TODO urls
					URLs:    s.URLs,
				})
			}

			sort.Slice(data.Syscalls, func(i, j int) bool {
				return data.Syscalls[i].Number < data.Syscalls[j].Number
			})

			if err := mdTemplate.Execute(f, data); err != nil {
				Fatalf("Error writing file %q: %v", outFile, err)
			}
		}
	}
}
<|endoftext|>