<commit_before>// Copyright 2017-2021 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package format

import (
	"fmt"
	"math"
	"net"
	"strconv"
	"strings"

	amassnet "github.com/OWASP/Amass/v3/net"
)

// ParseStrings implements the flag.Value interface.
type ParseStrings []string

// ParseInts implements the flag.Value interface.
type ParseInts []int

// ParseIPs implements the flag.Value interface.
type ParseIPs []net.IP

// ParseCIDRs implements the flag.Value interface.
type ParseCIDRs []*net.IPNet

// ParseASNs implements the flag.Value interface.
type ParseASNs []int

func (p *ParseStrings) String() string {
	if p == nil {
		return ""
	}
	return strings.Join(*p, ",")
}

// Set implements the flag.Value interface.
func (p *ParseStrings) Set(s string) error {
	if s == "" {
		return fmt.Errorf("String parsing failed")
	}

	str := strings.Split(s, ",")
	for _, s := range str {
		*p = append(*p, strings.TrimSpace(s))
	}
	return nil
}

func (p *ParseInts) String() string {
	if p == nil {
		return ""
	}
	var builder strings.Builder
	for i, n := range *p {
		if i > 0 {
			builder.WriteRune(',')
		}
		builder.WriteString(strconv.Itoa(n))
	}
	return builder.String()
}

// Set implements the flag.Value interface.
func (p *ParseInts) Set(s string) error {
	if s == "" {
		return fmt.Errorf("Integer parsing failed")
	}

	nums := strings.Split(s, ",")
	for _, n := range nums {
		i, err := strconv.Atoi(strings.TrimSpace(n))
		if err != nil {
			return err
		}
		*p = append(*p, i)
	}
	return nil
}

func (p *ParseIPs) String() string {
	if p == nil {
		return ""
	}
	var builder strings.Builder
	for i, ipaddr := range *p {
		if i > 0 {
			builder.WriteRune(',')
		}
		builder.WriteString(ipaddr.String())
	}
	return builder.String()
}

// Set implements the flag.Value interface.
func (p *ParseIPs) Set(s string) error {
	if s == "" {
		return fmt.Errorf("IP address parsing failed")
	}

	for _, v := range strings.Split(s, ",") {
		if start, end, ok := parseRange(v); ok {
			ips := amassnet.RangeHosts(start, end)
			if len(ips) == 0 {
				return fmt.Errorf("%s is not a valid IP address or range", v)
			}
			for _, ip := range ips {
				*p = append(*p, ip)
			}
			continue
		} else if ip := net.ParseIP(v); ip != nil {
			*p = append(*p, ip)
			continue
		} else {
			return fmt.Errorf("%s is not a valid IP address or range", v)
		}
	}
	return nil
}

func parseRange(s string) (start net.IP, end net.IP, ok bool) {
	twoIPs := strings.Split(s, "-")
	if len(twoIPs) != 2 {
		return
	}
	start = net.ParseIP(twoIPs[0])
	if start == nil {
		return
	}
	end = net.ParseIP(twoIPs[1])
	if end == nil {
		num, err := strconv.Atoi(twoIPs[1])
		if err != nil || math.MaxUint8 < num {
			return
		}
		end = make(net.IP, len(start))
		copy(end, start)
		end[len(end)-1] = byte(num)
	}
	ok = true
	return
}

func (p *ParseCIDRs) String() string {
	if p == nil {
		return ""
	}

	var builder strings.Builder
	for i, ipnet := range *p {
		if i > 0 {
			builder.WriteRune(',')
		}
		builder.WriteString(ipnet.String())
	}
	return builder.String()
}

// Set implements the flag.Value interface.
func (p *ParseCIDRs) Set(s string) error {
	if s == "" {
		return fmt.Errorf("%s is not a valid CIDR", s)
	}

	cidrs := strings.Split(s, ",")
	for _, cidr := range cidrs {
		_, ipnet, err := net.ParseCIDR(cidr)
		if err != nil {
			return fmt.Errorf("Failed to parse %s as a CIDR", cidr)
		}

		*p = append(*p, ipnet)
	}
	return nil
}

func (p *ParseASNs) String() string {
	if p == nil {
		return ""
	}
	var builder strings.Builder
	for i, n := range *p {
		if i > 0 {
			builder.WriteRune(',')
		}
		builder.WriteString(strconv.Itoa(n))
	}
	return builder.String()
}

// Set implements the flag.Value interface.
func (p *ParseASNs) Set(s string) error {
	if s == "" {
		return fmt.Errorf("ASN parsing failed")
	}

	asns := strings.Split(s, ",")
	for _, asn := range asns {
		i, err := strconv.Atoi(strings.TrimPrefix(strings.TrimSpace(asn), "AS"))
		if err != nil {
			return err
		}
		*p = append(*p, i)
	}
	return nil
}
<commit_msg>Fixed warnings from the linter<commit_after>// Copyright 2017-2021 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package format

import (
	"fmt"
	"math"
	"net"
	"strconv"
	"strings"

	amassnet "github.com/OWASP/Amass/v3/net"
)

// ParseStrings implements the flag.Value interface.
type ParseStrings []string

// ParseInts implements the flag.Value interface.
type ParseInts []int

// ParseIPs implements the flag.Value interface.
type ParseIPs []net.IP

// ParseCIDRs implements the flag.Value interface.
type ParseCIDRs []*net.IPNet

// ParseASNs implements the flag.Value interface.
type ParseASNs []int

func (p *ParseStrings) String() string {
	if p == nil {
		return ""
	}
	return strings.Join(*p, ",")
}

// Set implements the flag.Value interface.
func (p *ParseStrings) Set(s string) error {
	if s == "" {
		return fmt.Errorf("String parsing failed")
	}

	str := strings.Split(s, ",")
	for _, s := range str {
		*p = append(*p, strings.TrimSpace(s))
	}
	return nil
}

func (p *ParseInts) String() string {
	if p == nil {
		return ""
	}
	var builder strings.Builder
	for i, n := range *p {
		if i > 0 {
			builder.WriteRune(',')
		}
		builder.WriteString(strconv.Itoa(n))
	}
	return builder.String()
}

// Set implements the flag.Value interface.
func (p *ParseInts) Set(s string) error {
	if s == "" {
		return fmt.Errorf("integer parsing failed")
	}

	nums := strings.Split(s, ",")
	for _, n := range nums {
		i, err := strconv.Atoi(strings.TrimSpace(n))
		if err != nil {
			return err
		}
		*p = append(*p, i)
	}
	return nil
}

func (p *ParseIPs) String() string {
	if p == nil {
		return ""
	}
	var builder strings.Builder
	for i, ipaddr := range *p {
		if i > 0 {
			builder.WriteRune(',')
		}
		builder.WriteString(ipaddr.String())
	}
	return builder.String()
}

// Set implements the flag.Value interface.
func (p *ParseIPs) Set(s string) error {
	if s == "" {
		return fmt.Errorf("IP address parsing failed")
	}

	for _, v := range strings.Split(s, ",") {
		if start, end, ok := parseRange(v); ok {
			ips := amassnet.RangeHosts(start, end)
			if len(ips) == 0 {
				return fmt.Errorf("%s is not a valid IP address or range", v)
			}
			for _, ip := range ips {
				*p = append(*p, ip)
			}
			continue
		} else if ip := net.ParseIP(v); ip != nil {
			*p = append(*p, ip)
			continue
		} else {
			return fmt.Errorf("%s is not a valid IP address or range", v)
		}
	}
	return nil
}

func parseRange(s string) (start net.IP, end net.IP, ok bool) {
	twoIPs := strings.Split(s, "-")
	if len(twoIPs) != 2 {
		return
	}
	start = net.ParseIP(twoIPs[0])
	if start == nil {
		return
	}
	end = net.ParseIP(twoIPs[1])
	if end == nil {
		num, err := strconv.Atoi(twoIPs[1])
		if err != nil || math.MaxUint8 < num {
			return
		}
		end = make(net.IP, len(start))
		copy(end, start)
		end[len(end)-1] = byte(num)
	}
	ok = true
	return
}

func (p *ParseCIDRs) String() string {
	if p == nil {
		return ""
	}

	var builder strings.Builder
	for i, ipnet := range *p {
		if i > 0 {
			builder.WriteRune(',')
		}
		builder.WriteString(ipnet.String())
	}
	return builder.String()
}

// Set implements the flag.Value interface.
func (p *ParseCIDRs) Set(s string) error {
	if s == "" {
		return fmt.Errorf("%s is not a valid CIDR", s)
	}

	cidrs := strings.Split(s, ",")
	for _, cidr := range cidrs {
		_, ipnet, err := net.ParseCIDR(cidr)
		if err != nil {
			return fmt.Errorf("failed to parse %s as a CIDR", cidr)
		}

		*p = append(*p, ipnet)
	}
	return nil
}

func (p *ParseASNs) String() string {
	if p == nil {
		return ""
	}
	var builder strings.Builder
	for i, n := range *p {
		if i > 0 {
			builder.WriteRune(',')
		}
		builder.WriteString(strconv.Itoa(n))
	}
	return builder.String()
}

// Set implements the flag.Value interface.
func (p *ParseASNs) Set(s string) error {
	if s == "" {
		return fmt.Errorf("ASN parsing failed")
	}

	asns := strings.Split(s, ",")
	for _, asn := range asns {
		i, err := strconv.Atoi(strings.TrimPrefix(strings.TrimSpace(asn), "AS"))
		if err != nil {
			return err
		}
		*p = append(*p, i)
	}
	return nil
}
<|endoftext|>


<commit_before>package core

import (
	"context"
	"sync"

	"v2ray.com/core/common"
	"v2ray.com/core/common/uuid"
)

// Server is an instance of V2Ray. At any time, there must be at most one Server instance running.
// Deprecated. Use Instance directly.
type Server interface {
	common.Runnable
}

// Feature is the interface for V2Ray features. All features must implement this interface.
// All existing features have an implementation in app directory. These features can be replaced by third-party ones.
type Feature interface {
	common.Runnable
}

// Instance combines all functionalities in V2Ray.
type Instance struct {
	dnsClient     syncDNSClient
	policyManager syncPolicyManager
	dispatcher    syncDispatcher
	router        syncRouter
	ihm           syncInboundHandlerManager
	ohm           syncOutboundHandlerManager
	clock         syncClock
	cmd           syncCommander

	access   sync.Mutex
	features []Feature
	id       uuid.UUID
	running  bool
}

// New returns a new V2Ray instance based on given configuration.
// The instance is not started at this point.
// To make sure V2Ray instance works properly, the config must contain one Dispatcher, one InboundHandlerManager and one OutboundHandlerManager. Other features are optional.
func New(config *Config) (*Instance, error) {
	var server = &Instance{
		id: uuid.New(),
	}

	if err := config.Transport.Apply(); err != nil {
		return nil, err
	}

	for _, appSettings := range config.App {
		settings, err := appSettings.GetInstance()
		if err != nil {
			return nil, err
		}
		if _, err := server.CreateObject(settings); err != nil {
			return nil, err
		}
	}

	for _, inbound := range config.Inbound {
		rawHandler, err := server.CreateObject(inbound)
		if err != nil {
			return nil, err
		}
		handler, ok := rawHandler.(InboundHandler)
		if !ok {
			return nil, newError("not an InboundHandler")
		}
		if err := server.InboundHandlerManager().AddHandler(context.Background(), handler); err != nil {
			return nil, err
		}
	}

	for _, outbound := range config.Outbound {
		rawHandler, err := server.CreateObject(outbound)
		if err != nil {
			return nil, err
		}
		handler, ok := rawHandler.(OutboundHandler)
		if !ok {
			return nil, newError("not an OutboundHandler")
		}
		if err := server.OutboundHandlerManager().AddHandler(context.Background(), handler); err != nil {
			return nil, err
		}
	}

	return server, nil
}

func (s *Instance) CreateObject(config interface{}) (interface{}, error) {
	ctx := context.WithValue(context.Background(), v2rayKey, s)
	return common.CreateObject(ctx, config)
}

// ID returns an unique ID for this V2Ray instance.
func (s *Instance) ID() uuid.UUID {
	return s.id
}

// Close shutdown the V2Ray instance.
func (s *Instance) Close() error {
	s.access.Lock()
	defer s.access.Unlock()

	s.running = false
	for _, f := range s.features {
		f.Close()
	}

	return nil
}

// Start starts the V2Ray instance, including all registered features. When Start returns error, the state of the instance is unknown.
func (s *Instance) Start() error {
	s.access.Lock()
	defer s.access.Unlock()

	s.running = true
	for _, f := range s.features {
		if err := f.Start(); err != nil {
			return err
		}
	}

	newError("V2Ray started").AtWarning().WriteToLog()

	return nil
}

// RegisterFeature registers the given feature into V2Ray.
// If feature is one of the following types, the corressponding feature in this Instance
// will be replaced: DNSClient, PolicyManager, Router, Dispatcher, InboundHandlerManager, OutboundHandlerManager.
func (s *Instance) RegisterFeature(feature interface{}, instance Feature) error {
	switch feature.(type) {
	case DNSClient, *DNSClient:
		s.dnsClient.Set(instance.(DNSClient))
	case PolicyManager, *PolicyManager:
		s.policyManager.Set(instance.(PolicyManager))
	case Router, *Router:
		s.router.Set(instance.(Router))
	case Dispatcher, *Dispatcher:
		s.dispatcher.Set(instance.(Dispatcher))
	case InboundHandlerManager, *InboundHandlerManager:
		s.ihm.Set(instance.(InboundHandlerManager))
	case OutboundHandlerManager, *OutboundHandlerManager:
		s.ohm.Set(instance.(OutboundHandlerManager))
	case Clock, *Clock:
		s.clock.Set(instance.(Clock))
	case Commander, *Commander:
		s.cmd.Set(instance.(Commander))
	}
	s.access.Lock()
	defer s.access.Unlock()

	s.features = append(s.features, instance)
	if s.running {
		return instance.Start()
	}
	return nil
}

// DNSClient returns the DNSClient used by this Instance. The returned DNSClient is always functional.
func (s *Instance) DNSClient() DNSClient {
	return &(s.dnsClient)
}

// PolicyManager returns the PolicyManager used by this Instance. The returned PolicyManager is always functional.
func (s *Instance) PolicyManager() PolicyManager {
	return &(s.policyManager)
}

// Router returns the Router used by this Instance. The returned Router is always functional.
func (s *Instance) Router() Router {
	return &(s.router)
}

// Dispatcher returns the Dispatcher used by this Instance. If Dispatcher was not registered before, the returned value doesn't work, although it is not nil.
func (s *Instance) Dispatcher() Dispatcher {
	return &(s.dispatcher)
}

// InboundHandlerManager returns the InboundHandlerManager used by this Instance. If InboundHandlerManager was not registered before, the returned value doesn't work.
func (s *Instance) InboundHandlerManager() InboundHandlerManager {
	return &(s.ihm)
}

// OutboundHandlerManager returns the OutboundHandlerManager used by this Instance. If OutboundHandlerManager was not registered before, the returned value doesn't work.
func (s *Instance) OutboundHandlerManager() OutboundHandlerManager {
	return &(s.ohm)
}

// Clock returns the Clock used by this Instance. The returned Clock is always functional.
func (s *Instance) Clock() Clock {
	return &(s.clock)
}

// Commander returns the Commander used by this Instance. The returned Commander is always functional.
func (s *Instance) Commander() Commander {
	return &(s.cmd)
}
<commit_msg>comments<commit_after>package core

import (
	"context"
	"sync"

	"v2ray.com/core/common"
	"v2ray.com/core/common/uuid"
)

// Server is an instance of V2Ray. At any time, there must be at most one Server instance running.
// Deprecated. Use Instance directly.
type Server interface {
	common.Runnable
}

// Feature is the interface for V2Ray features. All features must implement this interface.
// All existing features have an implementation in app directory. These features can be replaced by third-party ones.
type Feature interface {
	common.Runnable
}

// Instance combines all functionalities in V2Ray.
type Instance struct {
	dnsClient     syncDNSClient
	policyManager syncPolicyManager
	dispatcher    syncDispatcher
	router        syncRouter
	ihm           syncInboundHandlerManager
	ohm           syncOutboundHandlerManager
	clock         syncClock
	cmd           syncCommander

	access   sync.Mutex
	features []Feature
	id       uuid.UUID
	running  bool
}

// New returns a new V2Ray instance based on given configuration.
// The instance is not started at this point.
// To make sure V2Ray instance works properly, the config must contain one Dispatcher, one InboundHandlerManager and one OutboundHandlerManager. Other features are optional.
func New(config *Config) (*Instance, error) {
	var server = &Instance{
		id: uuid.New(),
	}

	if err := config.Transport.Apply(); err != nil {
		return nil, err
	}

	for _, appSettings := range config.App {
		settings, err := appSettings.GetInstance()
		if err != nil {
			return nil, err
		}
		if _, err := server.CreateObject(settings); err != nil {
			return nil, err
		}
	}

	for _, inbound := range config.Inbound {
		rawHandler, err := server.CreateObject(inbound)
		if err != nil {
			return nil, err
		}
		handler, ok := rawHandler.(InboundHandler)
		if !ok {
			return nil, newError("not an InboundHandler")
		}
		if err := server.InboundHandlerManager().AddHandler(context.Background(), handler); err != nil {
			return nil, err
		}
	}

	for _, outbound := range config.Outbound {
		rawHandler, err := server.CreateObject(outbound)
		if err != nil {
			return nil, err
		}
		handler, ok := rawHandler.(OutboundHandler)
		if !ok {
			return nil, newError("not an OutboundHandler")
		}
		if err := server.OutboundHandlerManager().AddHandler(context.Background(), handler); err != nil {
			return nil, err
		}
	}

	return server, nil
}

func (s *Instance) CreateObject(config interface{}) (interface{}, error) {
	ctx := context.WithValue(context.Background(), v2rayKey, s)
	return common.CreateObject(ctx, config)
}

// ID returns an unique ID for this V2Ray instance.
func (s *Instance) ID() uuid.UUID {
	return s.id
}

// Close shutdown the V2Ray instance.
func (s *Instance) Close() error {
	s.access.Lock()
	defer s.access.Unlock()

	s.running = false
	for _, f := range s.features {
		f.Close()
	}

	return nil
}

// Start starts the V2Ray instance, including all registered features. When Start returns error, the state of the instance is unknown.
// A V2Ray instance can be started only once. Upon closing, the instance is not guaranteed to start again.
func (s *Instance) Start() error {
	s.access.Lock()
	defer s.access.Unlock()

	s.running = true
	for _, f := range s.features {
		if err := f.Start(); err != nil {
			return err
		}
	}

	newError("V2Ray started").AtWarning().WriteToLog()

	return nil
}

// RegisterFeature registers the given feature into V2Ray.
// If feature is one of the following types, the corressponding feature in this Instance
// will be replaced: DNSClient, PolicyManager, Router, Dispatcher, InboundHandlerManager, OutboundHandlerManager.
func (s *Instance) RegisterFeature(feature interface{}, instance Feature) error {
	switch feature.(type) {
	case DNSClient, *DNSClient:
		s.dnsClient.Set(instance.(DNSClient))
	case PolicyManager, *PolicyManager:
		s.policyManager.Set(instance.(PolicyManager))
	case Router, *Router:
		s.router.Set(instance.(Router))
	case Dispatcher, *Dispatcher:
		s.dispatcher.Set(instance.(Dispatcher))
	case InboundHandlerManager, *InboundHandlerManager:
		s.ihm.Set(instance.(InboundHandlerManager))
	case OutboundHandlerManager, *OutboundHandlerManager:
		s.ohm.Set(instance.(OutboundHandlerManager))
	case Clock, *Clock:
		s.clock.Set(instance.(Clock))
	case Commander, *Commander:
		s.cmd.Set(instance.(Commander))
	}
	s.access.Lock()
	defer s.access.Unlock()

	s.features = append(s.features, instance)
	if s.running {
		return instance.Start()
	}
	return nil
}

// DNSClient returns the DNSClient used by this Instance. The returned DNSClient is always functional.
func (s *Instance) DNSClient() DNSClient {
	return &(s.dnsClient)
}

// PolicyManager returns the PolicyManager used by this Instance. The returned PolicyManager is always functional.
func (s *Instance) PolicyManager() PolicyManager {
	return &(s.policyManager)
}

// Router returns the Router used by this Instance. The returned Router is always functional.
func (s *Instance) Router() Router {
	return &(s.router)
}

// Dispatcher returns the Dispatcher used by this Instance. If Dispatcher was not registered before, the returned value doesn't work, although it is not nil.
func (s *Instance) Dispatcher() Dispatcher {
	return &(s.dispatcher)
}

// InboundHandlerManager returns the InboundHandlerManager used by this Instance. If InboundHandlerManager was not registered before, the returned value doesn't work.
func (s *Instance) InboundHandlerManager() InboundHandlerManager {
	return &(s.ihm)
}

// OutboundHandlerManager returns the OutboundHandlerManager used by this Instance. If OutboundHandlerManager was not registered before, the returned value doesn't work.
func (s *Instance) OutboundHandlerManager() OutboundHandlerManager {
	return &(s.ohm)
}

// Clock returns the Clock used by this Instance. The returned Clock is always functional.
func (s *Instance) Clock() Clock {
	return &(s.clock)
}

// Commander returns the Commander used by this Instance. The returned Commander is always functional.
func (s *Instance) Commander() Commander {
	return &(s.cmd)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
)

// $ glacier us-east-1 vault create <name>
// $ glacier us-east-1 vault delete <name>
// $ glacier us-east-1 vault describe <name>
// $ glacier us-east-1 vault list
// $ glacier us-east-1 vault notification set <name> [options]
// $ glacier us-east-1 vault notification get <name>
// $ glacier us-east-1 vault notification delete <name>

func vault() {
	switch flag.Arg(2) {
	case "list":
		_, vaults, err := connection.ListVaults(0, "")
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		fmt.Printf("%+v\n", vaults)
	default:
		fmt.Println("unknown vault command:", flag.Arg(2))
	}
}
<commit_msg>Added calls to glacier functions.<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
)

// $ glacier us-east-1 vault create <name>
// $ glacier us-east-1 vault delete <name>
// $ glacier us-east-1 vault describe <name>
// $ glacier us-east-1 vault list
// $ glacier us-east-1 vault notification set <name> [options]
// $ glacier us-east-1 vault notification get <name>
// $ glacier us-east-1 vault notification delete <name>

func vault() {
	switch flag.Arg(2) {
	case "create":
		err := connection.CreateVault(flag.Arg(3))
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	case "delete":
		err := connection.DeleteVault(flag.Arg(3))
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	case "describe":
		vault, err := connection.DescribeVault(flag.Arg(3))
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		fmt.Printf("%+v\n", vault)
	case "list":
		_, vaults, err := connection.ListVaults(0, "")
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		fmt.Printf("%+v\n", vaults)
	case "notification":
		if flag.NArg() < 5 {
			fmt.Println("no notification command")
			os.Exit(1)
		}
		switch flag.Arg(3) {
		case "set":
		case "get":
		case "delete":
		default:
			fmt.Println("unknown notification command:", flag.Arg(3))
			os.Exit(1)
		}
	default:
		fmt.Println("unknown vault command:", flag.Arg(2))
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package vinxi

import (
	"net/http"

	"gopkg.in/vinxi/vinxi.v0/context"
	"gopkg.in/vinxi/vinxi.v0/forward"
	"gopkg.in/vinxi/vinxi.v0/layer"
	"gopkg.in/vinxi/vinxi.v0/mux"
	"gopkg.in/vinxi/vinxi.v0/router"
)

// DefaultForwarder stores the default http.Handler to be used to forward the traffic.
// By default the proxy will reply with 502 Bad Gateway if no custom forwarder is defined.
var DefaultForwarder, _ = forward.New(forward.PassHostHeader(true))

// Middleware defines the required interface implemented
// by public middleware capable entities in the vinxi ecosystem.
type Middleware interface {
	// Use is used to register one or multiple middleware handlers.
	Use(...interface{}) Middleware
	// UsePhase is used to register one or multiple middleware
	// handlers for a specific middleware phase.
	UsePhase(string, ...interface{}) Middleware
	// UseFinalHandler is used to register the final request handler
	// usually to define the error or forward handlers.
	UseFinalHandler(http.Handler) Middleware
	// SetParent allows hierarchical middleware inheritance.
	SetParent(layer.Middleware)
}

// Vinxi represents the vinxi proxy layer.
type Vinxi struct {
	// Layer stores the proxy level middleware layer.
	Layer *layer.Layer
	// Router stores the built-in router.
	Router *router.Router
}

// New creates a new vinxi proxy layer with default fields.
func New() *Vinxi {
	v := &Vinxi{Layer: layer.New(), Router: router.New()}
	// Bind router with parent layer
	v.Router.SetParent(v.Layer)
	// Register the router in the middleware tail (this should change in the future)
	v.Layer.UsePriority("request", layer.Tail, v.Router)
	// Use the default forwarder as final middleware handler
	v.UseFinalHandler(DefaultForwarder)
	return v
}

// Get will register a pattern for GET requests.
// It also registers pat for HEAD requests. If this needs to be overridden, use
// Head before Get with pat.
func (v *Vinxi) Get(path string) *router.Route {
	return v.Route("GET", path)
}

// Post will register a pattern for POST requests.
func (v *Vinxi) Post(path string) *router.Route {
	return v.Route("POST", path)
}

// Put will register a pattern for PUT requests.
func (v *Vinxi) Put(path string) *router.Route {
	return v.Route("PUT", path)
}

// Delete will register a pattern for DELETE requests.
func (v *Vinxi) Delete(path string) *router.Route {
	return v.Route("DELETE", path)
}

// Options will register a pattern for OPTIONS requests.
func (v *Vinxi) Options(path string) *router.Route {
	return v.Route("OPTIONS", path)
}

// Patch will register a pattern for PATCH requests.
func (v *Vinxi) Patch(path string) *router.Route {
	return v.Route("PATCH", path)
}

// All will register a pattern for any HTTP method.
func (v *Vinxi) All(path string) *router.Route {
	return v.Route("*", path)
}

// Route will register a new route for the given pattern and HTTP method.
func (v *Vinxi) Route(method, path string) *router.Route {
	return v.Router.Route(method, path)
}

// Forward defines the default URL to forward incoming traffic.
func (v *Vinxi) Forward(uri string) *Vinxi {
	return v.UseFinalHandler(http.HandlerFunc(forward.To(uri)))
}

// Use attaches a new middleware handler for incoming HTTP traffic.
func (v *Vinxi) Use(handler ...interface{}) *Vinxi {
	v.Layer.Use(layer.RequestPhase, handler...)
	return v
}

// UsePhase attaches a new middleware handler to a specific phase.
func (v *Vinxi) UsePhase(phase string, handler ...interface{}) *Vinxi {
	v.Layer.Use(phase, handler...)
	return v
}

// UseFinalHandler uses a new middleware handler function as final handler.
func (v *Vinxi) UseFinalHandler(fn http.Handler) *Vinxi {
	v.Layer.UseFinalHandler(fn)
	return v
}

// SetForwader sets the default final traffic forwarder.
func (v *Vinxi) SetForwader(fn http.Handler) *Vinxi {
	v.Layer.UseFinalHandler(fn)
	return v
}

// Flush flushes all the middleware stack.
func (v *Vinxi) Flush() {
	v.Layer.Flush()
}

// Mux creates a new multiplexer based on the given matcher functions.
func (v *Vinxi) Mux(matchers ...mux.Matcher) *mux.Mux {
	m := mux.New()
	// Register matchers
	m.If(matchers...)
	// Bind multiplexer to the current vinxi layer
	v.Use(m)
	return m
}

// SetParent sets a parent middleware layer.
func (v *Vinxi) SetParent(parent layer.Middleware) {
	v.Layer.SetParent(parent)
}

// NewServer creates a new http.Server.
func (v *Vinxi) NewServer(opts ServerOptions) *Server {
	srv := NewServer(opts)
	v.BindServer(srv.Server)
	return srv
}

// ListenAndServe creates a new http.Server and starts listening
// on the network based on the given server options.
func (v *Vinxi) ListenAndServe(opts ServerOptions) (*Server, error) {
	srv := NewServer(opts)
	v.BindServer(srv.Server)
	return srv, srv.Listen()
}

// BindServer binds the vinxi HTTP handler to the given http.Server.
func (v *Vinxi) BindServer(server *http.Server) {
	server.Handler = v
}

// ServeHTTP implements the required http.Handler interface to handle incoming traffic.
func (v *Vinxi) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Expose original incoming request host
	context.Set(r, "vinxi.host", r.Host)
	// Define target URL
	r.URL.Host = r.Host
	// Run the incoming request middleware layer
	v.Layer.Run("request", w, r, nil)
}
<commit_msg>refactor(plugin): remove Register method<commit_after>package vinxi

import (
	"net/http"

	"gopkg.in/vinxi/vinxi.v0/context"
	"gopkg.in/vinxi/vinxi.v0/forward"
	"gopkg.in/vinxi/vinxi.v0/layer"
	"gopkg.in/vinxi/vinxi.v0/mux"
	"gopkg.in/vinxi/vinxi.v0/router"
)

// DefaultForwarder stores the default http.Handler to be used to forward the traffic.
// By default the proxy will reply with 502 Bad Gateway if no custom forwarder is defined.
var DefaultForwarder, _ = forward.New(forward.PassHostHeader(true))

// Middleware defines the required interface implemented
// by public middleware capable entities in the vinxi ecosystem.
type Middleware interface {
	// Use is used to register one or multiple middleware handlers.
	Use(...interface{}) Middleware
	// UsePhase is used to register one or multiple middleware
	// handlers for a specific middleware phase.
	UsePhase(string, ...interface{}) Middleware
	// UseFinalHandler is used to register the final request handler
	// usually to define the error or forward handlers.
	UseFinalHandler(http.Handler) Middleware
	// SetParent allows hierarchical middleware inheritance.
	SetParent(layer.Middleware)
}

// Vinxi represents the vinxi proxy layer.
type Vinxi struct {
	// Layer stores the proxy level middleware layer.
	Layer *layer.Layer
	// Router stores the built-in router.
	Router *router.Router
}

// New creates a new vinxi proxy layer with default fields.
func New() *Vinxi {
	v := &Vinxi{Layer: layer.New(), Router: router.New()}
	// Bind router with parent layer
	v.Router.SetParent(v.Layer)
	// Register the router in the middleware tail (this should change in the future)
	v.Layer.UsePriority(layer.RequestPhase, layer.Tail, v.Router)
	// Use the default forwarder as final middleware handler
	v.UseFinalHandler(DefaultForwarder)
	return v
}

// Get will register a pattern for GET requests.
// It also registers pat for HEAD requests. If this needs to be overridden, use
// Head before Get with pat.
func (v *Vinxi) Get(path string) *router.Route {
	return v.Route("GET", path)
}

// Post will register a pattern for POST requests.
func (v *Vinxi) Post(path string) *router.Route {
	return v.Route("POST", path)
}

// Put will register a pattern for PUT requests.
func (v *Vinxi) Put(path string) *router.Route {
	return v.Route("PUT", path)
}

// Delete will register a pattern for DELETE requests.
func (v *Vinxi) Delete(path string) *router.Route {
	return v.Route("DELETE", path)
}

// Options will register a pattern for OPTIONS requests.
func (v *Vinxi) Options(path string) *router.Route {
	return v.Route("OPTIONS", path)
}

// Patch will register a pattern for PATCH requests.
func (v *Vinxi) Patch(path string) *router.Route {
	return v.Route("PATCH", path)
}

// All will register a pattern for any HTTP method.
func (v *Vinxi) All(path string) *router.Route {
	return v.Route("*", path)
}

// Route will register a new route for the given pattern and HTTP method.
func (v *Vinxi) Route(method, path string) *router.Route {
	return v.Router.Route(method, path)
}

// Forward defines the default URL to forward incoming traffic.
func (v *Vinxi) Forward(uri string) *Vinxi {
	return v.UseFinalHandler(http.HandlerFunc(forward.To(uri)))
}

// Use attaches a new middleware handler for incoming HTTP traffic.
func (v *Vinxi) Use(handler ...interface{}) *Vinxi {
	v.Layer.Use(layer.RequestPhase, handler...)
	return v
}

// UsePhase attaches a new middleware handler to a specific phase.
func (v *Vinxi) UsePhase(phase string, handler ...interface{}) *Vinxi {
	v.Layer.Use(phase, handler...)
	return v
}

// UseFinalHandler uses a new middleware handler function as final handler.
func (v *Vinxi) UseFinalHandler(fn http.Handler) *Vinxi {
	v.Layer.UseFinalHandler(fn)
	return v
}

// SetForwader sets the default final traffic forwarder.
func (v *Vinxi) SetForwader(fn http.Handler) *Vinxi {
	v.Layer.UseFinalHandler(fn)
	return v
}

// Flush flushes all the middleware stack.
func (v *Vinxi) Flush() {
	v.Layer.Flush()
}

// Mux creates a new multiplexer based on the given matcher functions.
func (v *Vinxi) Mux(matchers ...mux.Matcher) *mux.Mux {
	m := mux.New()
	// Register matchers
	m.If(matchers...)
	// Bind multiplexer to the current vinxi layer
	v.Use(m)
	return m
}

// SetParent sets a parent middleware layer.
func (v *Vinxi) SetParent(parent layer.Middleware) {
	v.Layer.SetParent(parent)
}

// NewServer creates a new http.Server.
func (v *Vinxi) NewServer(opts ServerOptions) *Server {
	srv := NewServer(opts)
	v.BindServer(srv.Server)
	return srv
}

// ListenAndServe creates a new http.Server and starts listening
// on the network based on the given server options.
func (v *Vinxi) ListenAndServe(opts ServerOptions) (*Server, error) {
	srv := NewServer(opts)
	v.BindServer(srv.Server)
	return srv, srv.Listen()
}

// BindServer binds the vinxi HTTP handler to the given http.Server.
func (v *Vinxi) BindServer(server *http.Server) {
	server.Handler = v
}

// ServeHTTP implements the required http.Handler interface to handle incoming traffic.
func (v *Vinxi) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Expose original incoming request host
	context.Set(r, "vinxi.host", r.Host)
	// Define target URL
	r.URL.Host = r.Host
	// Run the incoming request middleware layer
	v.Layer.Run("request", w, r, nil)
}
<|endoftext|>


<commit_before>package fauxgl

type Voxel struct {
	X, Y, Z int
	Color   Color
}

type voxelAxis int

const (
	_ voxelAxis = iota
	voxelX
	voxelY
	voxelZ
)

type voxelNormal struct {
	Axis voxelAxis
	Sign int
}

var (
	voxelPosX = voxelNormal{voxelX, 1}
	voxelNegX = voxelNormal{voxelX, -1}
	voxelPosY = voxelNormal{voxelY, 1}
	voxelNegY = voxelNormal{voxelY, -1}
	voxelPosZ = voxelNormal{voxelZ, 1}
	voxelNegZ = voxelNormal{voxelZ, -1}
)

type voxelPlane struct {
	Normal   voxelNormal
	Position int
	Color    Color
}

type voxelFace struct {
	I0, J0 int
	I1, J1 int
}

func NewVoxelMesh(voxels []Voxel) *Mesh {
	type key struct {
		X, Y, Z int
	}

	// create lookup table
	lookup := make(map[key]bool)
	for _, v := range voxels {
		lookup[key{v.X, v.Y, v.Z}] = true
	}

	// find exposed faces
	planeFaces := make(map[voxelPlane][]voxelFace)
	for _, v := range voxels {
		if !lookup[key{v.X + 1, v.Y, v.Z}] {
			plane := voxelPlane{voxelPosX, v.X, v.Color}
			face := voxelFace{v.Y, v.Z, v.Y, v.Z}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X - 1, v.Y, v.Z}] {
			plane := voxelPlane{voxelNegX, v.X, v.Color}
			face := voxelFace{v.Y, v.Z, v.Y, v.Z}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X, v.Y + 1, v.Z}] {
			plane := voxelPlane{voxelPosY, v.Y, v.Color}
			face := voxelFace{v.X, v.Z, v.X, v.Z}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X, v.Y - 1, v.Z}] {
			plane := voxelPlane{voxelNegY, v.Y, v.Color}
			face := voxelFace{v.X, v.Z, v.X, v.Z}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X, v.Y, v.Z + 1}] {
			plane := voxelPlane{voxelPosZ, v.Z, v.Color}
			face := voxelFace{v.X, v.Y, v.X, v.Y}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X, v.Y, v.Z - 1}] {
			plane := voxelPlane{voxelNegZ, v.Z, v.Color}
			face := voxelFace{v.X, v.Y, v.X, v.Y}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
	}

	var triangles []*Triangle
	var lines []*Line

	// find large rectangles, triangulate and outline
	for plane, faces := range planeFaces {
		faces = combineVoxelFaces(faces)
		lines = append(lines, outlineVoxelFaces(plane, faces)...)
		triangles = append(triangles, triangulateVoxelFaces(plane, faces)...)
	}

	return NewMesh(triangles, lines)
}

func combineVoxelFaces(faces []voxelFace) []voxelFace {
	// determine bounding box
	i0 := faces[0].I0
	j0 := faces[0].J0
	i1 := faces[0].I1
	j1 := faces[0].J1
	for _, f := range faces {
		if f.I0 < i0 {
			i0 = f.I0
		}
		if f.J0 < j0 {
			j0 = f.J0
		}
		if f.I1 > i1 {
			i1 = f.I1
		}
		if f.J1 > j1 {
			j1 = f.J1
		}
	}
	// create arrays
	nj := j1 - j0 + 1
	ni := i1 - i0 + 1
	a := make([][]int, nj)
	w := make([][]int, nj)
	h := make([][]int, nj)
	for j := range a {
		a[j] = make([]int, ni)
		w[j] = make([]int, ni)
		h[j] = make([]int, ni)
	}
	// populate array
	count := 0
	for _, f := range faces {
		for j := f.J0; j <= f.J1; j++ {
			for i := f.I0; i <= f.I1; i++ {
				a[j-j0][i-i0] = 1
				count++
			}
		}
	}
	// find rectangles
	var result []voxelFace
	for count > 0 {
		var maxArea int
		var maxFace voxelFace
		for j := 0; j < nj; j++ {
			for i := 0; i < ni; i++ {
				if a[j][i] == 0 {
					continue
				}
				if j == 0 {
					h[j][i] = 1
				} else {
					h[j][i] = h[j-1][i] + 1
				}
				if i == 0 {
					w[j][i] = 1
				} else {
					w[j][i] = w[j][i-1] + 1
				}
				minw := w[j][i]
				for dh := 0; dh < h[j][i]; dh++ {
					if w[j-dh][i] < minw {
						minw = w[j-dh][i]
					}
					area := (dh + 1) * minw
					if area > maxArea {
						maxArea = area
						maxFace = voxelFace{
							i0 + i - minw + 1, j0 + j - dh, i0 + i, j0 + j}
					}
				}
			}
		}
		result = append(result, maxFace)
		for j := maxFace.J0; j <= maxFace.J1; j++ {
			for i := maxFace.I0; i <= maxFace.I1; i++ {
				a[j-j0][i-i0] = 0
				count--
			}
		}
		for j := 0; j < nj; j++ {
			for i := 0; i < ni; i++ {
				w[j][i] = 0
				h[j][i] = 0
			}
		}
	}
	return result
}

func triangulateVoxelFaces(plane voxelPlane, faces []voxelFace) []*Triangle {
	triangles := make([]*Triangle, len(faces)*2)
	k := float64(plane.Position) + float64(plane.Normal.Sign)*0.5
	for i, face := range faces {
		i0 := float64(face.I0) - 0.5
		j0 := float64(face.J0) - 0.5
		i1 := float64(face.I1) + 0.5
		j1 := float64(face.J1) + 0.5
		var p1, p2, p3, p4 Vector
		switch plane.Normal.Axis {
		case voxelX:
			p1 = Vector{k, i0, j0}
			p2 = Vector{k, i1, j0}
			p3 = Vector{k, i1, j1}
			p4 = Vector{k, i0, j1}
		case voxelY:
			p1 = Vector{i0, k, j1}
			p2 = Vector{i1, k, j1}
			p3 = Vector{i1, k, j0}
			p4 = Vector{i0, k, j0}
		case voxelZ:
			p1 = Vector{i0, j0, k}
			p2 = Vector{i1, j0, k}
			p3 = Vector{i1, j1, k}
			p4 = Vector{i0, j1, k}
		}
		if plane.Normal.Sign < 0 {
			p1, p2, p3, p4 = p4, p3, p2, p1
		}
		t1 := NewTriangleForPoints(p1, p2, p3)
		t2 := NewTriangleForPoints(p1, p3, p4)
		t1.V1.Color = plane.Color
		t1.V2.Color = plane.Color
		t1.V3.Color = plane.Color
		t2.V1.Color = plane.Color
		t2.V2.Color = plane.Color
		t2.V3.Color = plane.Color
		triangles[i*2+0] = t1
		triangles[i*2+1] = t2
	}
	return triangles
}

func outlineVoxelFaces(plane voxelPlane, faces []voxelFace) []*Line {
	// determine bounding box
	i0 := faces[0].I0
	j0 := faces[0].J0
	i1 := faces[0].I1
	j1 := faces[0].J1
	for _, f := range faces {
		if f.I0 < i0 {
			i0 = f.I0
		}
		if f.J0 < j0 {
			j0 = f.J0
		}
		if f.I1 > i1 {
			i1 = f.I1
		}
		if f.J1 > j1 {
			j1 = f.J1
		}
	}
	// padding
	i0--
	j0--
	i1++
	j1++
	// create array
	nj := j1 - j0 + 1
	ni := i1 - i0 + 1
	a := make([][]bool, nj)
	for j := range a {
		a[j] = make([]bool, ni)
	}
	// populate array
	for _, f := range faces {
		for j := f.J0; j <= f.J1; j++ {
			for i := f.I0; i <= f.I1; i++ {
				a[j-j0][i-i0] = true
			}
		}
	}
	var lines []*Line
	for sign := -1; sign <= 1; sign += 2 {
		// find "horizontal" lines
		for j := 1; j < nj-1; j++ {
			start := -1
			for i := 0; i < ni; i++ {
				if a[j][i] && !a[j+sign][i] {
					if start < 0 {
						start = i
					}
				} else if start >= 0 {
					end := i - 1
					ai := float64(i0+start) - 0.5
					bi := float64(i0+end) + 0.5
					jj := float64(j0+j) + 0.5*float64(sign)
					line := createVoxelOutline(plane, ai, jj, bi, jj)
					lines = append(lines, line)
					start = -1
				}
			}

		}
		// find "vertical" lines
		for i := 1; i < ni-1; i++ {
			start := -1
			for j := 0; j < nj; j++ {
				if a[j][i] && !a[j][i+sign] {
					if start < 0 {
						start = j
					}
				} else if start >= 0 {
					end := j - 1
					aj := float64(j0+start) - 0.5
					bj := float64(j0+end) + 0.5
					ii := float64(i0+i) + 0.5*float64(sign)
					line := createVoxelOutline(plane, ii, aj, ii, bj)
					lines = append(lines, line)
					start = -1
				}
			}
		}
	}
	return lines
}

func createVoxelOutline(plane voxelPlane, i0, j0, i1, j1 float64) *Line {
	k := float64(plane.Position) + float64(plane.Normal.Sign)*0.5
	var p1, p2 Vector
	switch plane.Normal.Axis {
	case voxelX:
		p1 = Vector{k, i0, j0}
		p2 = Vector{k, i1, j1}
	case voxelY:
		p1 = Vector{i0, k, j0}
		p2 = Vector{i1, k, j1}
	case voxelZ:
		p1 = Vector{i0, j0, k}
		p2 = Vector{i1, j1, k}
	}
	return NewLineForPoints(p1, p2)
}
<commit_msg>remove t-junctions<commit_after>package fauxgl

type Voxel struct {
	X, Y, Z int
	Color   Color
}

type voxelAxis int

const (
	_ voxelAxis = iota
	voxelX
	voxelY
	voxelZ
)

type voxelNormal struct {
	Axis voxelAxis
	Sign int
}

var (
	voxelPosX = voxelNormal{voxelX, 1}
	voxelNegX = voxelNormal{voxelX, -1}
	voxelPosY = voxelNormal{voxelY, 1}
	voxelNegY = voxelNormal{voxelY, -1}
	voxelPosZ = voxelNormal{voxelZ, 1}
	voxelNegZ = voxelNormal{voxelZ, -1}
)

type voxelPlane struct {
	Normal   voxelNormal
	Position int
	Color    Color
}

type voxelFace struct {
	I0, J0 int
	I1, J1 int
}

func NewVoxelMesh(voxels []Voxel) *Mesh {
	type key struct {
		X, Y, Z int
	}

	// create lookup table
	lookup := make(map[key]bool)
	for _, v := range voxels {
		lookup[key{v.X, v.Y, v.Z}] = true
	}

	// find exposed faces
	planeFaces := make(map[voxelPlane][]voxelFace)
	for _, v := range voxels {
		if !lookup[key{v.X + 1, v.Y, v.Z}] {
			plane := voxelPlane{voxelPosX, v.X, v.Color}
			face := voxelFace{v.Y, v.Z, v.Y, v.Z}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X - 1, v.Y, v.Z}] {
			plane := voxelPlane{voxelNegX, v.X, v.Color}
			face := voxelFace{v.Y, v.Z, v.Y, v.Z}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X, v.Y + 1, v.Z}] {
			plane := voxelPlane{voxelPosY, v.Y, v.Color}
			face := voxelFace{v.X, v.Z, v.X, v.Z}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X, v.Y - 1, v.Z}] {
			plane := voxelPlane{voxelNegY, v.Y, v.Color}
			face := voxelFace{v.X, v.Z, v.X, v.Z}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X, v.Y, v.Z + 1}] {
			plane := voxelPlane{voxelPosZ, v.Z, v.Color}
			face := voxelFace{v.X, v.Y, v.X, v.Y}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
		if !lookup[key{v.X, v.Y, v.Z - 1}] {
			plane := voxelPlane{voxelNegZ, v.Z, v.Color}
			face := voxelFace{v.X, v.Y, v.X, v.Y}
			planeFaces[plane] = append(planeFaces[plane], face)
		}
	}

	var triangles []*Triangle
	var lines []*Line

	// find large rectangles, triangulate and outline
	for plane, faces := range planeFaces {
		faces = combineVoxelFaces(faces)
		lines = append(lines, outlineVoxelFaces(plane, faces)...)
		triangles = append(triangles, triangulateVoxelFaces(plane, faces)...)
	}

	// remove t-junctions in mesh
	if false {
		vertexes := make(map[Vector]bool)
		for _, t := range triangles {
			vertexes[t.V1.Position] = true
			vertexes[t.V2.Position] = true
			vertexes[t.V3.Position] = true
		}
		for v := range vertexes {
			for _, t := range triangles {
				if pointOnSegment(v, t.V1.Position, t.V2.Position) {
					u := NewTriangle(t.V1, t.V2, t.V3)
					u.V1.Position = v
					t.V2.Position = v
					triangles = append(triangles, u)
				}
				if pointOnSegment(v, t.V2.Position, t.V3.Position) {
					u := NewTriangle(t.V1, t.V2, t.V3)
					u.V2.Position = v
					t.V3.Position = v
					triangles = append(triangles, u)
				}
				if pointOnSegment(v, t.V3.Position, t.V1.Position) {
					u := NewTriangle(t.V1, t.V2, t.V3)
					u.V3.Position = v
					t.V1.Position = v
					triangles = append(triangles, u)
				}
			}
		}
	}

	return NewMesh(triangles, lines)
}

func pointOnSegment(p, v0, v1 Vector) bool {
	// v0 to v1 must be an axis aligned segment
	if v0.X == v1.X && v0.X == p.X && v0.Y == v1.Y && v0.Y == p.Y {
		z0, z1 := v0.Z, v1.Z
		return (p.Z > z0 && p.Z < z1) || (p.Z < z0 && p.Z > z1)
	}
	if v0.X == v1.X && v0.X == p.X && v0.Z == v1.Z && v0.Z == p.Z {
		y0, y1 := v0.Y, v1.Y
		return (p.Y > y0 && p.Y < y1) || (p.Y < y0 && p.Y > y1)
	}
	if v0.Y == v1.Y && v0.Y == p.Y && v0.Z == v1.Z && v0.Z == p.Z {
		x0, x1 := v0.X, v1.X
		return (p.X > x0 && p.X < x1) || (p.X < x0 && p.X > x1)
	}
	return false
}

func combineVoxelFaces(faces []voxelFace) []voxelFace {
	// determine bounding box
	i0 := faces[0].I0
	j0 := faces[0].J0
	i1 := faces[0].I1
	j1 := faces[0].J1
	for _, f := range faces {
		if f.I0 < i0 {
			i0 = f.I0
		}
		if f.J0 < j0 {
			j0 = f.J0
		}
		if f.I1 > i1 {
			i1 = f.I1
		}
		if f.J1 > j1 {
			j1 = f.J1
		}
	}
	// create arrays
	nj := j1 - j0 + 1
	ni := i1 - i0 + 1
	a := make([][]int, nj)
	w := make([][]int, nj)
	h := make([][]int, nj)
	for j := range a {
		a[j] = make([]int, ni)
		w[j] = make([]int, ni)
		h[j] = make([]int, ni)
	}
	// populate array
	count := 0
	for _, f := range faces {
		for j := f.J0; j <= f.J1; j++ {
			for i := f.I0; i <= f.I1; i++ {
				a[j-j0][i-i0] = 1
				count++
			}
		}
	}
	// find rectangles
	var result []voxelFace
	for count > 0 {
		var maxArea int
		var maxFace voxelFace
		for j := 0; j < nj; j++ {
			for i := 0; i < ni; i++ {
				if a[j][i] == 0 {
					continue
				}
				if j == 0 {
					h[j][i] = 1
				} else {
					h[j][i] = h[j-1][i] + 1
				}
				if i == 0 {
					w[j][i] = 1
				} else {
					w[j][i] = w[j][i-1] + 1
				}
				minw := w[j][i]
				for dh := 0; dh < h[j][i]; dh++ {
					if w[j-dh][i] < minw {
						minw = w[j-dh][i]
					}
					area := (dh + 1) * minw
					if area > maxArea {
						maxArea = area
						maxFace = voxelFace{
							i0 + i - minw + 1, j0 + j - dh, i0 + i, j0 + j}
					}
				}
			}
		}
		result = append(result, maxFace)
		for j := maxFace.J0; j <= maxFace.J1; j++ {
			for i := maxFace.I0; i <= maxFace.I1; i++ {
				a[j-j0][i-i0] = 0
				count--
			}
		}
		for j := 0; j < nj; j++ {
			for i := 0; i < ni; i++ {
				w[j][i] = 0
				h[j][i] = 0
			}
		}
	}
	return result
}

func triangulateVoxelFaces(plane voxelPlane, faces []voxelFace) []*Triangle {
	triangles := make([]*Triangle, len(faces)*2)
	k := float64(plane.Position) + float64(plane.Normal.Sign)*0.5
	for i, face := range faces {
		i0 := float64(face.I0) - 0.5
		j0 := float64(face.J0) - 0.5
		i1 := float64(face.I1) + 0.5
		j1 := float64(face.J1) + 0.5
		var p1, p2, p3, p4 Vector
		switch plane.Normal.Axis {
		case voxelX:
			p1 = Vector{k, i0, j0}
			p2 = Vector{k, i1, j0}
			p3 = Vector{k, i1, j1}
			p4 = Vector{k, i0, j1}
		case voxelY:
			p1 = Vector{i0, k, j1}
			p2 = Vector{i1, k, j1}
			p3 = Vector{i1, k, j0}
			p4 = Vector{i0, k, j0}
		case voxelZ:
			p1 = Vector{i0, j0, k}
			p2 = Vector{i1, j0, k}
			p3 = Vector{i1, j1, k}
			p4 = Vector{i0, j1, k}
		}
		if plane.Normal.Sign < 0 {
			p1, p2, p3, p4 = p4, p3, p2, p1
		}
		t1 := NewTriangleForPoints(p1, p2, p3)
		t2 := NewTriangleForPoints(p1, p3, p4)
		t1.V1.Color = plane.Color
		t1.V2.Color = plane.Color
		t1.V3.Color = plane.Color
		t2.V1.Color = plane.Color
		t2.V2.Color = plane.Color
		t2.V3.Color = plane.Color
		triangles[i*2+0] = t1
		triangles[i*2+1] = t2
	}
	return triangles
}

func outlineVoxelFaces(plane voxelPlane, faces []voxelFace) []*Line {
	// determine bounding box
	i0 := faces[0].I0
	j0 := faces[0].J0
	i1 := faces[0].I1
	j1 := faces[0].J1
	for _, f := range faces {
		if f.I0 < i0 {
			i0 = f.I0
		}
		if f.J0 < j0 {
			j0 = f.J0
		}
		if f.I1 > i1 {
			i1 = f.I1
		}
		if f.J1 > j1 {
			j1 = f.J1
		}
	}
	// padding
	i0--
	j0--
	i1++
	j1++
	// create array
	nj := j1 - j0 + 1
	ni := i1 - i0 + 1
	a := make([][]bool, nj)
	for j := range a {
		a[j] = make([]bool, ni)
	}
	// populate array
	for _, f := range faces {
		for j := f.J0; j <= f.J1; j++ {
			for i := f.I0; i <= f.I1; i++ {
				a[j-j0][i-i0] = true
			}
		}
	}
	var lines []*Line
	for sign := -1; sign <= 1; sign += 2 {
		// find "horizontal" lines
		for j := 1; j < nj-1; j++ {
			start := -1
			for i := 0; i < ni; i++ {
				if a[j][i] && !a[j+sign][i] {
					if start < 0 {
						start = i
					}
				} else if start >= 0 {
					end := i - 1
					ai := float64(i0+start) - 0.5
					bi := float64(i0+end) + 0.5
					jj := float64(j0+j) + 0.5*float64(sign)
					line := createVoxelOutline(plane, ai, jj, bi, jj)
					lines = append(lines, line)
					start = -1
				}
			}

		}
		// find "vertical" lines
		for i := 1; i < ni-1; i++ {
			start := -1
			for j := 0; j < nj; j++ {
				if a[j][i] && !a[j][i+sign] {
					if start < 0 {
						start = j
					}
				} else if start >= 0 {
					end := j - 1
					aj := float64(j0+start) - 0.5
					bj := float64(j0+end) + 0.5
					ii := float64(i0+i) + 0.5*float64(sign)
					line := createVoxelOutline(plane, ii, aj, ii, bj)
					lines = append(lines, line)
					start = -1
				}
			}
		}
	}
	return lines
}

func createVoxelOutline(plane voxelPlane, i0, j0, i1, j1 float64) *Line {
	k := float64(plane.Position) + float64(plane.Normal.Sign)*0.5
	var p1, p2 Vector
	switch plane.Normal.Axis {
	case voxelX:
		p1 = Vector{k, i0, j0}
		p2 = Vector{k, i1, j1}
	case voxelY:
		p1 = Vector{i0, k, j0}
		p2 = Vector{i1, k, j1}
	case voxelZ:
		p1 = Vector{i0, j0, k}
		p2 = Vector{i1, j1, k}
	}
	return NewLineForPoints(p1, p2)
}
<|endoftext|>


<commit_before>package vultr

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
	"text/template"
	"time"

	"github.com/ChimeraCoder/tokenbucket"
	vultr "github.com/JamesClonk/vultr/lib"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcnflag"
	"github.com/docker/machine/libmachine/ssh"
	"github.com/docker/machine/libmachine/state"
)

var vultrTokenBucket = tokenbucket.NewBucket(1*time.Second, 1)

type Driver struct {
	*drivers.BaseDriver
	APIKey            string
	MachineID         string
	PrivateIP         string
	OSID              int
	RegionID          int
	PlanID            int
	SSHKeyID          string
	IPv6              bool
	Backups           bool
	PrivateNetworking bool
	ScriptID          int
	bucket            *tokenbucket.Bucket
}

const (
	defaultOS     = 160
	defaultRegion = 1
	defaultPlan   = 29
)

// GetCreateFlags registers the flags this driver adds to
// "docker hosts create"
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
	return []mcnflag.Flag{
		mcnflag.StringFlag{
			EnvVar: "VULTR_API_KEY",
			Name:   "vultr-api-key",
			Usage:  "Vultr API key",
		},
		mcnflag.IntFlag{
			EnvVar: "VULTR_OS",
			Name:   "vultr-os-id",
			Usage:  "Vultr operating system ID. Default: ubuntu-14-04-x64",
			Value:  defaultOS,
		},
		mcnflag.IntFlag{
			EnvVar: "VULTR_REGION",
			Name:   "vultr-region-id",
			Usage:  "Vultr region ID. Default: New Jersey",
			Value:  defaultRegion,
		},
		mcnflag.IntFlag{
			EnvVar: "VULTR_PLAN",
			Name:   "vultr-plan-id",
			Usage:  "Vultr plan ID. Default: 768 MB RAM",
			Value:  defaultPlan,
		},
		mcnflag.BoolFlag{
			EnvVar: "VULTR_IPV6",
			Name:   "vultr-ipv6",
			Usage:  "Enable IPv6 for VPS",
		},
		mcnflag.BoolFlag{
			EnvVar: "VULTR_PRIVATE_NETWORKING",
			Name:   "vultr-private-networking",
			Usage:  "Enable private networking for VPS",
		},
		mcnflag.BoolFlag{
			EnvVar: "VULTR_BACKUPS",
			Name:   "vultr-backups",
			Usage:  "Enable automatic backups for VPS",
		},
	}
}

func NewDriver(hostName, storePath string) *Driver {
	d := &Driver{
		OSID:     defaultOS,
		PlanID:   defaultPlan,
		RegionID: defaultRegion,
		bucket:   nil,
		BaseDriver: &drivers.BaseDriver{
			MachineName: hostName,
			StorePath:   storePath,
		},
	}
	d.bucket = vultrTokenBucket
	return d
}

func (d *Driver) GetSSHHostname() (string, error) {
	return d.GetIP()
}

func (d *Driver) DriverName() string {
	return "vultr"
}

func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
	d.APIKey = flags.String("vultr-api-key")
	d.OSID = flags.Int("vultr-os-id")
	d.RegionID = flags.Int("vultr-region-id")
	d.PlanID = flags.Int("vultr-plan-id")
	d.IPv6 = flags.Bool("vultr-ipv6")
	d.PrivateNetworking = flags.Bool("vultr-private-networking")
	d.Backups = flags.Bool("vultr-backups")
	d.SwarmMaster = flags.Bool("swarm-master")
	d.SwarmHost = flags.String("swarm-host")
	d.SwarmDiscovery = flags.String("swarm-discovery")
	d.SSHUser = "root"
	d.SSHPort = 22

	if d.APIKey == "" {
		return fmt.Errorf("vultr driver requires the --vultr-api-key option")
	}
	return nil
}

func (d *Driver) PreCreateCheck() error {

	log.Info("Validating Vultr VPS parameters...")

	if err := d.validateRegion(); err != nil {
		return err
	}

	if err := d.validatePlan(); err != nil {
		return err
	}

	if err := d.validateApiCredentials(); err != nil {
		return err
	}

	return nil
}

func (d *Driver) Create() error {
	var userdata string
	log.Debug("Generating SSH key...")

	key, err := d.createSSHKey()
	if err != nil {
		return err
	}

	d.SSHKeyID = key.ID

	log.Info("Creating Vultr VPS...")

	// RancherOS iPXE boot prep
	if d.OSID == 159 {
		log.Info("Deploying RancherOS via iPXE")
		d.SSHUser = "rancher"
		if err := d.createBootScript(); err != nil {
			return err
		}
		log.Debugf("Uploaded iPXE boot script ID %d", d.ScriptID)
		userdata, err = d.getCloudConfig()
		if err != nil {
			return err
		}
		log.Debugf("Using the following cloud-config file:")
		log.Debugf("%s", userdata)
	}

	client := d.getClient()
	<-d.bucket.SpendToken(1)
	machine, err := client.CreateServer(
		d.MachineName,
		d.RegionID,
		d.PlanID,
		d.OSID,
		&vultr.ServerOptions{
			SSHKey:            d.SSHKeyID,
			IPV6:              d.IPv6,
			PrivateNetworking: d.PrivateNetworking,
			AutoBackups:       d.Backups,
			Script:            d.ScriptID,
			UserData:          userdata,
		})
	if err != nil {
		return err
	}
	d.MachineID = machine.ID

	log.Info("Waiting for IP address to become available...")
	for {
		<-d.bucket.SpendToken(3)
		machine, err = client.GetServer(d.MachineID)
		if err != nil {
			return err
		}
		d.IPAddress = machine.MainIP
		d.PrivateIP = machine.InternalIP

		if d.IPAddress != "" && d.IPAddress != "0" {
			break
		}
		log.Debug("IP address not yet available")
	}

	if d.PrivateIP == "0" {
		d.PrivateIP = ""
	}

	log.Infof("Created Vultr VPS ID: %s, Public IP: %s, Private IP: %s",
		d.MachineID,
		d.IPAddress,
		d.PrivateIP,
	)

	return nil
}

func (d *Driver) createSSHKey() (*vultr.SSHKey, error) {
	if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
		return nil, err
	}

	publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
	if err != nil {
		return nil, err
	}

	<-d.bucket.SpendToken(1)
	key, err := d.getClient().CreateSSHKey(d.MachineName, string(publicKey))
	if err != nil {
		return &key, err
	}
	return &key, nil
}

func (d *Driver) GetURL() (string, error) {
	ip, err := d.GetIP()
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("tcp://%s:2376", ip), nil
}

func (d *Driver) GetIP() (string, error) {
	if d.IPAddress == "" || d.IPAddress == "0" {
		return "", fmt.Errorf("IP address is not set")
	}
	return d.IPAddress, nil
}

func (d *Driver) GetState() (state.State, error) {
	<-d.bucket.SpendToken(1)
	machine, err := d.getClient().GetServer(d.MachineID)
	if err != nil {
		return state.Error, err
	}
	switch machine.Status {
	case "pending":
		return state.Starting, nil
	case "active":
		switch machine.PowerStatus {
		case "running":
			return state.Running, nil
		case "stopped":
			return state.Stopped, nil
		}
	}
	return state.None, nil
}

func (d *Driver) Start() error {
	if vmState, err := d.GetState(); err != nil {
		return err
	} else if vmState == state.Running || vmState == state.Starting {
		log.Infof("Host is already running or starting")
		return nil
	}
	log.Debugf("starting %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	return d.getClient().StartServer(d.MachineID)
}

func (d *Driver) Stop() error {
	if vmState, err := d.GetState(); err != nil {
		return err
	} else if vmState == state.Stopped {
		log.Infof("Host is already stopped")
		return nil
	}
	log.Debugf("stopping %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	return d.getClient().HaltServer(d.MachineID)
}

func (d *Driver) Remove() error {
	client := d.getClient()
	log.Debugf("removing %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	if err := client.DeleteServer(d.MachineID); err != nil {
		if strings.Contains(err.Error(), "Invalid server") {
			log.Infof("VPS doesn't exist, assuming it is already deleted")
		} else {
			return err
		}
	}
	<-d.bucket.SpendToken(1)
	if err := client.DeleteSSHKey(d.SSHKeyID); err != nil {
		if strings.Contains(err.Error(), "Invalid SSH Key") {
			log.Infof("SSH key doesn't exist, assuming it is already deleted")
		} else {
			return err
		}
	}
	if d.ScriptID != 0 {
		<-d.bucket.SpendToken(1)
		if err := client.DeleteStartupScript(string(d.ScriptID)); err != nil {
			if strings.Contains(err.Error(), "Check SCRIPTID") {
				log.Infof("Script doesn't exist, assuming it is already deleted")
			} else {
				return err
			}
		}
	}
	return nil
}

func (d *Driver) Restart() error {
	if vmState, err := d.GetState(); err != nil {
		return err
	} else if vmState == state.Stopped {
		log.Infof("Host is already stopped, use start command to run it")
		return nil
	}
	log.Debugf("restarting %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	return d.getClient().RebootServer(d.MachineID)
}

func (d *Driver) Kill() error {
	if vmState, err := d.GetState(); err != nil {
		return err
	} else if vmState == state.Stopped {
		log.Infof("Host is already stopped")
		return nil
	}
	log.Debugf("killing %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	return d.getClient().HaltServer(d.MachineID)
}

func (d *Driver) getClient() *vultr.Client {
	return vultr.NewClient(d.APIKey, nil)
}

func (d *Driver) publicSSHKeyPath() string {
	return d.GetSSHKeyPath() + ".pub"
}

func (d *Driver) instanceIsRunning() bool {
	st, err := d.GetState()
	if err != nil {
		log.Debug(err)
	}
	if st == state.Running {
		return true
	}
	log.Debug("VPS not yet started")
	return false
}

func (d *Driver) validateApiCredentials() error {
	_, err := d.getClient().GetAccountInfo()
	if err != nil {
		return err
	}
	return nil
}

func (d *Driver) validateRegion() error {
	<-d.bucket.SpendToken(1)
	regions, err := d.getClient().GetRegions()
	if err != nil {
		return err
	}
	for _, region := range regions {
		if region.ID == d.RegionID {
			return nil
		}
	}
	return fmt.Errorf("Region ID %d is invalid", d.RegionID)
}

func (d *Driver) validatePlan() error {
	<-d.bucket.SpendToken(1)
	plans, err := d.getClient().GetAvailablePlansForRegion(d.RegionID)
	if err != nil {
		return err
	}
	for _, v := range plans {
		if v == d.PlanID {
			return nil
		}
	}
	return fmt.Errorf("PlanID %d not available in the chosen region. Available plans for RegionID %d: %v", d.PlanID, d.RegionID, plans)
}

// RancherOS - Create iPXE boot script
func (d *Driver) createBootScript() error {
	content := `#!ipxe
set base-url https://releases.rancher.com/os/latest
kernel ${base-url}/vmlinuz rancher.state.autoformat=[/dev/vda] rancher.cloud_init.datasources=[ec2]
initrd ${base-url}/initrd
boot`
	<-d.bucket.SpendToken(1)
	script, err := d.getClient().CreateStartupScript(d.MachineName, content, "pxe")
	if err != nil {
		return err
	}
	d.ScriptID, err = strconv.Atoi(script.ID)
	if err != nil {
		return err
	}
	return nil
}

// RancherOS - Generate cloud-config userdata string that will
// provision the SSH Key to the VPS and configure private networking
func (d *Driver) getCloudConfig() (string, error) {
	type userData struct {
		HostName   string
		SSHkey     string
		PrivateNet bool
	}
	const tpl = `#cloud-config
hostname: {{.HostName}}
ssh_authorized_keys:
  - {{.SSHkey}}{{if .PrivateNet}}
write_files:
  - path: /opt/rancher/bin/start.sh
    permissions: 0700
    content: |
      #!/bin/bash
      sudo netconf
      rm -- "$0"
rancher:
  network:
    interfaces:
      eth0:
        dhcp: true
      eth1:
        address: $private_ipv4/16
        mtu: 1450{{end}}
`
	var buffer bytes.Buffer

	publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
	if err != nil {
		return "", err
	}
	config := userData{HostName: d.MachineName, SSHkey: string(publicKey), PrivateNet: d.PrivateNetworking}

	tmpl, err := template.New("cloud-config").Parse(tpl)
	if err != nil {
		return "", err
	}
	err = tmpl.Execute(&buffer, config)
	if err != nil {
		return "", err
	}
	return buffer.String(), nil
}
<commit_msg>Fix: iPXE boot script is not removed on docker-machine rm<commit_after>package vultr

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
	"text/template"
	"time"

	"github.com/ChimeraCoder/tokenbucket"
	vultr "github.com/JamesClonk/vultr/lib"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcnflag"
	"github.com/docker/machine/libmachine/ssh"
	"github.com/docker/machine/libmachine/state"
)

var vultrTokenBucket = tokenbucket.NewBucket(1*time.Second, 1)

type Driver struct {
	*drivers.BaseDriver
	APIKey            string
	MachineID         string
	PrivateIP         string
	OSID              int
	RegionID          int
	PlanID            int
	SSHKeyID          string
	IPv6              bool
	Backups           bool
	PrivateNetworking bool
	ScriptID          int
	bucket            *tokenbucket.Bucket
}

const (
	defaultOS     = 160
	defaultRegion = 1
	defaultPlan   = 29
)

// GetCreateFlags registers the flags this driver adds to
// "docker hosts create"
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
	return []mcnflag.Flag{
		mcnflag.StringFlag{
			EnvVar: "VULTR_API_KEY",
			Name:   "vultr-api-key",
			Usage:  "Vultr API key",
		},
		mcnflag.IntFlag{
			EnvVar: "VULTR_OS",
			Name:   "vultr-os-id",
			Usage:  "Vultr operating system ID. Default: ubuntu-14-04-x64",
			Value:  defaultOS,
		},
		mcnflag.IntFlag{
			EnvVar: "VULTR_REGION",
			Name:   "vultr-region-id",
			Usage:  "Vultr region ID. Default: New Jersey",
			Value:  defaultRegion,
		},
		mcnflag.IntFlag{
			EnvVar: "VULTR_PLAN",
			Name:   "vultr-plan-id",
			Usage:  "Vultr plan ID. Default: 768 MB RAM",
			Value:  defaultPlan,
		},
		mcnflag.BoolFlag{
			EnvVar: "VULTR_IPV6",
			Name:   "vultr-ipv6",
			Usage:  "Enable IPv6 for VPS",
		},
		mcnflag.BoolFlag{
			EnvVar: "VULTR_PRIVATE_NETWORKING",
			Name:   "vultr-private-networking",
			Usage:  "Enable private networking for VPS",
		},
		mcnflag.BoolFlag{
			EnvVar: "VULTR_BACKUPS",
			Name:   "vultr-backups",
			Usage:  "Enable automatic backups for VPS",
		},
	}
}

func NewDriver(hostName, storePath string) *Driver {
	d := &Driver{
		OSID:     defaultOS,
		PlanID:   defaultPlan,
		RegionID: defaultRegion,
		bucket:   nil,
		BaseDriver: &drivers.BaseDriver{
			MachineName: hostName,
			StorePath:   storePath,
		},
	}
	d.bucket = vultrTokenBucket
	return d
}

func (d *Driver) GetSSHHostname() (string, error) {
	return d.GetIP()
}

func (d *Driver) DriverName() string {
	return "vultr"
}

func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
	d.APIKey = flags.String("vultr-api-key")
	d.OSID = flags.Int("vultr-os-id")
	d.RegionID = flags.Int("vultr-region-id")
	d.PlanID = flags.Int("vultr-plan-id")
	d.IPv6 = flags.Bool("vultr-ipv6")
	d.PrivateNetworking = flags.Bool("vultr-private-networking")
	d.Backups = flags.Bool("vultr-backups")
	d.SwarmMaster = flags.Bool("swarm-master")
	d.SwarmHost = flags.String("swarm-host")
	d.SwarmDiscovery = flags.String("swarm-discovery")
	d.SSHUser = "root"
	d.SSHPort = 22

	if d.APIKey == "" {
		return fmt.Errorf("vultr driver requires the --vultr-api-key option")
	}
	return nil
}

func (d *Driver) PreCreateCheck() error {

	log.Info("Validating Vultr VPS parameters...")

	if err := d.validateRegion(); err != nil {
		return err
	}

	if err := d.validatePlan(); err != nil {
		return err
	}

	if err := d.validateApiCredentials(); err != nil {
		return err
	}

	return nil
}

func (d *Driver) Create() error {
	var userdata string
	log.Debug("Generating SSH key...")

	key, err := d.createSSHKey()
	if err != nil {
		return err
	}

	d.SSHKeyID = key.ID

	log.Info("Creating Vultr VPS...")

	// RancherOS iPXE boot prep
	if d.OSID == 159 {
		log.Info("Deploying RancherOS via iPXE")
		d.SSHUser = "rancher"
		if err := d.createBootScript(); err != nil {
			return err
		}
		log.Debugf("Uploaded iPXE boot script ID %d", d.ScriptID)
		userdata, err = d.getCloudConfig()
		if err != nil {
			return err
		}
		log.Debugf("Using the following cloud-config file:")
		log.Debugf("%s", userdata)
	}

	client := d.getClient()
	<-d.bucket.SpendToken(1)
	machine, err := client.CreateServer(
		d.MachineName,
		d.RegionID,
		d.PlanID,
		d.OSID,
		&vultr.ServerOptions{
			SSHKey:            d.SSHKeyID,
			IPV6:              d.IPv6,
			PrivateNetworking: d.PrivateNetworking,
			AutoBackups:       d.Backups,
			Script:            d.ScriptID,
			UserData:          userdata,
		})
	if err != nil {
		return err
	}
	d.MachineID = machine.ID

	log.Info("Waiting for IP address to become available...")
	for {
		<-d.bucket.SpendToken(3)
		machine, err = client.GetServer(d.MachineID)
		if err != nil {
			return err
		}
		d.IPAddress = machine.MainIP
		d.PrivateIP = machine.InternalIP

		if d.IPAddress != "" && d.IPAddress != "0" {
			break
		}
		log.Debug("IP address not yet available")
	}

	if d.PrivateIP == "0" {
		d.PrivateIP = ""
	}

	log.Infof("Created Vultr VPS ID: %s, Public IP: %s, Private IP: %s",
		d.MachineID,
		d.IPAddress,
		d.PrivateIP,
	)

	return nil
}

func (d *Driver) createSSHKey() (*vultr.SSHKey, error) {
	if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
		return nil, err
	}

	publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
	if err != nil {
		return nil, err
	}

	<-d.bucket.SpendToken(1)
	key, err := d.getClient().CreateSSHKey(d.MachineName, string(publicKey))
	if err != nil {
		return &key, err
	}
	return &key, nil
}

func (d *Driver) GetURL() (string, error) {
	ip, err := d.GetIP()
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("tcp://%s:2376", ip), nil
}

func (d *Driver) GetIP() (string, error) {
	if d.IPAddress == "" || d.IPAddress == "0" {
		return "", fmt.Errorf("IP address is not set")
	}
	return d.IPAddress, nil
}

func (d *Driver) GetState() (state.State, error) {
	<-d.bucket.SpendToken(1)
	machine, err := d.getClient().GetServer(d.MachineID)
	if err != nil {
		return state.Error, err
	}
	switch machine.Status {
	case "pending":
		return state.Starting, nil
	case "active":
		switch machine.PowerStatus {
		case "running":
			return state.Running, nil
		case "stopped":
			return state.Stopped, nil
		}
	}
	return state.None, nil
}

func (d *Driver) Start() error {
	if vmState, err := d.GetState(); err != nil {
		return err
	} else if vmState == state.Running || vmState == state.Starting {
		log.Infof("Host is already running or starting")
		return nil
	}
	log.Debugf("starting %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	return d.getClient().StartServer(d.MachineID)
}

func (d *Driver) Stop() error {
	if vmState, err := d.GetState(); err != nil {
		return err
	} else if vmState == state.Stopped {
		log.Infof("Host is already stopped")
		return nil
	}
	log.Debugf("stopping %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	return d.getClient().HaltServer(d.MachineID)
}

func (d *Driver) Remove() error {
	client := d.getClient()
	log.Debugf("removing %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	if err := client.DeleteServer(d.MachineID); err != nil {
		if strings.Contains(err.Error(), "Invalid server") {
			log.Infof("VPS doesn't exist, assuming it is already deleted")
		} else {
			return err
		}
	}
	<-d.bucket.SpendToken(1)
	if err := client.DeleteSSHKey(d.SSHKeyID); err != nil {
		if strings.Contains(err.Error(), "Invalid SSH Key") {
			log.Infof("SSH key doesn't exist, assuming it is already deleted")
		} else {
			return err
		}
	}
	if d.ScriptID != 0 {
		<-d.bucket.SpendToken(1)
		if err := client.DeleteStartupScript(strconv.Itoa(d.ScriptID)); err != nil {
			if strings.Contains(err.Error(), "Check SCRIPTID") {
				log.Infof("Script doesn't exist, assuming it is already deleted")
			} else {
				return err
			}
		}
	}
	return nil
}

func (d *Driver) Restart() error {
	if vmState, err := d.GetState(); err != nil {
		return err
	} else if vmState == state.Stopped {
		log.Infof("Host is already stopped, use start command to run it")
		return nil
	}
	log.Debugf("restarting %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	return d.getClient().RebootServer(d.MachineID)
}

func (d *Driver) Kill() error {
	if vmState, err := d.GetState(); err != nil {
		return err
	} else if vmState == state.Stopped {
		log.Infof("Host is already stopped")
		return nil
	}
	log.Debugf("killing %s", d.MachineName)
	<-d.bucket.SpendToken(1)
	return d.getClient().HaltServer(d.MachineID)
}

func (d *Driver) getClient() *vultr.Client {
	return vultr.NewClient(d.APIKey, nil)
}

func (d *Driver) publicSSHKeyPath() string {
	return d.GetSSHKeyPath() + ".pub"
}

func (d *Driver) instanceIsRunning() bool {
	st, err := d.GetState()
	if err != nil {
		log.Debug(err)
	}
	if st == state.Running {
		return true
	}
	log.Debug("VPS not yet started")
	return false
}

func (d *Driver) validateApiCredentials() error {
	_, err := d.getClient().GetAccountInfo()
	if err != nil {
		return err
	}
	return nil
}

func (d *Driver) validateRegion() error {
	<-d.bucket.SpendToken(1)
	regions, err := d.getClient().GetRegions()
	if err != nil {
		return err
	}
	for _, region := range regions {
		if region.ID == d.RegionID {
			return nil
		}
	}
	return fmt.Errorf("Region ID %d is invalid", d.RegionID)
}

func (d *Driver) validatePlan() error {
	<-d.bucket.SpendToken(1)
	plans, err := d.getClient().GetAvailablePlansForRegion(d.RegionID)
	if err != nil {
		return err
	}
	for _, v := range plans {
		if v == d.PlanID {
			return nil
		}
	}
	return fmt.Errorf("PlanID %d not available in the chosen region. Available plans for RegionID %d: %v", d.PlanID, d.RegionID, plans)
}

// RancherOS - Create iPXE boot script
func (d *Driver) createBootScript() error {
	content := `#!ipxe
set base-url https://releases.rancher.com/os/latest
kernel ${base-url}/vmlinuz rancher.state.autoformat=[/dev/vda] rancher.cloud_init.datasources=[ec2]
initrd ${base-url}/initrd
boot`
	<-d.bucket.SpendToken(1)
	script, err := d.getClient().CreateStartupScript(d.MachineName, content, "pxe")
	if err != nil {
		return err
	}
	d.ScriptID, err = strconv.Atoi(script.ID)
	if err != nil {
		return err
	}
	return nil
}

// RancherOS - Generate cloud-config userdata string that will
// provision the SSH Key to the VPS and configure private networking
func (d *Driver) getCloudConfig() (string, error) {
	type userData struct {
		HostName   string
		SSHkey     string
		PrivateNet bool
	}
	const tpl = `#cloud-config
hostname: {{.HostName}}
ssh_authorized_keys:
  - {{.SSHkey}}{{if .PrivateNet}}
write_files:
  - path: /opt/rancher/bin/start.sh
    permissions: 0700
    content: |
      #!/bin/bash
      sudo netconf
      rm -- "$0"
rancher:
  network:
    interfaces:
      eth0:
        dhcp: true
      eth1:
        address: $private_ipv4/16
        mtu: 1450{{end}}
`
	var buffer bytes.Buffer

	publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
	if err != nil {
		return "", err
	}
	config := userData{HostName: d.MachineName, SSHkey: string(publicKey), PrivateNet: d.PrivateNetworking}

	tmpl, err := template.New("cloud-config").Parse(tpl)
	if err != nil {
		return "", err
	}
	err = tmpl.Execute(&buffer, config)
	if err != nil {
		return "", err
	}
	return buffer.String(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/fsnotify/fsevents"
	"sort"
	"time"
)

var noteDescription = map[fsevents.EventFlags]string{
	fsevents.MustScanSubDirs: "MustScanSubdirs",
	fsevents.UserDropped:     "UserDropped",
	fsevents.KernelDropped:   "KernelDropped",
	fsevents.EventIDsWrapped: "EventIDsWrapped",
	fsevents.HistoryDone:     "HistoryDone",
	fsevents.RootChanged:     "RootChanged",
	fsevents.Mount:           "Mount",
	fsevents.Unmount:         "Unmount",

	fsevents.ItemCreated:       "Created",
	fsevents.ItemRemoved:       "Removed",
	fsevents.ItemInodeMetaMod:  "InodeMetaMod",
	fsevents.ItemRenamed:       "Renamed",
	fsevents.ItemModified:      "Modified",
	fsevents.ItemFinderInfoMod: "FinderInfoMod",
	fsevents.ItemChangeOwner:   "ChangeOwner",
	fsevents.ItemXattrMod:      "XAttrMod",
	fsevents.ItemIsFile:        "IsFile",
	fsevents.ItemIsDir:         "IsDir",
	fsevents.ItemIsSymlink:     "IsSymLink",
}

func Watch(path string, eventHandler func(id uint64, path string, flags []string)) {
	dev, _ := fsevents.DeviceForPath(path)
	fsevents.EventIDForDeviceBeforeTime(dev, time.Now())

	es := &fsevents.EventStream{
		Paths:   []string{path},
		Latency: 50 * time.Millisecond,
		Device:  dev,
		Flags:   fsevents.FileEvents | fsevents.WatchRoot}
	es.Start()
	ec := es.Events

	for {
		select {
		case event := <-ec:
			flags := make([]string, 0)
			for bit, description := range noteDescription {
				if event.Flags&bit == bit {
					flags = append(flags, description)
				}
			}
			sort.Sort(sort.StringSlice(flags))
			go eventHandler(event.ID, event.Path, flags)

			es.Flush(false)
		}
	}
}
<commit_msg>Update event handler to use expected unbuffered Events chan<commit_after>package main

import (
	"github.com/fsnotify/fsevents"
	"sort"
	"time"
)

var noteDescription = map[fsevents.EventFlags]string{
	fsevents.MustScanSubDirs: "MustScanSubdirs",
	fsevents.UserDropped:     "UserDropped",
	fsevents.KernelDropped:   "KernelDropped",
	fsevents.EventIDsWrapped: "EventIDsWrapped",
	fsevents.HistoryDone:     "HistoryDone",
	fsevents.RootChanged:     "RootChanged",
	fsevents.Mount:           "Mount",
	fsevents.Unmount:         "Unmount",

	fsevents.ItemCreated:       "Created",
	fsevents.ItemRemoved:       "Removed",
	fsevents.ItemInodeMetaMod:  "InodeMetaMod",
	fsevents.ItemRenamed:       "Renamed",
	fsevents.ItemModified:      "Modified",
	fsevents.ItemFinderInfoMod: "FinderInfoMod",
	fsevents.ItemChangeOwner:   "ChangeOwner",
	fsevents.ItemXattrMod:      "XAttrMod",
	fsevents.ItemIsFile:        "IsFile",
	fsevents.ItemIsDir:         "IsDir",
	fsevents.ItemIsSymlink:     "IsSymLink",
}

func Watch(path string, eventHandler func(id uint64, path string, flags []string)) {
	dev, _ := fsevents.DeviceForPath(path)
	fsevents.EventIDForDeviceBeforeTime(dev, time.Now())

	es := &fsevents.EventStream{
		Paths:   []string{path},
		Latency: 50 * time.Millisecond,
		Device:  dev,
		Flags:   fsevents.FileEvents | fsevents.WatchRoot}
	es.Start()
	ec := es.Events

	for msg := range ec {
		for _, event := range msg {
			flags := make([]string, 0)
			for bit, description := range noteDescription {
				if event.Flags&bit == bit {
					flags = append(flags, description)
				}
			}
			sort.Sort(sort.StringSlice(flags))
			go eventHandler(event.ID, event.Path, flags)

		}
	}
}
<|endoftext|>


<commit_before>package itest

import (
	"context"
	"fmt"

	"github.com/lightningnetwork/lnd/lncfg"
	"github.com/lightningnetwork/lnd/lnrpc"
	"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
	"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
	"github.com/lightningnetwork/lnd/lntest"
	"github.com/lightningnetwork/lnd/lntest/wait"
	"github.com/lightningnetwork/lnd/lntypes"
	"github.com/stretchr/testify/require"
)

// testHoldInvoiceForceClose demonstrates that recipients of hold invoices
// will not release active htlcs for their own invoices when they expire,
// resulting in a force close of their channel.
func testHoldInvoiceForceClose(net *lntest.NetworkHarness, t *harnessTest) {
	ctxb, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Open a channel between alice and bob.
	chanReq := lntest.OpenChannelParams{
		Amt: 300000,
	}

	ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout)
	chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, chanReq)

	// Create a non-dust hold invoice for bob.
	var (
		preimage = lntypes.Preimage{1, 2, 3}
		payHash  = preimage.Hash()
	)
	invoiceReq := &invoicesrpc.AddHoldInvoiceRequest{
		Value:      30000,
		CltvExpiry: 40,
		Hash:       payHash[:],
	}

	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
	bobInvoice, err := net.Bob.AddHoldInvoice(ctxt, invoiceReq)
	require.NoError(t.t, err)

	// Pay this invoice from Alice -> Bob, we should achieve this with a
	// single htlc.
	_, err = net.Alice.RouterClient.SendPaymentV2(
		ctxb, &routerrpc.SendPaymentRequest{
			PaymentRequest: bobInvoice.PaymentRequest,
			TimeoutSeconds: 60,
			FeeLimitMsat:   noFeeLimitMsat,
		},
	)
	require.NoError(t.t, err)

	waitForInvoiceAccepted(t, net.Bob, payHash)

	// Once the HTLC has cleared, alice and bob should both have a single
	// htlc locked in.
	nodes := []*lntest.HarnessNode{net.Alice, net.Bob}
	err = wait.NoError(func() error {
		return assertActiveHtlcs(nodes, payHash[:])
	}, defaultTimeout)
	require.NoError(t.t, err)

	// Get our htlc expiry height and current block height so that we
	// can mine the exact number of blocks required to expire the htlc.
	chans, err := net.Alice.ListChannels(ctxb, &lnrpc.ListChannelsRequest{})
	require.NoError(t.t, err)
	require.Len(t.t, chans.Channels, 1)
	require.Len(t.t, chans.Channels[0].PendingHtlcs, 1)
	activeHtlc := chans.Channels[0].PendingHtlcs[0]

	info, err := net.Alice.GetInfo(ctxb, &lnrpc.GetInfoRequest{})
	require.NoError(t.t, err)

	// Now we will mine blocks until the htlc expires, and wait for each
	// node to sync to our latest height. Sanity check that we won't
	// underflow.
	require.Greater(t.t, activeHtlc.ExpirationHeight, info.BlockHeight,
		"expected expiry after current height")
	blocksTillExpiry := activeHtlc.ExpirationHeight - info.BlockHeight

	// Alice will go to chain with some delta, sanity check that we won't
	// underflow and subtract this from our mined blocks.
	require.Greater(t.t, blocksTillExpiry,
		uint32(lncfg.DefaultOutgoingBroadcastDelta))
	blocksTillForce := blocksTillExpiry - lncfg.DefaultOutgoingBroadcastDelta

	mineBlocks(t, net, blocksTillForce, 0)

	require.NoError(t.t, net.Alice.WaitForBlockchainSync(ctxb))
	require.NoError(t.t, net.Bob.WaitForBlockchainSync(ctxb))

	// Alice should have a waiting-close channel because she has force
	// closed to time out the htlc.
	assertNumPendingChannels(t, net.Alice, 1, 0)

	// We should have our force close tx in the mempool.
	mineBlocks(t, net, 1, 1)

	// Ensure alice and bob are synced to chain after we've mined our force
	// close.
	require.NoError(t.t, net.Alice.WaitForBlockchainSync(ctxb))
	require.NoError(t.t, net.Bob.WaitForBlockchainSync(ctxb))

	// At this point, Bob's channel should be resolved because his htlc is
	// expired, so no further action is required. Alice will still have a
	// pending force close channel because she needs to resolve the htlc.
	assertNumPendingChannels(t, net.Alice, 0, 1)
	assertNumPendingChannels(t, net.Bob, 0, 0)

	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
	err = waitForNumChannelPendingForceClose(ctxt, net.Alice, 1,
		func(channel *lnrpcForceCloseChannel) error {
			numHtlcs := len(channel.PendingHtlcs)
			if numHtlcs != 1 {
				return fmt.Errorf("expected 1 htlc, got: "+
					"%v", numHtlcs)
			}

			return nil
		},
	)
	require.NoError(t.t, err)

	// Cleanup Alice's force close.
	cleanupForceClose(t, net, net.Alice, chanPoint)
}
<commit_msg>itest/test: test hold invoice cancel before force close<commit_after>package itest

import (
	"context"
	"fmt"

	"github.com/lightningnetwork/lnd/lncfg"
	"github.com/lightningnetwork/lnd/lnrpc"
	"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
	"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
	"github.com/lightningnetwork/lnd/lntest"
	"github.com/lightningnetwork/lnd/lntest/wait"
	"github.com/lightningnetwork/lnd/lntypes"
	"github.com/stretchr/testify/require"
)

// testHoldInvoiceForceClose tests cancelation of accepted hold invoices which
// would otherwise trigger force closes when they expire.
func testHoldInvoiceForceClose(net *lntest.NetworkHarness, t *harnessTest) {
	ctxb, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Open a channel between alice and bob.
	chanReq := lntest.OpenChannelParams{
		Amt: 300000,
	}

	ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout)
	chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, chanReq)

	// Create a non-dust hold invoice for bob.
	var (
		preimage = lntypes.Preimage{1, 2, 3}
		payHash  = preimage.Hash()
	)
	invoiceReq := &invoicesrpc.AddHoldInvoiceRequest{
		Value:      30000,
		CltvExpiry: 40,
		Hash:       payHash[:],
	}

	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
	bobInvoice, err := net.Bob.AddHoldInvoice(ctxt, invoiceReq)
	require.NoError(t.t, err)

	// Pay this invoice from Alice -> Bob, we should achieve this with a
	// single htlc.
	_, err = net.Alice.RouterClient.SendPaymentV2(
		ctxb, &routerrpc.SendPaymentRequest{
			PaymentRequest: bobInvoice.PaymentRequest,
			TimeoutSeconds: 60,
			FeeLimitMsat:   noFeeLimitMsat,
		},
	)
	require.NoError(t.t, err)

	waitForInvoiceAccepted(t, net.Bob, payHash)

	// Once the HTLC has cleared, alice and bob should both have a single
	// htlc locked in.
	nodes := []*lntest.HarnessNode{net.Alice, net.Bob}
	err = wait.NoError(func() error {
		return assertActiveHtlcs(nodes, payHash[:])
	}, defaultTimeout)
	require.NoError(t.t, err)

	// Get our htlc expiry height and current block height so that we
	// can mine the exact number of blocks required to expire the htlc.
	chans, err := net.Alice.ListChannels(ctxb, &lnrpc.ListChannelsRequest{})
	require.NoError(t.t, err)
	require.Len(t.t, chans.Channels, 1)
	require.Len(t.t, chans.Channels[0].PendingHtlcs, 1)
	activeHtlc := chans.Channels[0].PendingHtlcs[0]

	info, err := net.Alice.GetInfo(ctxb, &lnrpc.GetInfoRequest{})
	require.NoError(t.t, err)

	// Now we will mine blocks until the htlc expires, and wait for each
	// node to sync to our latest height. Sanity check that we won't
	// underflow.
	require.Greater(t.t, activeHtlc.ExpirationHeight, info.BlockHeight,
		"expected expiry after current height")
	blocksTillExpiry := activeHtlc.ExpirationHeight - info.BlockHeight

	// Alice will go to chain with some delta, sanity check that we won't
	// underflow and subtract this from our mined blocks.
	require.Greater(t.t, blocksTillExpiry,
		uint32(lncfg.DefaultOutgoingBroadcastDelta))
	blocksTillForce := blocksTillExpiry - lncfg.DefaultOutgoingBroadcastDelta

	mineBlocks(t, net, blocksTillForce, 0)

	require.NoError(t.t, net.Alice.WaitForBlockchainSync(ctxb))
	require.NoError(t.t, net.Bob.WaitForBlockchainSync(ctxb))

	// Our channel should not have been force closed, instead we expect our
	// channel to still be open and our invoice to have been canceled before
	// expiry.
	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
	chanInfo, err := getChanInfo(ctxt, net.Alice)
	require.NoError(t.t, err)

	fundingTxID, err := lnrpc.GetChanPointFundingTxid(chanPoint)
	require.NoError(t.t, err)
	chanStr := fmt.Sprintf("%v:%v", fundingTxID, chanPoint.OutputIndex)
	require.Equal(t.t, chanStr, chanInfo.ChannelPoint)

	err = wait.NoError(func() error {
		inv, err := net.Bob.LookupInvoice(ctxt, &lnrpc.PaymentHash{
			RHash: payHash[:],
		})
		if err != nil {
			return err
		}

		if inv.State != lnrpc.Invoice_CANCELED {
			return fmt.Errorf("expected canceled invoice, got: %v",
				inv.State)
		}

		for _, htlc := range inv.Htlcs {
			if htlc.State != lnrpc.InvoiceHTLCState_CANCELED {
				return fmt.Errorf("expected htlc canceled, "+
					"got: %v", htlc.State)
			}
		}

		return nil
	}, defaultTimeout)
	require.NoError(t.t, err, "expected canceled invoice")

	// Clean up the channel.
	ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
	closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path"
	"sort"

	"github.com/gummiboll/woozy/weatherdata"
)

// Configuration for woozy
type Configuration struct {
	Place string `json:"place"`
	Days  int    `json:"days"`
}

var (
	icons = map[string]string{
		"Rain":                           "\U0001f327",
		"Snow":                           "\U0001f328",
		"Rain and thunder":               "\u26C8",
		"Light rain":                     "\U0001f326",
		"Light snow":                     "\U0001f328",
		"Light rain and thunder":         "\u26C8",
		"Light rain showers":             "\U0001f326",
		"Light rain showers and thunder": "\u26C8",
		"Light snow showers":             "\U0001f328",
		"Heavy rain":                     "\U0001f327",
		"Heavy rain and thunder":         "\u26C8",
		"Heavy snow":                     "\U0001f328",
		"Rain showers":                   "\U0001f326",
		"Rain showers and thunder":       "\u26C8",
		"Snow showers":                   "\U0001f328",
		"Clear sky":                      "\u263C",
		"Cloudy":                         "\u2601",
		"Partly cloudy":                  "\u26C5",
		"Fair":                           "\u26C5",
	}

	windIcons = map[string]string{
		"N":   "\u2193",
		"S":   "\u2191",
		"E":   "\u2190",
		"W":   "\u2192",
		"NE":  "\u2199",
		"NNE": "\u2199",
		"NEE": "\u2199",
		"ENE": "\u2199",
		"NW":  "\u2198",
		"NNW": "\u2198",
		"NWW": "\u2198",
		"WNW": "\u2198",
		"SE":  "\u2196",
		"SEE": "\u2196",
		"SSE": "\u2196",
		"ESE": "\u2196",
		"SW":  "\u2197",
		"SSW": "\u2197",
		"SWW": "\u2197",
		"WSW": "\u2197",
	}
)

func printHeader(wd weatherdata.WeatherData) {
	hStr := fmt.Sprintf("%s / %s", wd.Location.Country, wd.Location.Name)
	hStr = fmt.Sprintf("%s | %s %s %s %s %s (%.1f hours)", hStr, icons["Clear sky"], windIcons["S"], wd.Sun.Rise.Local().Format("15:04"), windIcons["N"], wd.Sun.Set.Local().Format("15:04"), wd.SunHours())
	fmt.Println(hStr)
}

func printFooter(wd weatherdata.WeatherData) {
	fmt.Println(fmt.Sprintf("Forecast issued %.1f hours ago, next update in %.1f hours", wd.Meta.HoursSinceUpdate(), wd.Meta.HoursToNextUpdate()))
	fmt.Println(fmt.Sprintf("\n%s.\n%s", wd.Credit.Text, wd.Credit.URL))
}

func printForecast(wd weatherdata.WeatherData, days int) {
	forecasts := make(map[string][]weatherdata.WeatherForecast)
	for i := range wd.Forecast {
		// Should maybe be typecasted to int?
		forecasts[wd.Forecast[i].From.Format("20060102")] = append(forecasts[wd.Forecast[i].From.Format("20060102")], wd.Forecast[i])
	}

	mk := make([]string, len(forecasts))
	i := 0
	for k := range forecasts {
		mk[i] = k
		i++
	}

	sort.Strings(mk)

	for i := 0; i < days; i++ {
		var wStr string
		fmt.Println(forecasts[mk[i]][0].From.Format("January 02 (Monday):"))
		for _, w := range forecasts[mk[i]] {
			wStr = fmt.Sprintf(" %s %s %d%s (%.1fmm)", w.PeriodName(), icons[w.Symbol.Name], w.Temperature.Value, "\u2103", w.Precipitation.Value)
			wStr = fmt.Sprintf("%s %s %.1f m/s", wStr, windIcons[w.WindDirection.Code], w.WindSpeed.Mps)
			fmt.Println(wStr)
		}
		fmt.Println("")
	}
}

func loadConfig() (Configuration, error) {
	configuration := Configuration{}

	usr, err := user.Current()
	if err != nil {
		return configuration, err
	}

	cfile := path.Join(usr.HomeDir, ".woozy")

	file, err := os.Open(cfile)
	if err != nil {
		fmt.Println(fmt.Sprintf("Configuration file not found, creating a example in %s..", cfile))
		out, err := os.Create(cfile)
		if err != nil {
			panic(err)
		}
		defer out.Close()
		configuration.Place = "Sweden/Västerbotten/Estersmark"
		configuration.Days = 3
		configjson, err := json.MarshalIndent(configuration, "", "\t")
		ioutil.WriteFile(cfile, configjson, 0600)
		fmt.Println(".. edit it and restart woozy")
		os.Exit(1)
	}

	decoder := json.NewDecoder(file)

	err = decoder.Decode(&configuration)

	if err != nil {
		return configuration, err
	}

	return configuration, nil

}

func main() {
	configuration, err := loadConfig()

	if err != nil {
		panic(err)
	}

	cc := flag.Bool("cache-clear", false, "Force cache clear")
	days := flag.Int("days", 3, "Number of days to print")
	flag.Parse()

	wd, err := weatherdata.LoadWeatherData(configuration.Place, *cc)
	if err != nil {
		panic(err)
	}

	if configuration.Days == 0 {
		configuration.Days = *days
	}

	printHeader(wd)
	printForecast(wd, configuration.Days)
	printFooter(wd)

}
<commit_msg>Updated layout<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path"
	"sort"

	"github.com/gummiboll/woozy/weatherdata"
)

// Configuration for woozy
type Configuration struct {
	Place string `json:"place"`
	Days  int    `json:"days"`
}

var (
	icons = map[string]string{
		"Rain":                           "\U0001f327",
		"Snow":                           "\U0001f328",
		"Rain and thunder":               "\u26C8",
		"Light rain":                     "\U0001f326",
		"Light snow":                     "\U0001f328",
		"Light rain and thunder":         "\u26C8",
		"Light rain showers":             "\U0001f326",
		"Light rain showers and thunder": "\u26C8",
		"Light snow showers":             "\U0001f328",
		"Heavy rain":                     "\U0001f327",
		"Heavy rain and thunder":         "\u26C8",
		"Heavy snow":                     "\U0001f328",
		"Rain showers":                   "\U0001f326",
		"Rain showers and thunder":       "\u26C8",
		"Snow showers":                   "\U0001f328",
		"Clear sky":                      "\u263C",
		"Cloudy":                         "\u2601",
		"Partly cloudy":                  "\u26C5",
		"Fair":                           "\u26C5",
	}

	windIcons = map[string]string{
		"N":   "\u2193",
		"S":   "\u2191",
		"E":   "\u2190",
		"W":   "\u2192",
		"NE":  "\u2199",
		"NNE": "\u2199",
		"NEE": "\u2199",
		"ENE": "\u2199",
		"NW":  "\u2198",
		"NNW": "\u2198",
		"NWW": "\u2198",
		"WNW": "\u2198",
		"SE":  "\u2196",
		"SEE": "\u2196",
		"SSE": "\u2196",
		"ESE": "\u2196",
		"SW":  "\u2197",
		"SSW": "\u2197",
		"SWW": "\u2197",
		"WSW": "\u2197",
	}
)

func printHeader(wd weatherdata.WeatherData) {
	hStr := fmt.Sprintf("%s / %s", wd.Location.Country, wd.Location.Name)
	hStr = fmt.Sprintf("%s | %s %s %s %s %s (%.1f hours)\n", hStr, icons["Clear sky"], windIcons["S"], wd.Sun.Rise.Local().Format("15:04"), windIcons["N"], wd.Sun.Set.Local().Format("15:04"), wd.SunHours())
	fmt.Println(hStr)
}

func printFooter(wd weatherdata.WeatherData) {
	fmt.Println(fmt.Sprintf("Forecast issued %.1f hours ago, next update in %.1f hours", wd.Meta.HoursSinceUpdate(), wd.Meta.HoursToNextUpdate()))
	fmt.Println(fmt.Sprintf("\n%s.\n%s", wd.Credit.Text, wd.Credit.URL))
}

func printForecast(wd weatherdata.WeatherData, days int) {
	forecasts := make(map[string][]weatherdata.WeatherForecast)
	for i := range wd.Forecast {
		// Should maybe be typecasted to int?
		forecasts[wd.Forecast[i].From.Format("20060102")] = append(forecasts[wd.Forecast[i].From.Format("20060102")], wd.Forecast[i])
	}

	mk := make([]string, len(forecasts))
	i := 0
	for k := range forecasts {
		mk[i] = k
		i++
	}

	sort.Strings(mk)

	for i := 0; i < days; i++ {
		var wStr string
		fmt.Println(forecasts[mk[i]][0].From.Format("January 02 (Monday):"))
		for _, w := range forecasts[mk[i]] {
			wStr = fmt.Sprintf(" %s %s    \U0001f321 %d%s    \u2602  %.1fmm", w.PeriodName(), icons[w.Symbol.Name], w.Temperature.Value, "\u2103", w.Precipitation.Value)
			wStr = fmt.Sprintf("%s    \U0001f32C  %.1f m/s %s", wStr, w.WindSpeed.Mps, windIcons[w.WindDirection.Code])
			fmt.Println(wStr)
		}
		fmt.Println("")
	}
}

func loadConfig() (Configuration, error) {
	configuration := Configuration{}

	usr, err := user.Current()
	if err != nil {
		return configuration, err
	}

	cfile := path.Join(usr.HomeDir, ".woozy")

	file, err := os.Open(cfile)
	if err != nil {
		fmt.Println(fmt.Sprintf("Configuration file not found, creating a example in %s..", cfile))
		out, err := os.Create(cfile)
		if err != nil {
			panic(err)
		}
		defer out.Close()
		configuration.Place = "Sweden/Västerbotten/Estersmark"
		configuration.Days = 3
		configjson, err := json.MarshalIndent(configuration, "", "\t")
		ioutil.WriteFile(cfile, configjson, 0600)
		fmt.Println(".. edit it and restart woozy")
		os.Exit(1)
	}

	decoder := json.NewDecoder(file)

	err = decoder.Decode(&configuration)

	if err != nil {
		return configuration, err
	}

	return configuration, nil

}

func main() {
	configuration, err := loadConfig()

	if err != nil {
		panic(err)
	}

	cc := flag.Bool("cache-clear", false, "Force cache clear")
	days := flag.Int("days", 3, "Number of days to print")
	flag.Parse()

	wd, err := weatherdata.LoadWeatherData(configuration.Place, *cc)
	if err != nil {
		panic(err)
	}

	if configuration.Days == 0 {
		configuration.Days = *days
	}

	printHeader(wd)
	printForecast(wd, configuration.Days)
	printFooter(wd)

}
<|endoftext|>