<commit_before>package openstack

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools"
)

func resourceMemberV2() *schema.Resource {
	return &schema.Resource{
		Create: resourceMemberV2Create,
		Read:   resourceMemberV2Read,
		Update: resourceMemberV2Update,
		Delete: resourceMemberV2Delete,

		Schema: map[string]*schema.Schema{
			"region": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""),
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"tenant_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"address": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"protocol_port": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"weight": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(int)
					if value < 1 {
						errors = append(errors, fmt.Errorf(
							"Only numbers greater than 0 are supported values for 'weight'"))
					}
					return
				},
			},

			"subnet_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"admin_state_up": &schema.Schema{
				Type:     schema.TypeBool,
				Default:  true,
				Optional: true,
			},

			"pool_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
		},
	}
}

func resourceMemberV2Create(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	adminStateUp := d.Get("admin_state_up").(bool)
	createOpts := pools.CreateMemberOpts{
		Name:         d.Get("name").(string),
		TenantID:     d.Get("tenant_id").(string),
		Address:      d.Get("address").(string),
		ProtocolPort: d.Get("protocol_port").(int),
		Weight:       d.Get("weight").(int),
		AdminStateUp: &adminStateUp,
	}

	// Must omit if not set
	if v, ok := d.GetOk("subnet_id"); ok {
		createOpts.SubnetID = v.(string)
	}

	poolID := d.Get("pool_id").(string)

	log.Printf("[DEBUG] Create Options: %#v", createOpts)

	var member *pools.Member
	err = resource.Retry(10*time.Minute, func() *resource.RetryError {
		var err error
		log.Printf("[DEBUG] Attempting to create LBaaSV2 member")
		member, err = pools.CreateMember(networkingClient, poolID, createOpts).Extract()
		if err != nil {
			if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok {
				if errCode.Actual == 409 || errCode.Actual == 500 {
					log.Printf("[DEBUG] OpenStack LBaaSV2 member is still creating.")
					return resource.RetryableError(err)
				}
			}
			return resource.NonRetryableError(err)
		}

		return nil
	})

	if err != nil {
		return fmt.Errorf("Error creating OpenStack LBaaSV2 member: %s", err)
	}
	log.Printf("[INFO] member ID: %s", member.ID)

	log.Printf("[DEBUG] Waiting for Openstack LBaaSV2 member (%s) to become available.", member.ID)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"PENDING_CREATE"},
		Target:     []string{"ACTIVE"},
		Refresh:    waitForMemberActive(networkingClient, poolID, member.ID),
		Timeout:    2 * time.Minute,
		Delay:      5 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return err
	}

	d.SetId(member.ID)

	return resourceMemberV2Read(d, meta)
}

func resourceMemberV2Read(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	member, err := pools.GetMember(networkingClient, d.Get("pool_id").(string), d.Id()).Extract()
	if err != nil {
		return CheckDeleted(d, err, "LBV2 Member")
	}

	log.Printf("[DEBUG] Retrieved OpenStack LBaaSV2 Member %s: %+v", d.Id(), member)

	d.Set("name", member.Name)
	d.Set("weight", member.Weight)
	d.Set("admin_state_up", member.AdminStateUp)
	d.Set("tenant_id", member.TenantID)
	d.Set("subnet_id", member.SubnetID)
	d.Set("address", member.Address)
	d.Set("protocol_port", member.ProtocolPort)
	d.Set("id", member.ID)

	return nil
}

func resourceMemberV2Update(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	var updateOpts pools.UpdateMemberOpts
	if d.HasChange("name") {
		updateOpts.Name = d.Get("name").(string)
	}
	if d.HasChange("weight") {
		updateOpts.Weight = d.Get("weight").(int)
	}
	if d.HasChange("admin_state_up") {
		asu := d.Get("admin_state_up").(bool)
		updateOpts.AdminStateUp = &asu
	}

	log.Printf("[DEBUG] Updating OpenStack LBaaSV2 Member %s with options: %+v", d.Id(), updateOpts)

	_, err = pools.UpdateMember(networkingClient, d.Get("pool_id").(string), d.Id(), updateOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error updating OpenStack LBaaSV2 Member: %s", err)
	}

	return resourceMemberV2Read(d, meta)
}

func resourceMemberV2Delete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"ACTIVE", "PENDING_DELETE"},
		Target:     []string{"DELETED"},
		Refresh:    waitForMemberDelete(networkingClient, d.Get("pool_id").(string), d.Id()),
		Timeout:    2 * time.Minute,
		Delay:      5 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack LBaaSV2 Member: %s", err)
	}

	d.SetId("")
	return nil
}

func waitForMemberActive(networkingClient *gophercloud.ServiceClient, poolID string, memberID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		member, err := pools.GetMember(networkingClient, poolID, memberID).Extract()
		if err != nil {
			return nil, "", err
		}

		// The member resource has no Status attribute, so a successful Get is the best we can do
		log.Printf("[DEBUG] OpenStack LBaaSV2 Member: %+v", member)
		return member, "ACTIVE", nil
	}
}

func waitForMemberDelete(networkingClient *gophercloud.ServiceClient, poolID string, memberID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		log.Printf("[DEBUG] Attempting to delete OpenStack LBaaSV2 Member %s", memberID)

		member, err := pools.GetMember(networkingClient, poolID, memberID).Extract()
		if err != nil {
			if _, ok := err.(gophercloud.ErrDefault404); ok {
				log.Printf("[DEBUG] Successfully deleted OpenStack LBaaSV2 Member %s", memberID)
				return member, "DELETED", nil
			}
			return member, "ACTIVE", err
		}

		log.Printf("[DEBUG] Openstack LBaaSV2 Member: %+v", member)
		err = pools.DeleteMember(networkingClient, poolID, memberID).ExtractErr()
		if err != nil {
			if _, ok := err.(gophercloud.ErrDefault404); ok {
				log.Printf("[DEBUG] Successfully deleted OpenStack LBaaSV2 Member %s", memberID)
				return member, "DELETED", nil
			}

			if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok {
				if errCode.Actual == 409 {
					log.Printf("[DEBUG] OpenStack LBaaSV2 Member (%s) is still in use.", memberID)
					return member, "PENDING_DELETE", nil
				}
			}

			return member, "ACTIVE", err
		}

		log.Printf("[DEBUG] OpenStack LBaaSV2 Member %s still active.", memberID)
		return member, "ACTIVE", nil
	}
}
<commit_msg>Check for ErrDefault500 when creating/deleting pool member (#12664)<commit_after>package openstack

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools"
)

func resourceMemberV2() *schema.Resource {
	return &schema.Resource{
		Create: resourceMemberV2Create,
		Read:   resourceMemberV2Read,
		Update: resourceMemberV2Update,
		Delete: resourceMemberV2Delete,

		Schema: map[string]*schema.Schema{
			"region": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""),
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"tenant_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"address": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"protocol_port": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"weight": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(int)
					if value < 1 {
						errors = append(errors, fmt.Errorf(
							"Only numbers greater than 0 are supported values for 'weight'"))
					}
					return
				},
			},

			"subnet_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"admin_state_up": &schema.Schema{
				Type:     schema.TypeBool,
				Default:  true,
				Optional: true,
			},

			"pool_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
		},
	}
}

func resourceMemberV2Create(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	adminStateUp := d.Get("admin_state_up").(bool)
	createOpts := pools.CreateMemberOpts{
		Name:         d.Get("name").(string),
		TenantID:     d.Get("tenant_id").(string),
		Address:      d.Get("address").(string),
		ProtocolPort: d.Get("protocol_port").(int),
		Weight:       d.Get("weight").(int),
		AdminStateUp: &adminStateUp,
	}

	// Must omit if not set
	if v, ok := d.GetOk("subnet_id"); ok {
		createOpts.SubnetID = v.(string)
	}

	poolID := d.Get("pool_id").(string)

	log.Printf("[DEBUG] Create Options: %#v", createOpts)

	var member *pools.Member
	err = resource.Retry(10*time.Minute, func() *resource.RetryError {
		var err error
		log.Printf("[DEBUG] Attempting to create LBaaSV2 member")
		member, err = pools.CreateMember(networkingClient, poolID, createOpts).Extract()
		if err != nil {
			switch errCode := err.(type) {
			case gophercloud.ErrDefault500:
				log.Printf("[DEBUG] OpenStack LBaaSV2 member is still creating.")
				return resource.RetryableError(err)
			case gophercloud.ErrUnexpectedResponseCode:
				if errCode.Actual == 409 {
					log.Printf("[DEBUG] OpenStack LBaaSV2 member is still creating.")
					return resource.RetryableError(err)
				}

			default:
				return resource.NonRetryableError(err)
			}
		}
		return nil
	})

	if err != nil {
		return fmt.Errorf("Error creating OpenStack LBaaSV2 member: %s", err)
	}
	log.Printf("[INFO] member ID: %s", member.ID)

	log.Printf("[DEBUG] Waiting for Openstack LBaaSV2 member (%s) to become available.", member.ID)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"PENDING_CREATE"},
		Target:     []string{"ACTIVE"},
		Refresh:    waitForMemberActive(networkingClient, poolID, member.ID),
		Timeout:    2 * time.Minute,
		Delay:      5 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return err
	}

	d.SetId(member.ID)

	return resourceMemberV2Read(d, meta)
}

func resourceMemberV2Read(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	member, err := pools.GetMember(networkingClient, d.Get("pool_id").(string), d.Id()).Extract()
	if err != nil {
		return CheckDeleted(d, err, "LBV2 Member")
	}

	log.Printf("[DEBUG] Retrieved OpenStack LBaaSV2 Member %s: %+v", d.Id(), member)

	d.Set("name", member.Name)
	d.Set("weight", member.Weight)
	d.Set("admin_state_up", member.AdminStateUp)
	d.Set("tenant_id", member.TenantID)
	d.Set("subnet_id", member.SubnetID)
	d.Set("address", member.Address)
	d.Set("protocol_port", member.ProtocolPort)
	d.Set("id", member.ID)

	return nil
}

func resourceMemberV2Update(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	var updateOpts pools.UpdateMemberOpts
	if d.HasChange("name") {
		updateOpts.Name = d.Get("name").(string)
	}
	if d.HasChange("weight") {
		updateOpts.Weight = d.Get("weight").(int)
	}
	if d.HasChange("admin_state_up") {
		asu := d.Get("admin_state_up").(bool)
		updateOpts.AdminStateUp = &asu
	}

	log.Printf("[DEBUG] Updating OpenStack LBaaSV2 Member %s with options: %+v", d.Id(), updateOpts)

	_, err = pools.UpdateMember(networkingClient, d.Get("pool_id").(string), d.Id(), updateOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error updating OpenStack LBaaSV2 Member: %s", err)
	}

	return resourceMemberV2Read(d, meta)
}

func resourceMemberV2Delete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"ACTIVE", "PENDING_DELETE"},
		Target:     []string{"DELETED"},
		Refresh:    waitForMemberDelete(networkingClient, d.Get("pool_id").(string), d.Id()),
		Timeout:    2 * time.Minute,
		Delay:      5 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack LBaaSV2 Member: %s", err)
	}

	d.SetId("")
	return nil
}

func waitForMemberActive(networkingClient *gophercloud.ServiceClient, poolID string, memberID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		member, err := pools.GetMember(networkingClient, poolID, memberID).Extract()
		if err != nil {
			return nil, "", err
		}

		// The member resource has no Status attribute, so a successful Get is the best we can do
		log.Printf("[DEBUG] OpenStack LBaaSV2 Member: %+v", member)
		return member, "ACTIVE", nil
	}
}

func waitForMemberDelete(networkingClient *gophercloud.ServiceClient, poolID string, memberID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		log.Printf("[DEBUG] Attempting to delete OpenStack LBaaSV2 Member %s", memberID)

		member, err := pools.GetMember(networkingClient, poolID, memberID).Extract()
		if err != nil {
			if _, ok := err.(gophercloud.ErrDefault404); ok {
				log.Printf("[DEBUG] Successfully deleted OpenStack LBaaSV2 Member %s", memberID)
				return member, "DELETED", nil
			}
			return member, "ACTIVE", err
		}

		log.Printf("[DEBUG] Openstack LBaaSV2 Member: %+v", member)
		err = pools.DeleteMember(networkingClient, poolID, memberID).ExtractErr()
		if err != nil {
			switch errCode := err.(type) {
			case gophercloud.ErrDefault404:
				log.Printf("[DEBUG] Successfully deleted OpenStack LBaaSV2 Member %s", memberID)
				return member, "DELETED", nil
			case gophercloud.ErrDefault500:
				log.Printf("[DEBUG] OpenStack LBaaSV2 Member (%s) is still in use.", memberID)
				return member, "PENDING_DELETE", nil
			case gophercloud.ErrUnexpectedResponseCode:
				if errCode.Actual == 409 {
					log.Printf("[DEBUG] OpenStack LBaaSV2 Member (%s) is still in use.", memberID)
					return member, "PENDING_DELETE", nil
				}

			default:
				return member, "ACTIVE", err
			}
		}

		log.Printf("[DEBUG] OpenStack LBaaSV2 Member %s still active.", memberID)
		return member, "ACTIVE", nil
	}
}
<|endoftext|>


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

package reverseproxy

import (
	"encoding/json"
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/caddyconfig"
	"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
	caddycmd "github.com/caddyserver/caddy/v2/cmd"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp/headers"
	"github.com/mholt/certmagic"
)

func init() {
	caddycmd.RegisterCommand(caddycmd.Command{
		Name:  "reverse-proxy",
		Func:  cmdReverseProxy,
		Usage: "[--from <addr>] [--to <addr>]",
		Short: "A quick and production-ready reverse proxy",
		Long: `
A simple but production-ready reverse proxy. Useful for quick deployments,
demos, and development.

Simply shuttles HTTP traffic from the --from address to the --to address.

If the --from address has a domain name, Caddy will attempt to serve the
proxy over HTTPS with a certificate.
`,
		Flags: func() *flag.FlagSet {
			fs := flag.NewFlagSet("file-server", flag.ExitOnError)
			fs.String("from", "", "Address to receive traffic on")
			fs.String("to", "", "Upstream address to proxy traffic to")
			return fs
		}(),
	})
}

func cmdReverseProxy(fs caddycmd.Flags) (int, error) {
	from := fs.String("from")
	to := fs.String("to")

	if from == "" {
		from = "localhost:" + httpcaddyfile.DefaultPort
	}

	// URLs need a scheme in order to parse successfully
	if !strings.Contains(from, "://") {
		from = "http://" + from
	}
	if !strings.Contains(to, "://") {
		to = "http://" + to
	}

	fromURL, err := url.Parse(from)
	if err != nil {
		return caddy.ExitCodeFailedStartup, fmt.Errorf("parsing 'from' URL: %v", err)
	}
	toURL, err := url.Parse(to)
	if err != nil {
		return caddy.ExitCodeFailedStartup, fmt.Errorf("parsing 'to' URL: %v", err)
	}

	if toURL.Port() == "" {
		toPort := "80"
		if toURL.Scheme == "https" {
			toPort = "443"
		}
		toURL.Host = net.JoinHostPort(toURL.Host, toPort)
	}

	ht := HTTPTransport{}
	if toURL.Scheme == "https" {
		ht.TLS = new(TLSConfig)
	}

	handler := Handler{
		TransportRaw: caddyconfig.JSONModuleObject(ht, "protocol", "http", nil),
		Upstreams:    UpstreamPool{{Dial: toURL.Host}},
		Headers: &headers.Handler{
			Request: &headers.HeaderOps{
				Set: http.Header{
					"Host": []string{"{http.reverse_proxy.upstream.host}"},
				},
			},
		},
	}

	route := caddyhttp.Route{
		HandlersRaw: []json.RawMessage{
			caddyconfig.JSONModuleObject(handler, "handler", "reverse_proxy", nil),
		},
	}
	urlHost := fromURL.Hostname()
	if urlHost != "" {
		route.MatcherSetsRaw = []caddy.ModuleMap{
			caddy.ModuleMap{
				"host": caddyconfig.JSON(caddyhttp.MatchHost{urlHost}, nil),
			},
		}
	}

	listen := ":80"
	if urlPort := fromURL.Port(); urlPort != "" {
		listen = ":" + urlPort
	} else if certmagic.HostQualifies(urlHost) {
		listen = ":443"
	}

	server := &caddyhttp.Server{
		Routes: caddyhttp.RouteList{route},
		Listen: []string{listen},
	}

	httpApp := caddyhttp.App{
		Servers: map[string]*caddyhttp.Server{"proxy": server},
	}

	cfg := &caddy.Config{
		Admin: &caddy.AdminConfig{Disabled: true},
		AppsRaw: caddy.ModuleMap{
			"http": caddyconfig.JSON(httpApp, nil),
		},
	}

	err = caddy.Run(cfg)
	if err != nil {
		return caddy.ExitCodeFailedStartup, err
	}

	fmt.Printf("Caddy 2 proxying from %s to %s\n", fromURL, toURL)

	select {}
}
<commit_msg>cmd/reverse_proxy: Add --change-host-header flag<commit_after>// Copyright 2015 Matthew Holt and The Caddy Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package reverseproxy

import (
	"encoding/json"
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/caddyconfig"
	"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
	caddycmd "github.com/caddyserver/caddy/v2/cmd"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp/headers"
	"github.com/mholt/certmagic"
)

func init() {
	caddycmd.RegisterCommand(caddycmd.Command{
		Name:  "reverse-proxy",
		Func:  cmdReverseProxy,
		Usage: "[--from <addr>] [--to <addr>] [--change-host-header]",
		Short: "A quick and production-ready reverse proxy",
		Long: `
A simple but production-ready reverse proxy. Useful for quick deployments,
demos, and development.

Simply shuttles HTTP traffic from the --from address to the --to address.

If the --from address has a domain name, Caddy will attempt to serve the
proxy over HTTPS with a certificate.

If --change-host-header is set, the Host header on the request will be modified
from its original incoming value to the address of the upstream. (Otherwise, by
default, all incoming headers are passed through unmodified.)
`,
		Flags: func() *flag.FlagSet {
			fs := flag.NewFlagSet("file-server", flag.ExitOnError)
			fs.String("from", "", "Address on which to receive traffic")
			fs.String("to", "", "Upstream address to which to to proxy traffic")
			fs.Bool("change-host-header", false, "Set upstream Host header to address of upstream")
			return fs
		}(),
	})
}

func cmdReverseProxy(fs caddycmd.Flags) (int, error) {
	from := fs.String("from")
	to := fs.String("to")
	changeHost := fs.Bool("change-host-header")

	if from == "" {
		from = "localhost:" + httpcaddyfile.DefaultPort
	}

	// URLs need a scheme in order to parse successfully
	if !strings.Contains(from, "://") {
		from = "http://" + from
	}
	if !strings.Contains(to, "://") {
		to = "http://" + to
	}

	fromURL, err := url.Parse(from)
	if err != nil {
		return caddy.ExitCodeFailedStartup, fmt.Errorf("parsing 'from' URL: %v", err)
	}
	toURL, err := url.Parse(to)
	if err != nil {
		return caddy.ExitCodeFailedStartup, fmt.Errorf("parsing 'to' URL: %v", err)
	}

	if toURL.Port() == "" {
		toPort := "80"
		if toURL.Scheme == "https" {
			toPort = "443"
		}
		toURL.Host = net.JoinHostPort(toURL.Host, toPort)
	}

	ht := HTTPTransport{}
	if toURL.Scheme == "https" {
		ht.TLS = new(TLSConfig)
	}

	handler := Handler{
		TransportRaw: caddyconfig.JSONModuleObject(ht, "protocol", "http", nil),
		Upstreams:    UpstreamPool{{Dial: toURL.Host}},
	}

	if changeHost {
		handler.Headers = &headers.Handler{
			Request: &headers.HeaderOps{
				Set: http.Header{
					"Host": []string{"{http.reverse_proxy.upstream.hostport}"},
				},
			},
		}
	}

	route := caddyhttp.Route{
		HandlersRaw: []json.RawMessage{
			caddyconfig.JSONModuleObject(handler, "handler", "reverse_proxy", nil),
		},
	}
	urlHost := fromURL.Hostname()
	if urlHost != "" {
		route.MatcherSetsRaw = []caddy.ModuleMap{
			caddy.ModuleMap{
				"host": caddyconfig.JSON(caddyhttp.MatchHost{urlHost}, nil),
			},
		}
	}

	listen := ":80"
	if urlPort := fromURL.Port(); urlPort != "" {
		listen = ":" + urlPort
	} else if certmagic.HostQualifies(urlHost) {
		listen = ":443"
	}

	server := &caddyhttp.Server{
		Routes: caddyhttp.RouteList{route},
		Listen: []string{listen},
	}

	httpApp := caddyhttp.App{
		Servers: map[string]*caddyhttp.Server{"proxy": server},
	}

	cfg := &caddy.Config{
		Admin: &caddy.AdminConfig{Disabled: true},
		AppsRaw: caddy.ModuleMap{
			"http": caddyconfig.JSON(httpApp, nil),
		},
	}

	err = caddy.Run(cfg)
	if err != nil {
		return caddy.ExitCodeFailedStartup, err
	}

	fmt.Printf("Caddy 2 proxying from %s to %s\n", fromURL, toURL)

	select {}
}
<|endoftext|>


<commit_before>package jwp

type ApiMeta struct {
	SessionId string `json:"sessionId,omitempty"`
	Status    int    `json:"status,omitempty"`
}

type ApiServerStatusBuild struct {
	Version  string `json:"version,omitempty"`
	Revision string `json:"revision,omitempty"`
	Time     string `json:"time,omitempty"`
}

type ApiServerStatusOS struct {
	Arch    string `json:"arch,omitempty"`
	Name    string `json:"name,omitempty"`
	Version string `json:"version,omitempty"`
}

type ApiServerStatus struct {
	ApiMeta `json:",inline"`
	Value   struct {
		ApiServerStatusBuild `json:"build,omitempty"`
		ApiServerStatusOS    `json:"os,omitempty"`
	} `json:"value"`
}

type ApiCapabilities struct {
	BrowserName              string `json:"browserName"`
	Version                  string `json:"version"`
	DriverName               string `json:"driverName"`
	DriverVersion            string `json:"driverVersion"`
	Platform                 string `json:"platform"`
	JavascriptEnabled        bool   `json:"javascriptEnabled"`
	TakesScreenshot          bool   `json:"takesScreenshot"`
	HandlesAlerts            bool   `json:"handlesAlerts"`
	DatabaseEnabled          bool   `json:"databaseEnabled"`
	LocationContextEnabled   bool   `json:"locationContextEnabled"`
	ApplicationCacheEnabled  bool   `json:"applicationCacheEnabled"`
	BrowserConnectionEnabled bool   `json:"browserConnectionEnabled"`
	CSSSelectorsEnabled      bool   `json:"cssSelectorsEnabled"`
	WebStorageEnabled        bool   `json:"webStorageEnabled"`
	Rotatable                bool   `json:"rotatable"`
	AcceptSslCerts           bool   `json:"acceptSslCerts"`
	NativeEvents             bool   `json:"nativeEvents"`
	Proxy                    `json:"proxy"`

	// special
	UserAgent string `json:"phantomjs.page.settings.userAgent,omitempty"`
}
type Proxy struct {
	/* direct - A direct connection - no proxy in use,
	 * manual - Manual proxy settings configured, e.g. setting a proxy for HTTP, a proxy for FTP, etc,
	 * pac - Proxy autoconfiguration from a URL, autodetect - Proxy autodetection, probably with WPAD,
	 * system - Use system settings
	 */
	ProxyType string `json:"proxyType,omitempty"`

	// Required if proxyType == pac, Ignored otherwise) Specifies the URL to be used for proxy autoconfiguration
	ProxyAutoconfigUrl string `json:"proxyAutoconfigUrl,omitempty"`

	/* (Optional, Ignored if proxyType != manual) Specifies the proxies to be used for FTP, HTTP, HTTPS and SOCKS requests respectively.
	 * Behaviour is undefined if a request is made, where the proxy for the particular protocol is undefined, if proxyType is manual.
	 * Expected format example: hostname.com:1234
	 */
	FtpProxy   string `json:"ftpProxy,omitempty"`
	HttpProxy  string `json:"httpProxy,omitempty"`
	SslProxy   string `json:"sslProxy,omitempty"`
	SocksProxy string `json:"socksProxy,omitempty"`

	SocksUsername string `json:"socksUsername,omitempty"`
	SocksPassword string `json:"socksPassword,omitempty"`

	// Specifies proxy bypass addresses. Format is driver specific.
	NoProxy string `json:"noProxy,omitempty"`
}

type ApiSession struct {
	ApiMeta `json:",inline"`
	Value   ApiCapabilities `json:"value"`
}

type DesiredCapabilities struct {
	UserAgent       string `json:"phantomjs.page.settings.userAgent,omitempty"`
	TakesScreenshot bool   `json:"takesScreenshot,omitempty"`
	Proxy           Proxy  `json:"proxy,omitempty"`
}

type ApiDesiredCapabilities struct {
	DesiredCapabilities `json:"desiredCapabilities,omitempty"`
}

type SessionItem struct {
	Id           string          `json:"id"`
	Capabilities ApiCapabilities `json:"capabilities"`
}

type ApiSessions struct {
	ApiMeta `json:",inline"`
	Value   []SessionItem `json:"value"`
}

type WindowSize struct {
	Height int `json:"height"`
	Width  int `json:"width"`
}

type ApiWindowSize struct {
	ApiMeta `json:",inline"`
	Value   WindowSize `json:"value"`
}

type PageURL struct {
	URL string `json:"url"`
}

type ApiURL struct {
	ApiMeta `json:",inline"`
	Value   string `json:"value"`
}
<commit_msg>Define ExecuteScript.<commit_after>package jwp

type ApiMeta struct {
	SessionId string `json:"sessionId,omitempty"`
	Status    int    `json:"status,omitempty"`
}

type ApiServerStatusBuild struct {
	Version  string `json:"version,omitempty"`
	Revision string `json:"revision,omitempty"`
	Time     string `json:"time,omitempty"`
}

type ApiServerStatusOS struct {
	Arch    string `json:"arch,omitempty"`
	Name    string `json:"name,omitempty"`
	Version string `json:"version,omitempty"`
}

type ApiServerStatus struct {
	ApiMeta `json:",inline"`
	Value   struct {
		ApiServerStatusBuild `json:"build,omitempty"`
		ApiServerStatusOS    `json:"os,omitempty"`
	} `json:"value"`
}

type ApiCapabilities struct {
	BrowserName              string `json:"browserName"`
	Version                  string `json:"version"`
	DriverName               string `json:"driverName"`
	DriverVersion            string `json:"driverVersion"`
	Platform                 string `json:"platform"`
	JavascriptEnabled        bool   `json:"javascriptEnabled"`
	TakesScreenshot          bool   `json:"takesScreenshot"`
	HandlesAlerts            bool   `json:"handlesAlerts"`
	DatabaseEnabled          bool   `json:"databaseEnabled"`
	LocationContextEnabled   bool   `json:"locationContextEnabled"`
	ApplicationCacheEnabled  bool   `json:"applicationCacheEnabled"`
	BrowserConnectionEnabled bool   `json:"browserConnectionEnabled"`
	CSSSelectorsEnabled      bool   `json:"cssSelectorsEnabled"`
	WebStorageEnabled        bool   `json:"webStorageEnabled"`
	Rotatable                bool   `json:"rotatable"`
	AcceptSslCerts           bool   `json:"acceptSslCerts"`
	NativeEvents             bool   `json:"nativeEvents"`
	Proxy                    `json:"proxy"`

	// special
	UserAgent string `json:"phantomjs.page.settings.userAgent,omitempty"`
}
type Proxy struct {
	/* direct - A direct connection - no proxy in use,
	 * manual - Manual proxy settings configured, e.g. setting a proxy for HTTP, a proxy for FTP, etc,
	 * pac - Proxy autoconfiguration from a URL, autodetect - Proxy autodetection, probably with WPAD,
	 * system - Use system settings
	 */
	ProxyType string `json:"proxyType,omitempty"`

	// Required if proxyType == pac, Ignored otherwise) Specifies the URL to be used for proxy autoconfiguration
	ProxyAutoconfigUrl string `json:"proxyAutoconfigUrl,omitempty"`

	/* (Optional, Ignored if proxyType != manual) Specifies the proxies to be used for FTP, HTTP, HTTPS and SOCKS requests respectively.
	 * Behaviour is undefined if a request is made, where the proxy for the particular protocol is undefined, if proxyType is manual.
	 * Expected format example: hostname.com:1234
	 */
	FtpProxy   string `json:"ftpProxy,omitempty"`
	HttpProxy  string `json:"httpProxy,omitempty"`
	SslProxy   string `json:"sslProxy,omitempty"`
	SocksProxy string `json:"socksProxy,omitempty"`

	SocksUsername string `json:"socksUsername,omitempty"`
	SocksPassword string `json:"socksPassword,omitempty"`

	// Specifies proxy bypass addresses. Format is driver specific.
	NoProxy string `json:"noProxy,omitempty"`
}

type ApiSession struct {
	ApiMeta `json:",inline"`
	Value   ApiCapabilities `json:"value"`
}

type DesiredCapabilities struct {
	UserAgent       string `json:"phantomjs.page.settings.userAgent,omitempty"`
	TakesScreenshot bool   `json:"takesScreenshot,omitempty"`
	Proxy           Proxy  `json:"proxy,omitempty"`
}

type ApiDesiredCapabilities struct {
	DesiredCapabilities `json:"desiredCapabilities,omitempty"`
}

type SessionItem struct {
	Id           string          `json:"id"`
	Capabilities ApiCapabilities `json:"capabilities"`
}

type ApiSessions struct {
	ApiMeta `json:",inline"`
	Value   []SessionItem `json:"value"`
}

type WindowSize struct {
	Height int `json:"height"`
	Width  int `json:"width"`
}

type ApiWindowSize struct {
	ApiMeta `json:",inline"`
	Value   WindowSize `json:"value"`
}

type PageURL struct {
	URL string `json:"url"`
}

type ApiURL struct {
	ApiMeta `json:",inline"`
	Value   string `json:"value"`
}

type ExecuteScript struct {
	Script string                   `json:"script"`
	Args   []map[string]interface{} `json:"args"`
}
<|endoftext|>


<commit_before>package oauth2

import (
	"encoding/json"
	"net/url"
	"strings"
)

type GrantType string

func (t GrantType) String() string {
	return string(t)
}

func (t GrantType) Password() bool {
	return t == "password"
}

func (t GrantType) ClientCredentials() bool {
	return t == "client_credentials"
}

func (t GrantType) AuthorizationCode() bool {
	return t == "authorization_code"
}

func (t GrantType) RefreshToken() bool {
	return t == "refresh_token"
}

func (t GrantType) Known() bool {
	return t.Password() || t.ClientCredentials() ||
		t.AuthorizationCode() || t.RefreshToken()
}

func (t GrantType) Extension() bool {
	_, err := url.ParseRequestURI(string(t))
	return err == nil
}

type Scope []string

func ParseScope(str string) Scope {
	// split string
	list := strings.Split(str, " ")

	// prepare result
	var res []string

	// process items
	for _, item := range list {
		// trim whitespace
		item = strings.TrimSpace(item)

		if item != "" {
			res = append(res, item)
		}
	}

	return Scope(res)
}

func (s Scope) Contains(str string) bool {
	for _, i := range s {
		if i == str {
			return true
		}
	}

	return false
}

func (s Scope) Includes(scope Scope) bool {
	for _, i := range scope {
		if !s.Contains(i) {
			return false
		}
	}

	return true
}

func (s Scope) String() string {
	return strings.Join(s, " ")
}

func (s Scope) MarshalJSON() ([]byte, error) {
	return json.Marshal(s.String())
}

type ResponseType string

func (t ResponseType) String() string {
	return string(t)
}

func (t ResponseType) Token() bool {
	return t == "token"
}

func (t ResponseType) Code() bool {
	return t == "code"
}

func (t ResponseType) Known() bool {
	return t.Token() || t.Code()
}
<commit_msg>more docs<commit_after>package oauth2

import (
	"encoding/json"
	"net/url"
	"strings"
)

// A GrantType is typically received in a token request.
type GrantType string

// Strings implements the fmt.Stringer interface.
func (t GrantType) String() string {
	return string(t)
}

// Password returns true if the grant type is a password grant type.
func (t GrantType) Password() bool {
	return t == "password"
}

// ClientCredentials returns true if the grant type is a client credentials
// grant type.
func (t GrantType) ClientCredentials() bool {
	return t == "client_credentials"
}

// AuthorizationCode returns true if the grant type is a authorization code
// grant type.
func (t GrantType) AuthorizationCode() bool {
	return t == "authorization_code"
}

// RefreshToken returns true if the grant type is a refresh token grant type.
func (t GrantType) RefreshToken() bool {
	return t == "refresh_token"
}

// Known returns true if the grant type is a known grant type (e.g. password,
// client credentials, authorization code or refresh token).
func (t GrantType) Known() bool {
	return t.Password() || t.ClientCredentials() ||
		t.AuthorizationCode() || t.RefreshToken()
}

// Extension returns true if the grant type is valid extension grant type.
func (t GrantType) Extension() bool {
	_, err := url.ParseRequestURI(string(t))
	return err == nil
}

// A Scope is received typically in an authorization and token request.
type Scope []string

// ParseScope parses the joined string representation of a scope.
func ParseScope(str string) Scope {
	// split string
	list := strings.Split(str, " ")

	// prepare result
	var res []string

	// process items
	for _, item := range list {
		// trim whitespace
		item = strings.TrimSpace(item)

		if item != "" {
			res = append(res, item)
		}
	}

	return Scope(res)
}

// Contains returns true if the specified string is part of the scope.
func (s Scope) Contains(str string) bool {
	for _, i := range s {
		if i == str {
			return true
		}
	}

	return false
}

// Includes returns true if the specified scope is included in this scope.
func (s Scope) Includes(scope Scope) bool {
	for _, i := range scope {
		if !s.Contains(i) {
			return false
		}
	}

	return true
}

// String implements the fmt.Stringer interface.
func (s Scope) String() string {
	return strings.Join(s, " ")
}

// MarshalJSON implements the json.Marshaler interface.
func (s Scope) MarshalJSON() ([]byte, error) {
	return json.Marshal(s.String())
}

// A ResponseType is typically received in an authorization request.
type ResponseType string

// String implements the fmt.Stringer interface.
func (t ResponseType) String() string {
	return string(t)
}

// Token returns true if the response type is a token response type.
func (t ResponseType) Token() bool {
	return t == "token"
}

// Code returns true if the response type is a code response type.
func (t ResponseType) Code() bool {
	return t == "code"
}

// Known returns true if the response type is a known response type (e.g. token,
// or code).
func (t ResponseType) Known() bool {
	return t.Token() || t.Code()
}
<|endoftext|>


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

// Package maps contains TODO(brettmorgan)
//
// More information about Google Distance Matrix API is available on
// https://developers.google.com/maps/documentation/distancematrix/
package maps // import "google.golang.org/maps"
import "time"

const (
	// ModeDriving is for specifying driving as travel mode
	ModeDriving = "driving"
	// ModeWalking is for specifying walking as travel mode
	ModeWalking = "walking"
	// ModeBicycling is for specifying bicycling as travel mode
	ModeBicycling = "bicycling"
	// ModeTransit is for specifying transit as travel mode
	ModeTransit = "transit"

	// AvoidTolls is for specifying routes that avoid tolls
	AvoidTolls = "tolls"
	// AvoidHighways is for specifying routes that avoid highways
	AvoidHighways = "highways"
	// AvoidFerries is for specifying routes that avoid ferries
	AvoidFerries = "ferries"

	// UnitsMetric specifies usage of the metric units system
	UnitsMetric = "metric"
	// UnitsImperial specifies usage of the Imperial (English) units system
	UnitsImperial = "imperial"

	// TransitModeBus is for specifying a transit mode of bus
	TransitModeBus = "bus"
	// TransitModeSubway is for specifying a transit mode of subway
	TransitModeSubway = "subway"
	// TransitModeTrain is for specifying a transit mode of train
	TransitModeTrain = "train"
	// TransitModeTram is for specifying a transit mode of tram
	TransitModeTram = "tram"
	// TransitModeRail is for specifying a transit mode of rail
	TransitModeRail = "rail"

	// TransitRoutingPreferenceLessWalking indicates that the calculated route should prefer limited amounts of walking
	TransitRoutingPreferenceLessWalking = "less_walking"
	// TransitRoutingPreferenceFewerTransfers indicates that the calculated route should prefer a limited number of transfers
	TransitRoutingPreferenceFewerTransfers = "fewer_transfers"
)

// DistanceMatrixRequest is the functional options struct for DistanceMatrixGet
type DistanceMatrixRequest struct {
	Origins                  []string
	Destinations             []string
	Mode                     string
	Language                 string
	Avoid                    string
	Units                    string
	DepartureTime            string
	ArrivalTime              string
	TransitMode              string
	TransitRoutingPreference string
}

// DistanceMatrixResponse represents a Distance Matrix API response.
type DistanceMatrixResponse struct {

	// OriginAddresses contains an array of addresses as returned by the API from your original request.
	OriginAddresses []string `json:"origin_addresses"`
	// DestinationAddresses contains an array of addresses as returned by the API from your original request.
	DestinationAddresses []string `json:"destination_addresses"`
	// Rows contains an array of elements.
	Rows []DistanceMatrixElementsRow `json:"rows"`

	// Status contains the status of the request, and may contain
	// debugging information to help you track down why the Directions
	// service failed.
	// See https://developers.google.com/maps/documentation/distancematrix/#StatusCodes
	Status string `json:"status"`

	// ErrorMessage is the explanatory field added when Status is an error.
	ErrorMessage string `json:"error_message"`
}

// DistanceMatrixElementsRow is a row of distance elements.
type DistanceMatrixElementsRow struct {
	Elements []*DistanceMatrixElement `json:"elements"`
}

// DistanceMatrixElement is the travel distance and time for a pair of origin and destination.
type DistanceMatrixElement struct {
	Status   string        `json:"status"`
	Duration time.Duration `json:"duration"`
	Distance Distance      `json:"distance"`
}

// Distance is the API representation for a distance between two points.
type Distance struct {
	// Text is the distance in a human displayable form. The style of display can be changed by setting `units`.
	Text string `json:"text"`
	// Value is the distance in meters.
	Value int `json:"value"`
}
<commit_msg>Adding docs<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package maps contains TODO(brettmorgan)
//
// More information about Google Distance Matrix API is available on
// https://developers.google.com/maps/documentation/distancematrix/
package maps // import "google.golang.org/maps"
import "time"

const (
	// ModeDriving is for specifying driving as travel mode
	ModeDriving = "driving"
	// ModeWalking is for specifying walking as travel mode
	ModeWalking = "walking"
	// ModeBicycling is for specifying bicycling as travel mode
	ModeBicycling = "bicycling"
	// ModeTransit is for specifying transit as travel mode
	ModeTransit = "transit"

	// AvoidTolls is for specifying routes that avoid tolls
	AvoidTolls = "tolls"
	// AvoidHighways is for specifying routes that avoid highways
	AvoidHighways = "highways"
	// AvoidFerries is for specifying routes that avoid ferries
	AvoidFerries = "ferries"

	// UnitsMetric specifies usage of the metric units system
	UnitsMetric = "metric"
	// UnitsImperial specifies usage of the Imperial (English) units system
	UnitsImperial = "imperial"

	// TransitModeBus is for specifying a transit mode of bus
	TransitModeBus = "bus"
	// TransitModeSubway is for specifying a transit mode of subway
	TransitModeSubway = "subway"
	// TransitModeTrain is for specifying a transit mode of train
	TransitModeTrain = "train"
	// TransitModeTram is for specifying a transit mode of tram
	TransitModeTram = "tram"
	// TransitModeRail is for specifying a transit mode of rail
	TransitModeRail = "rail"

	// TransitRoutingPreferenceLessWalking indicates that the calculated route should prefer limited amounts of walking
	TransitRoutingPreferenceLessWalking = "less_walking"
	// TransitRoutingPreferenceFewerTransfers indicates that the calculated route should prefer a limited number of transfers
	TransitRoutingPreferenceFewerTransfers = "fewer_transfers"
)

// DistanceMatrixRequest is the functional options struct for DistanceMatrixGet
type DistanceMatrixRequest struct {
	// Origins is a list of addresses and/or textual latitude/longitude values from which to calculate distance and time. Required.
	Origins []string
	// Destinations is a list of addresses and/or textual latitude/longitude values to which to calculate distance and time. Required.
	Destinations []string
	// Mode specifies the mode of transport to use when calculating distance. Valid values are `ModeDriving`, `ModeWalking`, `ModeBicycling`
	// and `ModeTransit`. Optional.
	Mode string
	// Language in which to return results. Optional.
	Language string
	// Avoid introduces restrictions to the route. Valid values are `AvoidTolls`, `AvoidHighways` and `AvoidFerries`. Optional.
	Avoid string
	// Units Specifies the unit system to use when expressing distance as text. Valid values are `UnitsMetric` and `UnitsImperial`. Optional.
	Units string
	// DepartureTime is the desired time of departure. You can specify the time as an integer in seconds since midnight, January 1, 1970 UTC.
	// Alternatively, you can specify a value of `"now"``. Optional.
	DepartureTime string
	// ArrivalTime specifies the desired time of arrival for transit requests, in seconds since midnight, January 1, 1970 UTC. You cannot
	// specify both `DepartureTime` and `ArrivalTime`. Optional.
	ArrivalTime string
	// TransitMode specifies one or more preferred modes of transit. This parameter may only be specified for requests where the mode is
	// `transit`. Valid values are `TransitModeBus`, `TransitModeSubway`, `TransitModeTrain`, `TransitModeTram`, and `TransitModeRail`.
	// Optional.
	TransitMode string
	// TransitRoutingPreference Specifies preferences for transit requests. Valid values are `TransitRoutingPreferenceLessWalking` and
	// `TransitRoutingPreferenceFewerTransfers`. Optional.
	TransitRoutingPreference string
}

// DistanceMatrixResponse represents a Distance Matrix API response.
type DistanceMatrixResponse struct {

	// OriginAddresses contains an array of addresses as returned by the API from your original request.
	OriginAddresses []string `json:"origin_addresses"`
	// DestinationAddresses contains an array of addresses as returned by the API from your original request.
	DestinationAddresses []string `json:"destination_addresses"`
	// Rows contains an array of elements.
	Rows []DistanceMatrixElementsRow `json:"rows"`

	// Status contains the status of the request, and may contain
	// debugging information to help you track down why the Directions
	// service failed.
	// See https://developers.google.com/maps/documentation/distancematrix/#StatusCodes
	Status string `json:"status"`

	// ErrorMessage is the explanatory field added when Status is an error.
	ErrorMessage string `json:"error_message"`
}

// DistanceMatrixElementsRow is a row of distance elements.
type DistanceMatrixElementsRow struct {
	Elements []*DistanceMatrixElement `json:"elements"`
}

// DistanceMatrixElement is the travel distance and time for a pair of origin and destination.
type DistanceMatrixElement struct {
	Status string `json:"status"`
	// Duration is the length of time it takes to travel this route.
	Duration time.Duration `json:"duration"`
	// Distance is the total distance of this route.
	Distance Distance `json:"distance"`
}

// Distance is the API representation for a distance between two points.
type Distance struct {
	// Text is the distance in a human displayable form. The style of display can be changed by setting `units`.
	Text string `json:"text"`
	// Value is the distance in meters.
	Value int `json:"value"`
}
<|endoftext|>


<commit_before>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package optimize

import (
	"fmt"
	"math"
	"time"
)

// EvaluationType is used by the optimizer to specify information needed from
// the objective function.
type EvaluationType int

const (
	NoEvaluation EvaluationType = iota
	FunctionEval
	GradientEval
	FunctionAndGradientEval
)

func (e EvaluationType) String() string {
	if e < 0 || int(e) >= len(evaluationStrings) {
		return fmt.Sprintf("EvaluationType(%d)", e)
	}
	return evaluationStrings[e]
}

var evaluationStrings = [...]string{
	"NoEvaluation",
	"FunctionEval",
	"GradientEval",
	"FunctionAndGradientEval",
}

// IterationType specifies the type of iteration.
type IterationType int

const (
	NoIteration IterationType = iota
	MajorIteration
	MinorIteration
	SubIteration
	PostIteration // Iteration after the optimization. Sent to Recorder.
)

func (i IterationType) String() string {
	return iterationStrings[i]
}

var iterationStrings = [...]string{
	"NoIteration",
	"MajorIteration",
	"MinorIteration",
	"SubIteration",
	"PostIteration",
}

// Location represents a location in the optimization procedure.
type Location struct {
	X        []float64
	F        float64
	Gradient []float64
}

// LinesearchLocation is a location for a linesearch subiteration
type LinesearchLocation struct {
	F          float64 // Function value at the step
	Derivative float64 // Projected gradient in the linesearch direction
}

// Result represents the answer of an optimization run. It contains the optimum
// location as well as the Status at convergence and Statistics taken during the
// run.
type Result struct {
	Location
	Stats
	Status Status
}

// Stats contains the statistics of the run.
type Stats struct {
	MajorIterations       int           // Total number of major iterations
	FunctionEvals         int           // Number of evaluations of F()
	GradientEvals         int           // Number of evaluations of Df()
	FunctionGradientEvals int           // Number of evaluations of FDf()
	Runtime               time.Duration // Total runtime of the optimization
}

// FunctionInfo is data to give to the optimizer about the objective function.
type FunctionInfo struct {
	IsGradient         bool
	IsFunctionGradient bool
	IsStatuser         bool
}

// functions contains the actual methods of F that have been successfully type
// switched
type functions struct {
	function Function
	gradient Gradient
	gradFunc FunctionGradient
	status   Statuser
}

// Settings represents settings of the optimization run. It contains initial
// settings, convergence information, and Recorder information. In general, users
// should use DefaultSettings() rather than constructing a Settings literal.
//
// If UseInitData is true, InitialFunctionValue and InitialGradient specify
// function information at the initial location.
//
// If Recorder is nil, no information will be recorded.
type Settings struct {
	UseInitialData       bool      // Use supplied information about the conitions at the initial x.
	InitialFunctionValue float64   // F(x) at the initial x.
	InitialGradient      []float64 // Df(x) at the initial x.

	// Converge if the objective function is less than this value.
	FunctionAbsTol float64

	// Loosely, converge if the 'average' value of the gradient is less than this
	// value. Specifically, converge if ||grad||_2 / sqrt(len(grad)) is less than
	// this value.
	// Has no effect if gradient information is not used.
	GradientAbsTol float64

	// Converge if the number of major iterations equals or exceeds this value.
	// If it equals zero, this setting has no effect.
	MajorIterations int

	// Converge if the duration of the run is longer than this value. Runtime
	// is only checked at iterations of the optimizer. If it equals zero,
	// this setting has no effect.
	Runtime time.Duration

	// Converge if the total number of function evaluations equals or exceeds this
	// number. Calls to F() and FDf() are both counted as function evaluations
	// for this calculation. If it equals zero, this setting has no effect.
	FunctionEvals int

	// Converge if the total number of gradient evaluations equals or exceeds this
	// number. Calls to D() and FDf() are both counted as gradient evaluations
	// for this calculation. If it equals zero, this setting has no effect.
	GradientEvals int

	Recorder Recorder
}

// DefaultSettings returns a new Settings struct containing the default settings.
func DefaultSettings() *Settings {
	return &Settings{
		GradientAbsTol: 1e-6,
		FunctionAbsTol: math.Inf(-1),
		Recorder:       NewPrinter(),
	}
}

// resize takes x and returns a slice of length dim.
// It returns a resliced x if cap(x) >= dim, and a new
// slice otherwies
func resize(x []float64, dim int) []float64 {
	if dim > cap(x) {
		return make([]float64, dim)
	}
	return x[:dim]
}
<commit_msg>Handle invalid iteration in IterationType.String()<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package optimize

import (
	"fmt"
	"math"
	"time"
)

// EvaluationType is used by the optimizer to specify information needed from
// the objective function.
type EvaluationType int

const (
	NoEvaluation EvaluationType = iota
	FunctionEval
	GradientEval
	FunctionAndGradientEval
)

func (e EvaluationType) String() string {
	if e < 0 || int(e) >= len(evaluationStrings) {
		return fmt.Sprintf("EvaluationType(%d)", e)
	}
	return evaluationStrings[e]
}

var evaluationStrings = [...]string{
	"NoEvaluation",
	"FunctionEval",
	"GradientEval",
	"FunctionAndGradientEval",
}

// IterationType specifies the type of iteration.
type IterationType int

const (
	NoIteration IterationType = iota
	MajorIteration
	MinorIteration
	SubIteration
	PostIteration // Iteration after the optimization. Sent to Recorder.
)

func (i IterationType) String() string {
	if i < 0 || int(i) >= len(iterationStrings) {
		return fmt.Sprintf("IterationType(%d)", i)
	}
	return iterationStrings[i]
}

var iterationStrings = [...]string{
	"NoIteration",
	"MajorIteration",
	"MinorIteration",
	"SubIteration",
	"PostIteration",
}

// Location represents a location in the optimization procedure.
type Location struct {
	X        []float64
	F        float64
	Gradient []float64
}

// LinesearchLocation is a location for a linesearch subiteration
type LinesearchLocation struct {
	F          float64 // Function value at the step
	Derivative float64 // Projected gradient in the linesearch direction
}

// Result represents the answer of an optimization run. It contains the optimum
// location as well as the Status at convergence and Statistics taken during the
// run.
type Result struct {
	Location
	Stats
	Status Status
}

// Stats contains the statistics of the run.
type Stats struct {
	MajorIterations       int           // Total number of major iterations
	FunctionEvals         int           // Number of evaluations of F()
	GradientEvals         int           // Number of evaluations of Df()
	FunctionGradientEvals int           // Number of evaluations of FDf()
	Runtime               time.Duration // Total runtime of the optimization
}

// FunctionInfo is data to give to the optimizer about the objective function.
type FunctionInfo struct {
	IsGradient         bool
	IsFunctionGradient bool
	IsStatuser         bool
}

// functions contains the actual methods of F that have been successfully type
// switched
type functions struct {
	function Function
	gradient Gradient
	gradFunc FunctionGradient
	status   Statuser
}

// Settings represents settings of the optimization run. It contains initial
// settings, convergence information, and Recorder information. In general, users
// should use DefaultSettings() rather than constructing a Settings literal.
//
// If UseInitData is true, InitialFunctionValue and InitialGradient specify
// function information at the initial location.
//
// If Recorder is nil, no information will be recorded.
type Settings struct {
	UseInitialData       bool      // Use supplied information about the conitions at the initial x.
	InitialFunctionValue float64   // F(x) at the initial x.
	InitialGradient      []float64 // Df(x) at the initial x.

	// Converge if the objective function is less than this value.
	FunctionAbsTol float64

	// Loosely, converge if the 'average' value of the gradient is less than this
	// value. Specifically, converge if ||grad||_2 / sqrt(len(grad)) is less than
	// this value.
	// Has no effect if gradient information is not used.
	GradientAbsTol float64

	// Converge if the number of major iterations equals or exceeds this value.
	// If it equals zero, this setting has no effect.
	MajorIterations int

	// Converge if the duration of the run is longer than this value. Runtime
	// is only checked at iterations of the optimizer. If it equals zero,
	// this setting has no effect.
	Runtime time.Duration

	// Converge if the total number of function evaluations equals or exceeds this
	// number. Calls to F() and FDf() are both counted as function evaluations
	// for this calculation. If it equals zero, this setting has no effect.
	FunctionEvals int

	// Converge if the total number of gradient evaluations equals or exceeds this
	// number. Calls to D() and FDf() are both counted as gradient evaluations
	// for this calculation. If it equals zero, this setting has no effect.
	GradientEvals int

	Recorder Recorder
}

// DefaultSettings returns a new Settings struct containing the default settings.
func DefaultSettings() *Settings {
	return &Settings{
		GradientAbsTol: 1e-6,
		FunctionAbsTol: math.Inf(-1),
		Recorder:       NewPrinter(),
	}
}

// resize takes x and returns a slice of length dim.
// It returns a resliced x if cap(x) >= dim, and a new
// slice otherwies
func resize(x []float64, dim int) []float64 {
	if dim > cap(x) {
		return make([]float64, dim)
	}
	return x[:dim]
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	concurrent = flag.Int("j", runtime.NumCPU(), "number of concurrent")
	timeout    = flag.Int64("timeout", 10, "timeout second for HTTP request")
)

var (
	errRedirectNotFollowed = errors.New("redirection not followed")
)

var httpClient = &http.Client{
	CheckRedirect: func(req *http.Request, via []*http.Request) error {
		return errRedirectNotFollowed
	},
	Timeout: time.Duration(*timeout * int64(time.Second)),
}

type responseSet struct {
	res    *http.Response
	urlStr string
}

func main() {
	flag.Parse()

	var stock []*responseSet
	var m sync.Mutex
	enq := make(chan string, *concurrent)
	printq := make(chan string, *concurrent)
	stockq := make(chan bool, *concurrent)
	waitingq := make(chan bool, *concurrent)
	quitq := make(chan bool)
	eof := false

	go func() {
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			urlStr := strings.TrimRight(scanner.Text(), "\n")
			printq <- urlStr

			enq <- urlStr
			go func() {
				urlStr := <-enq
				waitingq <- true
				res, _ := fetch(urlStr)
				m.Lock()
				stock = append(stock, &responseSet{res: res, urlStr: urlStr})
				m.Unlock()
				<-waitingq
				stockq <- true
			}()
		}
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
		}
		eof = true
	}()

	go func() {
		for {
			urlStr := <-printq
		L:
			for {
				for i, set := range stock {
					if set.urlStr == urlStr {
						fmt.Fprintf(os.Stdout, "%s\t%s\n", edit(set.res), set.urlStr)
						m.Lock()
						stock = append(stock[:i], stock[i+1:]...)
						m.Unlock()
						if eof && len(waitingq) == 0 && len(stock) == 0 {
							quitq <- true
						}
						break L
					}
				}
				<-stockq
			}
		}
	}()

	<-quitq
}

func fetch(urlStr string) (*http.Response, error) {
	res, err := httpClient.Head(urlStr)
	if err != nil {
		ue, ok := err.(*url.Error)
		if ok {
			if ue.Err == errRedirectNotFollowed {
				// ignore
			} else {
				return nil, err
			}
		} else {
			return nil, err
		}
	}
	return res, nil
}

func edit(res *http.Response) string {
	if res == nil {
		return "???"
	}
	// TODO Implement other style
	return strconv.Itoa(res.StatusCode)
}
<commit_msg>Speed up when parallel run<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	concurrent = flag.Int("j", runtime.NumCPU(), "number of concurrent")
	timeout    = flag.Int64("timeout", 10, "timeout second for HTTP request")
)

var (
	errRedirectNotFollowed = errors.New("redirection not followed")
)

var customTransport http.RoundTripper = &http.Transport{
	Proxy: http.ProxyFromEnvironment,
	Dial: (&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}).Dial,
	TLSHandshakeTimeout: 10 * time.Second,
	MaxIdleConnsPerHost: 3 * http.DefaultMaxIdleConnsPerHost,
}

var httpClient = &http.Client{
	Transport: customTransport,
	CheckRedirect: func(req *http.Request, via []*http.Request) error {
		return errRedirectNotFollowed
	},
	Timeout: time.Duration(*timeout * int64(time.Second)),
}

type responseSet struct {
	res    *http.Response
	urlStr string
}

func main() {
	flag.Parse()

	var stock []*responseSet
	var m sync.Mutex
	enq := make(chan string, *concurrent)
	printq := make(chan string, *concurrent)
	stockq := make(chan bool, *concurrent)
	waitingq := make(chan bool, *concurrent)
	quitq := make(chan bool)
	eof := false

	go func() {
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			urlStr := strings.TrimRight(scanner.Text(), "\n")
			printq <- urlStr

			enq <- urlStr
			go func() {
				urlStr := <-enq
				waitingq <- true
				res, _ := fetch(urlStr)
				m.Lock()
				stock = append(stock, &responseSet{res: res, urlStr: urlStr})
				m.Unlock()
				<-waitingq
				stockq <- true
			}()
		}
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
		}
		eof = true
	}()

	go func() {
		for {
			urlStr := <-printq
		L:
			for {
				for i, set := range stock {
					if set.urlStr == urlStr {
						fmt.Fprintf(os.Stdout, "%s\t%s\n", edit(set.res), set.urlStr)
						m.Lock()
						stock = append(stock[:i], stock[i+1:]...)
						m.Unlock()
						if eof && len(waitingq) == 0 && len(stock) == 0 {
							quitq <- true
						}
						break L
					}
				}
				<-stockq
			}
		}
	}()

	<-quitq
}

func fetch(urlStr string) (*http.Response, error) {
	res, err := httpClient.Head(urlStr)
	if err != nil {
		ue, ok := err.(*url.Error)
		if ok {
			if ue.Err == errRedirectNotFollowed {
				// ignore
			} else {
				return nil, err
			}
		} else {
			return nil, err
		}
	}
	return res, nil
}

func edit(res *http.Response) string {
	if res == nil {
		return "???"
	}
	// TODO Implement other style
	return strconv.Itoa(res.StatusCode)
}
<|endoftext|>


<commit_before>// +build !darwin,!dragonfly,!freebsd,!linux,!nacl,!netbsd,!openbsd,!solaris

package main

// Return the server name, version number and description
func banner() string {
	return "\n" + version_string + "\nHTTP/2 web server\n\n"
}
<commit_msg>Minor change<commit_after>// +build !darwin,!dragonfly,!freebsd,!linux,!nacl,!netbsd,!openbsd,!solaris

package main

// Return the server name, version number and description
func banner() string {
	return "\n" + version_string + "\nHTTP/2 web server\n"
}
<|endoftext|>


<commit_before>package meritop

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/coreos/go-etcd/etcd"
)

const (
	parentIndicator string = "parent"
	childIndicator  string = "child"
)

// This interface is used by application during taskgraph configuration phase.
type Bootstrap interface {
	// These allow application developer to set the task configuration so framework
	// implementation knows which task to invoke at each node.
	SetTaskBuilder(taskBuilder TaskBuilder)

	// This allow the application to specify how tasks are connection at each epoch
	SetTopology(topology Topology)

	// After all the configure is done, driver need to call start so that all
	// nodes will get into the event loop to run the application.
	Start()
}

// Note that framework can decide how update can be done, and how to serve the updatelog.
type BackedUpFramework interface {
	// Ask framework to do update on this update on this task, which consists
	// of one primary and some backup copies.
	Update(taskID uint64, log UpdateLog)
}

type Framework interface {
	// These two are useful for task to inform the framework their status change.
	// metaData has to be really small, since it might be stored in etcd.
	// Flags that parent/child's metadata of the current task is ready.
	FlagParentMetaReady(meta string)
	FlagChildMetaReady(meta string)

	// This allow the task implementation query its neighbors.
	GetTopology() Topology

	// Some task can inform all participating tasks to exit.
	Exit()

	// Some task can inform all participating tasks to new epoch
	SetEpoch(epoch uint64)

	GetLogger() log.Logger

	// Request data from parent or children.
	DataRequest(toID uint64, meta string)

	// This is used to figure out taskid for current node
	GetTaskID() uint64
}

type framework struct {
	// These should be passed by outside world
	name     string
	etcdURLs []string

	// user defined interfaces
	task     Task
	topology Topology

	taskID       uint64
	epoch        uint64
	etcdClient   *etcd.Client
	stops        []chan bool
	dataPort     string            // ":xxxx"
	addressMap   map[uint64]string // taskId -> node address. Maybe in etcd later.
	dataRespChan chan *dataResponse
}

type dataResponse struct {
	taskID uint64
	req    string
	data   []byte
}

func (f *framework) parentOrChild(taskID uint64) string {
	for _, id := range f.topology.GetParents(f.epoch) {
		if taskID == id {
			return parentIndicator
		}
	}

	for _, id := range f.topology.GetChildren(f.epoch) {
		if taskID == id {
			return childIndicator
		}
	}
	return ""
}

func (f *framework) start() {
	f.etcdClient = etcd.NewClient(f.etcdURLs)
	f.topology.SetTaskID(f.taskID)
	f.epoch = 0
	f.stops = make([]chan bool, 0)
	f.dataRespChan = make(chan *dataResponse, 100)

	// setup etcd watches
	// - create self's parent and child meta flag
	// - watch parents' child meta flag
	// - watch children's parent meta flag
	f.etcdClient.Create(MakeParentMetaPath(f.name, f.GetTaskID()), "", 0)
	f.etcdClient.Create(MakeChildMetaPath(f.name, f.GetTaskID()), "", 0)
	parentStops := f.watchAll(parentIndicator, f.topology.GetParents(f.epoch))
	childStops := f.watchAll(childIndicator, f.topology.GetChildren(f.epoch))

	f.stops = append(f.stops, parentStops...)
	f.stops = append(f.stops, childStops...)

	// setup listening port for data requests
	go func() {
		// TODO: setup handlers
		http.ListenAndServe(f.dataPort, nil)
	}()
	// setup event loop for data responses
	go func() {
		for {
			dataResp := <-f.dataRespChan

			var dataReady func(uint64, string, []byte)
			switch f.parentOrChild(dataResp.taskID) {
			case parentIndicator:
				dataReady = f.task.ParentDataReady
			case childIndicator:
				dataReady = f.task.ChildDataReady
			default:
				panic("unimplemented")
			}

			go dataReady(dataResp.taskID, dataResp.req, dataResp.data)
		}
	}()

	// After framework init finished, it should init task.
	f.task.SetEpoch(f.epoch)
	f.task.Init(f.taskID, f, nil)
}

func (f *framework) stop() {
	for _, c := range f.stops {
		close(c)
	}
}

func (f *framework) FlagParentMetaReady(meta string) {
	f.etcdClient.Set(
		MakeParentMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) FlagChildMetaReady(meta string) {
	f.etcdClient.Set(
		MakeChildMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) SetEpoch(epoch uint64) {
	f.epoch = epoch
}

func (f *framework) watchAll(who string, taskIDs []uint64) []chan bool {
	stops := make([]chan bool, len(taskIDs))

	for i, taskID := range taskIDs {
		receiver := make(chan *etcd.Response, 10)
		stop := make(chan bool, 1)
		stops[i] = stop

		var watchPath string
		var taskCallback func(uint64, string)
		switch who {
		case parentIndicator:
			// Watch parent's child.
			watchPath = MakeChildMetaPath(f.name, taskID)
			taskCallback = f.task.ParentMetaReady
		case childIndicator:
			// Watch child's parent.
			watchPath = MakeParentMetaPath(f.name, taskID)
			taskCallback = f.task.ChildMetaReady
		default:
			panic("unimplemented")
		}

		go f.etcdClient.Watch(watchPath, 0, false, receiver, stop)
		go func(receiver <-chan *etcd.Response, taskID uint64) {
			for {
				resp, ok := <-receiver
				if !ok {
					return
				}
				if resp.Action != "set" {
					continue
				}
				taskCallback(taskID, resp.Node.Value)
			}
		}(receiver, taskID)
	}
	return stops
}

func (f *framework) DataRequest(toID uint64, req string) {
	// getAddressFromTaskID
	addr, ok := f.addressMap[toID]
	if !ok {
		log.Fatalf("ID = %d not found", toID)
		return
	}
	url := fmt.Sprintf("http://%s%s", addr,
		// it passes self taskID in url to tell the other side
		MakeDataRequestPath(f.taskID, req))
	// send request
	// pass the response to the awaiting event loop for data response
	go func(url string) {
		resp, err := http.Get(url)
		if err != nil {
			log.Fatalf("http.Get(%s) returns error: %v", url, err)
		}
		if resp.StatusCode != 200 {
			log.Fatalf("response code = %d, assume = %d", resp.StatusCode, 200)
		}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatalf("ioutil.ReadAll(%v) returns error: %v", resp.Body, err)
		}
		dataResp := &dataResponse{
			taskID: toID,
			req:    req,
			data:   data,
		}
		f.dataRespChan <- dataResp
	}(url)
}

func (f *framework) GetTopology() Topology {
	panic("unimplemented")
}

func (f *framework) Exit() {
}

func (f *framework) GetLogger() log.Logger {
	panic("unimplemented")
}

func (f *framework) GetTaskID() uint64 {
	return f.taskID
}
<commit_msg>framework: refactor, naming<commit_after>package meritop

import (
	"io/ioutil"
	"log"
	"net/http"
	"net/url"

	"github.com/coreos/go-etcd/etcd"
)

const (
	taskParent string = "parent"
	taskChild  string = "child"
)

// This interface is used by application during taskgraph configuration phase.
type Bootstrap interface {
	// These allow application developer to set the task configuration so framework
	// implementation knows which task to invoke at each node.
	SetTaskBuilder(taskBuilder TaskBuilder)

	// This allow the application to specify how tasks are connection at each epoch
	SetTopology(topology Topology)

	// After all the configure is done, driver need to call start so that all
	// nodes will get into the event loop to run the application.
	Start()
}

// Note that framework can decide how update can be done, and how to serve the updatelog.
type BackedUpFramework interface {
	// Ask framework to do update on this update on this task, which consists
	// of one primary and some backup copies.
	Update(taskID uint64, log UpdateLog)
}

type Framework interface {
	// These two are useful for task to inform the framework their status change.
	// metaData has to be really small, since it might be stored in etcd.
	// Flags that parent/child's metadata of the current task is ready.
	FlagParentMetaReady(meta string)
	FlagChildMetaReady(meta string)

	// This allow the task implementation query its neighbors.
	GetTopology() Topology

	// Some task can inform all participating tasks to exit.
	Exit()

	// Some task can inform all participating tasks to new epoch
	SetEpoch(epoch uint64)

	GetLogger() log.Logger

	// Request data from parent or children.
	DataRequest(toID uint64, meta string)

	// This is used to figure out taskid for current node
	GetTaskID() uint64
}

type framework struct {
	// These should be passed by outside world
	name     string
	etcdURLs []string

	// user defined interfaces
	task     Task
	topology Topology

	taskID       uint64
	epoch        uint64
	etcdClient   *etcd.Client
	stops        []chan bool
	dataPort     string            // ":xxxx"
	addressMap   map[uint64]string // taskId -> node address. Maybe in etcd later.
	dataRespChan chan *dataResponse
}

type dataResponse struct {
	taskID uint64
	req    string
	data   []byte
}

func (f *framework) parentOrChild(taskID uint64) string {
	for _, id := range f.topology.GetParents(f.epoch) {
		if taskID == id {
			return taskParent
		}
	}

	for _, id := range f.topology.GetChildren(f.epoch) {
		if taskID == id {
			return taskChild
		}
	}
	return ""
}

func (f *framework) start() {
	f.etcdClient = etcd.NewClient(f.etcdURLs)
	f.topology.SetTaskID(f.taskID)
	f.epoch = 0
	f.stops = make([]chan bool, 0)
	f.dataRespChan = make(chan *dataResponse, 100)

	// setup etcd watches
	// - create self's parent and child meta flag
	// - watch parents' child meta flag
	// - watch children's parent meta flag
	f.etcdClient.Create(MakeParentMetaPath(f.name, f.GetTaskID()), "", 0)
	f.etcdClient.Create(MakeChildMetaPath(f.name, f.GetTaskID()), "", 0)
	parentStops := f.watchAll(taskParent, f.topology.GetParents(f.epoch))
	childStops := f.watchAll(taskChild, f.topology.GetChildren(f.epoch))
	f.stops = append(f.stops, parentStops...)
	f.stops = append(f.stops, childStops...)

	go f.startHttpServerForDataRequest()
	go f.dataResponseEventLoop()

	// After framework init finished, it should init task.
	f.task.SetEpoch(f.epoch)
	f.task.Init(f.taskID, f, nil)
}

// Framework http server for data request.
// Each request will be in the format: "/datareq/{taskID}/{req}".
// "taskID" indicates the requesting task. "req" is the meta data for this request.
// On success, it should respond with requested data in http body.
func (f *framework) startHttpServerForDataRequest() {
	// setup handlers
	http.ListenAndServe(f.dataPort, nil)
}

// Framework event loop handles data response for requests sent in DataRequest().
func (f *framework) dataResponseEventLoop() {
	for {
		dataResp := <-f.dataRespChan

		var dataReady func(uint64, string, []byte)
		switch f.parentOrChild(dataResp.taskID) {
		case taskParent:
			dataReady = f.task.ParentDataReady
		case taskChild:
			dataReady = f.task.ChildDataReady
		default:
			panic("unimplemented")
		}

		go dataReady(dataResp.taskID, dataResp.req, dataResp.data)
	}
}

func (f *framework) stop() {
	for _, c := range f.stops {
		close(c)
	}
}

func (f *framework) FlagParentMetaReady(meta string) {
	f.etcdClient.Set(
		MakeParentMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) FlagChildMetaReady(meta string) {
	f.etcdClient.Set(
		MakeChildMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) SetEpoch(epoch uint64) {
	f.epoch = epoch
}

func (f *framework) watchAll(who string, taskIDs []uint64) []chan bool {
	stops := make([]chan bool, len(taskIDs))

	for i, taskID := range taskIDs {
		receiver := make(chan *etcd.Response, 10)
		stop := make(chan bool, 1)
		stops[i] = stop

		var watchPath string
		var taskCallback func(uint64, string)
		switch who {
		case taskParent:
			// Watch parent's child.
			watchPath = MakeChildMetaPath(f.name, taskID)
			taskCallback = f.task.ParentMetaReady
		case taskChild:
			// Watch child's parent.
			watchPath = MakeParentMetaPath(f.name, taskID)
			taskCallback = f.task.ChildMetaReady
		default:
			panic("unimplemented")
		}

		go f.etcdClient.Watch(watchPath, 0, false, receiver, stop)
		go func(receiver <-chan *etcd.Response, taskID uint64) {
			for {
				resp, ok := <-receiver
				if !ok {
					return
				}
				if resp.Action != "set" {
					continue
				}
				taskCallback(taskID, resp.Node.Value)
			}
		}(receiver, taskID)
	}
	return stops
}

func (f *framework) DataRequest(toID uint64, req string) {
	// getAddressFromTaskID
	addr, ok := f.addressMap[toID]
	if !ok {
		log.Fatalf("ID = %d not found", toID)
		return
	}
	u := url.URL{
		Scheme: "http",
		Host:   addr,
		Path:   MakeDataRequestPath(f.taskID, req),
	}
	urlStr := u.String()
	// send request
	// pass the response to the awaiting event loop for data response
	go func(urlStr string) {
		resp, err := http.Get(urlStr)
		if err != nil {
			log.Fatalf("http.Get(%s) returns error: %v", urlStr, err)
		}
		if resp.StatusCode != 200 {
			log.Fatalf("response code = %d, assume = %d", resp.StatusCode, 200)
		}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatalf("ioutil.ReadAll(%v) returns error: %v", resp.Body, err)
		}
		dataResp := &dataResponse{
			taskID: toID,
			req:    req,
			data:   data,
		}
		f.dataRespChan <- dataResp
	}(urlStr)
}

func (f *framework) GetTopology() Topology {
	panic("unimplemented")
}

func (f *framework) Exit() {
}

func (f *framework) GetLogger() log.Logger {
	panic("unimplemented")
}

func (f *framework) GetTaskID() uint64 {
	return f.taskID
}
<|endoftext|>


<commit_before>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package main

import (
	"bytes"
	"database/sql"
	"encoding/binary"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/fiorix/go-redis/redis"
	"github.com/fiorix/go-web/httpxtra"
	_ "github.com/mattn/go-sqlite3"
)

const (
	// API limits
	maxrequests = 10000
	expire      = 3600

	// Server settings
	debug      = true
	addr       = ":8080"            // ip:port or /path/to/unix.sock
	redisaddr  = "127.0.0.1:6379"   // redis server
	staticpath = "./static"         // public website
	ipdb       = "./db/ipdb.sqlite" // geoip database
)

func main() {
	http.Handle("/", http.FileServer(http.Dir(staticpath)))
	h := GeoipHandler()
	http.HandleFunc("/csv/", h)
	http.HandleFunc("/xml/", h)
	http.HandleFunc("/json/", h)
	server := http.Server{
		Addr:         addr,
		Handler:      httpxtra.Handler{Logger: logger},
		ReadTimeout:  15 * time.Second,
		WriteTimeout: 15 * time.Second,
	}
	log.Println("FreeGeoIP server starting")
	if e := httpxtra.ListenAndServe(server); e != nil {
		log.Println(e.Error())
	}
}

func logger(r *http.Request, created time.Time, status, bytes int) {
	//fmt.Println(httpxtra.ApacheCommonLog(r, created, status, bytes))
	log.Printf("HTTP %d %s %s (%s) :: %s",
		status,
		r.Method,
		r.URL.Path,
		r.RemoteAddr,
		time.Since(created))
}

// GeoipHandler handles GET on /csv, /xml and /json.
func GeoipHandler() http.HandlerFunc {
	db, err := sql.Open("sqlite3", ipdb)
	if err != nil {
		panic(err)
	}
	rc := redis.New(redisaddr)
	return func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case "GET":
			w.Header().Set("Access-Control-Allow-Origin", "*")
		case "OPTIONS":
			w.Header().Set("Access-Control-Allow-Origin", "*")
			w.Header().Set("Content-Type", "text/plain")
			w.Header().Set("Access-Control-Allow-Methods", "GET")
			w.Header().Set("Access-Control-Allow-Headers",
				"X-Requested-With")
			return
		default:
			w.Header().Set("Allow", "GET, OPTIONS")
			http.Error(w, http.StatusText(405), 405)
			return
		}
		// GET
		// Check quota
		var ipkey string
		if ip, _, err := net.SplitHostPort(r.RemoteAddr); err != nil {
			ipkey = r.RemoteAddr // support for XHeaders
		} else {
			ipkey = ip
		}
		if qcs, err := rc.Get(ipkey); err != nil {
			http.Error(w, http.StatusText(503), 503) // redis down
			return
		} else if qcs == "" {
			if err := rc.Set(ipkey, "1"); err == nil {
				rc.Expire(ipkey, expire)
			}
		} else if qc, _ := strconv.Atoi(qcs); qc < maxrequests {
			rc.Incr(ipkey)
		} else {
			// Out of quota, soz :(
			http.Error(w, http.StatusText(403), 403)
			return
		}
		// Parse URL and build the query.
		var ip string
		a := strings.SplitN(r.URL.Path, "/", 3)
		if len(a) == 3 && a[2] != "" {
			// e.g. /csv/google.com
			addrs, err := net.LookupHost(a[2])
			if err != nil {
				http.Error(w, http.StatusText(404), 404)
				return
			}
			ip = addrs[0]
		} else {
			ip = ipkey
		}
		geoip, err := GeoipLookup(db, ip)
		if err != nil {
			http.NotFound(w, r)
			return
		}
		switch a[1] {
		case "csv":
			w.Header().Set("Content-Type", "application/csv")
			fmt.Fprintf(w, `"%s","%s","%s","%s","%s","%s",`+
				`"%s","%0.4f","%0.4f","%s","%s"`+"\r\n",
				geoip.Ip,
				geoip.CountryCode, geoip.CountryName,
				geoip.RegionCode, geoip.RegionName,
				geoip.CityName, geoip.ZipCode,
				geoip.Latitude, geoip.Longitude,
				geoip.MetroCode, geoip.AreaCode)
		case "json":
			resp, err := json.Marshal(geoip)
			if err != nil {
				if debug {
					log.Println("JSON error:", err.Error())
				}
				http.NotFound(w, r)
				return
			}
			callback := r.FormValue("callback")
			if callback != "" {
				w.Header().Set("Content-Type", "text/javascript")
				fmt.Fprintf(w, "%s(%s);\n", callback, resp)
			} else {
				w.Header().Set("Content-Type", "application/json")
				fmt.Fprintf(w, "%s", resp)
			}
		case "xml":
			w.Header().Set("Content-Type", "application/xml")
			resp, err := xml.MarshalIndent(geoip, "", " ")
			if err != nil {
				if debug {
					log.Println("XML error:", err.Error())
				}
				http.Error(w, http.StatusText(500), 500)
				return
			}
			fmt.Fprintf(w, xml.Header+"%s\n", resp)
		}
	}
}

func GeoipLookup(db *sql.DB, ip string) (*GeoIP, error) {
	IP := net.ParseIP(ip)
	reserved := false
	for _, net := range reservedIPs {
		if net.Contains(IP) {
			reserved = true
			break
		}
	}
	geoip := GeoIP{Ip: ip}
	if reserved {
		geoip.CountryCode = "RD"
		geoip.CountryName = "Reserved"
	} else {
		q := `SELECT
		  city_location.country_code, country_blocks.country_name,
		  city_location.region_code, region_names.region_name,
		  city_location.city_name, city_location.postal_code,
		  city_location.latitude, city_location.longitude,
		  city_location.metro_code, city_location.area_code
		FROM city_blocks
		  NATURAL JOIN city_location
		  INNER JOIN country_blocks ON
		    city_location.country_code = country_blocks.country_code
		  LEFT OUTER JOIN region_names ON
		    city_location.country_code = region_names.country_code
		    AND
		    city_location.region_code = region_names.region_code
		WHERE city_blocks.ip_start <= ?
		ORDER BY city_blocks.ip_start DESC LIMIT 1`
		stmt, err := db.Prepare(q)
		if err != nil {
			if debug {
				log.Println("[debug] SQLite", err.Error())
			}
			return nil, err
		}
		defer stmt.Close()
		var uintIP uint32
		b := bytes.NewBuffer(IP.To4())
		binary.Read(b, binary.BigEndian, &uintIP)
		err = stmt.QueryRow(uintIP).Scan(
			&geoip.CountryCode,
			&geoip.CountryName,
			&geoip.RegionCode,
			&geoip.RegionName,
			&geoip.CityName,
			&geoip.ZipCode,
			&geoip.Latitude,
			&geoip.Longitude,
			&geoip.MetroCode,
			&geoip.AreaCode)
		if err != nil {
			return nil, err
		}
	}
	return &geoip, nil
}

type GeoIP struct {
	XMLName     xml.Name `json:"-" xml:"Response"`
	Ip          string   `json:"ip"`
	CountryCode string   `json:"country_code"`
	CountryName string   `json:"country_name"`
	RegionCode  string   `json:"region_code"`
	RegionName  string   `json:"region_name"`
	CityName    string   `json:"city" xml:"City"`
	ZipCode     string   `json:"zipcode"`
	Latitude    float32  `json:"latitude"`
	Longitude   float32  `json:"longitude"`
	MetroCode   string   `json:"metro_code"`
	AreaCode    string   `json:"areacode"`
}

// http://en.wikipedia.org/wiki/Reserved_IP_addresses
var reservedIPs = []net.IPNet{
	{net.IPv4(0, 0, 0, 0), net.IPv4Mask(255, 0, 0, 0)},
	{net.IPv4(10, 0, 0, 0), net.IPv4Mask(255, 0, 0, 0)},
	{net.IPv4(100, 64, 0, 0), net.IPv4Mask(255, 192, 0, 0)},
	{net.IPv4(127, 0, 0, 0), net.IPv4Mask(255, 0, 0, 0)},
	{net.IPv4(169, 254, 0, 0), net.IPv4Mask(255, 255, 0, 0)},
	{net.IPv4(172, 16, 0, 0), net.IPv4Mask(255, 240, 0, 0)},
	{net.IPv4(192, 0, 0, 0), net.IPv4Mask(255, 255, 255, 248)},
	{net.IPv4(192, 0, 2, 0), net.IPv4Mask(255, 255, 255, 0)},
	{net.IPv4(192, 88, 99, 0), net.IPv4Mask(255, 255, 255, 0)},
	{net.IPv4(192, 168, 0, 0), net.IPv4Mask(255, 255, 0, 0)},
	{net.IPv4(198, 18, 0, 0), net.IPv4Mask(255, 254, 0, 0)},
	{net.IPv4(198, 51, 100, 0), net.IPv4Mask(255, 255, 255, 0)},
	{net.IPv4(203, 0, 113, 0), net.IPv4Mask(255, 255, 255, 0)},
	{net.IPv4(224, 0, 0, 0), net.IPv4Mask(240, 0, 0, 0)},
	{net.IPv4(240, 0, 0, 0), net.IPv4Mask(240, 0, 0, 0)},
	{net.IPv4(255, 255, 255, 255), net.IPv4Mask(255, 255, 255, 255)},
}
<commit_msg>improvements..<commit_after>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package main

import (
	"bytes"
	"database/sql"
	"encoding/binary"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/fiorix/go-redis/redis"
	"github.com/fiorix/go-web/httpxtra"
	_ "github.com/mattn/go-sqlite3"
)

const (
	// API limits
	maxrequests = 10000
	expire      = 3600

	// Server settings
	debug      = true
	addr       = ":8080"            // ip:port or /path/to/unix.sock
	redisaddr  = "127.0.0.1:6379"   // redis server
	staticpath = "./static"         // public website
	ipdb       = "./db/ipdb.sqlite" // geoip database
)

func main() {
	http.Handle("/", http.FileServer(http.Dir(staticpath)))
	h := GeoipHandler()
	http.HandleFunc("/csv/", h)
	http.HandleFunc("/xml/", h)
	http.HandleFunc("/json/", h)
	server := http.Server{
		Addr:         addr,
		Handler:      httpxtra.Handler{Logger: logger},
		ReadTimeout:  15 * time.Second,
		WriteTimeout: 15 * time.Second,
	}
	log.Println("FreeGeoIP server starting")
	if e := httpxtra.ListenAndServe(server); e != nil {
		log.Println(e.Error())
	}
}

func logger(r *http.Request, created time.Time, status, bytes int) {
	//fmt.Println(httpxtra.ApacheCommonLog(r, created, status, bytes))
	log.Printf("HTTP %d %s %s (%s) :: %s",
		status,
		r.Method,
		r.URL.Path,
		r.RemoteAddr,
		time.Since(created))
}

// GeoipHandler handles GET on /csv, /xml and /json.
func GeoipHandler() http.HandlerFunc {
	db, err := sql.Open("sqlite3", ipdb)
	if err != nil {
		panic(err)
	}
	rc := redis.New(redisaddr)
	return func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case "GET":
			w.Header().Set("Access-Control-Allow-Origin", "*")
		case "OPTIONS":
			w.Header().Set("Access-Control-Allow-Origin", "*")
			w.Header().Set("Content-Type", "text/plain")
			w.Header().Set("Access-Control-Allow-Methods", "GET")
			w.Header().Set("Access-Control-Allow-Headers",
				"X-Requested-With")
			return
		default:
			w.Header().Set("Allow", "GET, OPTIONS")
			http.Error(w, http.StatusText(405), 405)
			return
		}
		// GET
		// Check quota
		var ipkey string
		if ip, _, err := net.SplitHostPort(r.RemoteAddr); err != nil {
			ipkey = r.RemoteAddr // support for XHeaders
		} else {
			ipkey = ip
		}
		if qcs, err := rc.Get(ipkey); err != nil {
			http.Error(w, http.StatusText(503), 503) // redis down
			return
		} else if qcs == "" {
			if err := rc.Set(ipkey, "1"); err == nil {
				rc.Expire(ipkey, expire)
			}
		} else if qc, _ := strconv.Atoi(qcs); qc < maxrequests {
			rc.Incr(ipkey)
		} else {
			// Out of quota, soz :(
			http.Error(w, http.StatusText(403), 403)
			return
		}
		// Parse URL and build the query.
		var ip string
		a := strings.SplitN(r.URL.Path, "/", 3)
		if len(a) == 3 && a[2] != "" {
			// e.g. /csv/google.com
			addrs, err := net.LookupHost(a[2])
			if err != nil {
				http.Error(w, http.StatusText(404), 404)
				return
			}
			ip = addrs[0]
		} else {
			ip = ipkey
		}
		geoip, err := GeoipLookup(db, ip)
		if err != nil {
			http.NotFound(w, r)
			return
		}
		switch a[1][0] {
		case 'c':
			w.Header().Set("Content-Type", "application/csv")
			fmt.Fprintf(w, `"%s","%s","%s","%s","%s","%s",`+
				`"%s","%0.4f","%0.4f","%s","%s"`+"\r\n",
				geoip.Ip,
				geoip.CountryCode, geoip.CountryName,
				geoip.RegionCode, geoip.RegionName,
				geoip.CityName, geoip.ZipCode,
				geoip.Latitude, geoip.Longitude,
				geoip.MetroCode, geoip.AreaCode)
		case 'j':
			resp, err := json.Marshal(geoip)
			if err != nil {
				if debug {
					log.Println("JSON error:", err.Error())
				}
				http.NotFound(w, r)
				return
			}
			callback := r.FormValue("callback")
			if callback != "" {
				w.Header().Set("Content-Type", "text/javascript")
				fmt.Fprintf(w, "%s(%s);", callback, resp)
			} else {
				w.Header().Set("Content-Type", "application/json")
				fmt.Fprintf(w, "%s", resp)
			}
		case 'x':
			w.Header().Set("Content-Type", "application/xml")
			resp, err := xml.MarshalIndent(geoip, "", " ")
			if err != nil {
				if debug {
					log.Println("XML error:", err.Error())
				}
				http.Error(w, http.StatusText(500), 500)
				return
			}
			fmt.Fprintf(w, xml.Header+"%s\n", resp)
		}
	}
}

func GeoipLookup(db *sql.DB, ip string) (*GeoIP, error) {
	IP := net.ParseIP(ip)
	reserved := false
	for _, net := range reservedIPs {
		if net.Contains(IP) {
			reserved = true
			break
		}
	}
	geoip := GeoIP{Ip: ip}
	if reserved {
		geoip.CountryCode = "RD"
		geoip.CountryName = "Reserved"
	} else {
		q := `SELECT
		  city_location.country_code, country_blocks.country_name,
		  city_location.region_code, region_names.region_name,
		  city_location.city_name, city_location.postal_code,
		  city_location.latitude, city_location.longitude,
		  city_location.metro_code, city_location.area_code
		FROM city_blocks
		  NATURAL JOIN city_location
		  INNER JOIN country_blocks ON
		    city_location.country_code = country_blocks.country_code
		  LEFT OUTER JOIN region_names ON
		    city_location.country_code = region_names.country_code
		    AND
		    city_location.region_code = region_names.region_code
		WHERE city_blocks.ip_start <= ?
		ORDER BY city_blocks.ip_start DESC LIMIT 1`
		stmt, err := db.Prepare(q)
		if err != nil {
			if debug {
				log.Println("[debug] SQLite", err.Error())
			}
			return nil, err
		}
		defer stmt.Close()
		var uintIP uint32
		b := bytes.NewBuffer(IP.To4())
		binary.Read(b, binary.BigEndian, &uintIP)
		err = stmt.QueryRow(uintIP).Scan(
			&geoip.CountryCode,
			&geoip.CountryName,
			&geoip.RegionCode,
			&geoip.RegionName,
			&geoip.CityName,
			&geoip.ZipCode,
			&geoip.Latitude,
			&geoip.Longitude,
			&geoip.MetroCode,
			&geoip.AreaCode)
		if err != nil {
			return nil, err
		}
	}
	return &geoip, nil
}

type GeoIP struct {
	XMLName     xml.Name `json:"-" xml:"Response"`
	Ip          string   `json:"ip"`
	CountryCode string   `json:"country_code"`
	CountryName string   `json:"country_name"`
	RegionCode  string   `json:"region_code"`
	RegionName  string   `json:"region_name"`
	CityName    string   `json:"city" xml:"City"`
	ZipCode     string   `json:"zipcode"`
	Latitude    float32  `json:"latitude"`
	Longitude   float32  `json:"longitude"`
	MetroCode   string   `json:"metro_code"`
	AreaCode    string   `json:"areacode"`
}

// http://en.wikipedia.org/wiki/Reserved_IP_addresses
var reservedIPs = []net.IPNet{
	{net.IPv4(0, 0, 0, 0), net.IPv4Mask(255, 0, 0, 0)},
	{net.IPv4(10, 0, 0, 0), net.IPv4Mask(255, 0, 0, 0)},
	{net.IPv4(100, 64, 0, 0), net.IPv4Mask(255, 192, 0, 0)},
	{net.IPv4(127, 0, 0, 0), net.IPv4Mask(255, 0, 0, 0)},
	{net.IPv4(169, 254, 0, 0), net.IPv4Mask(255, 255, 0, 0)},
	{net.IPv4(172, 16, 0, 0), net.IPv4Mask(255, 240, 0, 0)},
	{net.IPv4(192, 0, 0, 0), net.IPv4Mask(255, 255, 255, 248)},
	{net.IPv4(192, 0, 2, 0), net.IPv4Mask(255, 255, 255, 0)},
	{net.IPv4(192, 88, 99, 0), net.IPv4Mask(255, 255, 255, 0)},
	{net.IPv4(192, 168, 0, 0), net.IPv4Mask(255, 255, 0, 0)},
	{net.IPv4(198, 18, 0, 0), net.IPv4Mask(255, 254, 0, 0)},
	{net.IPv4(198, 51, 100, 0), net.IPv4Mask(255, 255, 255, 0)},
	{net.IPv4(203, 0, 113, 0), net.IPv4Mask(255, 255, 255, 0)},
	{net.IPv4(224, 0, 0, 0), net.IPv4Mask(240, 0, 0, 0)},
	{net.IPv4(240, 0, 0, 0), net.IPv4Mask(240, 0, 0, 0)},
	{net.IPv4(255, 255, 255, 255), net.IPv4Mask(255, 255, 255, 255)},
}
<|endoftext|>


<commit_before>package prob

// Ground operators

import (
	"fmt"
	"reflect"
)

type Operator struct {
	Name     string
	Parms    []Name
	Cost     float32
	Precond  []Literal
	Effect   []Literal
	CondEffs []CondEffect
}

type CondEffect struct {
	Cond   []Literal
	Effect []Literal
}

func (a *Action) operators() (ops []Operator) {
	a.dnf()
	a.ensureDnf()

	parms := make([]Name, len(a.Parameters))
	for i := range a.Parameters {
		parms[i] = a.Parameters[i].Name
	}

	conds := gatherOrs(a.Precondition)
	ueffs, ceffs := gatherEffects(a.Effect)

	for i := range conds {
		ops = append(ops, Operator{
			Name:     a.Name,
			Parms:    parms,
			Cost:     float32(1), // For now
			Precond:  gatherLits(conds[i]),
			Effect:   ueffs,
			CondEffs: ceffs,
		})
	}
	return
}

// Get the unconditional and conditional effects
func gatherEffects(f Formula) (ueffs []Literal, ceffs []CondEffect) {
	for _, eff := range gatherOrs(f) {
		switch n := eff.(type) {
		case *WhenNode:
			ceffs = append(ceffs, CondEffect{
				Cond:   gatherLits(n.Condition),
				Effect: gatherLits(n.Formula),
			})
		case *AndNode:
			ueffs = append(ueffs, gatherLits(n)...)
		case *Literal:
			if n.Num < 0 {
				panic("A Literal that was no assigned a number")
			}
			ueffs = append(ueffs, *n)
		case *AssignNode:
			// Ignore assignment for now
		case TrueNode:
			// Ignore
		case FalseNode:
			// Ignore
		default:
			panic(fmt.Sprintf("gatherEffects: unexpected node type: %v", f))
		}
	}
	return
}

func gatherLits(f Formula) (lits []Literal) {
	switch n := f.(type) {
	case *AndNode:
		lits = append(lits, gatherLits(n.Left)...)
		lits = append(lits, gatherLits(n.Right)...)
	case *Literal:
		if n.Num < 0 {
			panic("A Literal that was no assigned a number")
		}
		lits = append(lits, *n)
	case *AssignNode:
		// Ignore an assignment
	default:
		tname := reflect.TypeOf(f).String()
		panic(fmt.Sprintf("gatherLits: unexpected node type: %s", tname))
	}
	return
}
<commit_msg>Print the node types with %T.<commit_after>package prob

// Ground operators

import "fmt"

type Operator struct {
	Name     string
	Parms    []Name
	Cost     float32
	Precond  []Literal
	Effect   []Literal
	CondEffs []CondEffect
}

type CondEffect struct {
	Cond   []Literal
	Effect []Literal
}

func (a *Action) operators() (ops []Operator) {
	a.dnf()
	a.ensureDnf()

	parms := make([]Name, len(a.Parameters))
	for i := range a.Parameters {
		parms[i] = a.Parameters[i].Name
	}

	conds := gatherOrs(a.Precondition)
	ueffs, ceffs := gatherEffects(a.Effect)

	for i := range conds {
		ops = append(ops, Operator{
			Name:     a.Name,
			Parms:    parms,
			Cost:     float32(1), // For now
			Precond:  gatherLits(conds[i]),
			Effect:   ueffs,
			CondEffs: ceffs,
		})
	}
	return
}

// Get the unconditional and conditional effects
func gatherEffects(f Formula) (ueffs []Literal, ceffs []CondEffect) {
	for _, eff := range gatherOrs(f) {
		switch n := eff.(type) {
		case *WhenNode:
			ceffs = append(ceffs, CondEffect{
				Cond:   gatherLits(n.Condition),
				Effect: gatherLits(n.Formula),
			})
		case *AndNode:
			ueffs = append(ueffs, gatherLits(n)...)
		case *Literal:
			if n.Num < 0 {
				panic("A Literal that was no assigned a number")
			}
			ueffs = append(ueffs, *n)
		case *AssignNode:
			// Ignore assignment for now
		case TrueNode:
			// Ignore
		case FalseNode:
			// Ignore
		default:
			panic(fmt.Sprintf("gatherEffects: unexpected node type: %T", f))
		}
	}
	return
}

func gatherLits(f Formula) (lits []Literal) {
	switch n := f.(type) {
	case *AndNode:
		lits = append(lits, gatherLits(n.Left)...)
		lits = append(lits, gatherLits(n.Right)...)
	case *Literal:
		if n.Num < 0 {
			panic("A Literal that was no assigned a number")
		}
		lits = append(lits, *n)
	case *AssignNode:
		// Ignore an assignment
	default:
		panic(fmt.Sprintf("gatherLits: unexpected node type: %T", f))
	}
	return
}
<|endoftext|>


<commit_before>package prob_test

import (
	"math/big"
	"testing"

	"github.com/brnstz/prob"
)

type test struct {
	n      int64
	k      int64
	result string
}

func TestReplaceOrdered(t *testing.T) {
	// tests is a list to run with the expectation that
	// prob.ReplaceOrdered(n, k) == result (where n and k are converted to
	// big.Int values and the result is tested as a base10 string)
	tests := []test{
		{5, 4, "625"},
		{10, 2, "100"},
		{0, 21, "0"},
	}

	// Go through each test
	for _, test := range tests {

		// Get the result as a base10 string
		actual := prob.ReplaceOrdered(
			big.NewInt(test.n), big.NewInt(test.k),
		).Text(10)

		// Check result matches or signal fatal error
		if actual != test.result {
			t.Fatalf("expected prob.ReplaceOrdered(%d, %d) == %v but got %v",
				test.n, test.k, test.result, actual,
			)
		}
	}
}

func TestNoReplaceOrdered(t *testing.T) {
	// tests is a list to run with the expectation that
	// prob.NoReplaceOrdered(n, k) == result (where n and k are converted to
	// big.Int values and the result is tested as a base10 string)
	tests := []test{
		{100, 3, "970200"},
		{5, 6, "0"},
	}

	// Go through each test
	for _, test := range tests {

		// Get the result as a base10 string
		actual := prob.NoReplaceOrdered(
			big.NewInt(test.n), big.NewInt(test.k),
		).Text(10)

		// Check result matches or signal fatal error
		if actual != test.result {
			t.Fatalf("expected prob.NoReplaceOrdered(%d, %d) == %v but got %v",
				test.n, test.k, test.result, actual,
			)
		}
	}
}

func TestNoReplaceUnordered(t *testing.T) {

}
<commit_msg>generic-ize running tests for similar functions<commit_after>package prob_test

import (
	"math/big"
	"testing"

	"github.com/brnstz/prob"
)

type test struct {
	n      int64
	k      int64
	result string
}

type Tester func(n, k *big.Int) *big.Int

func runTests(t *testing.T, tests []test, tester Tester, name string) {
	for _, test := range tests {
		// Get the result as a base10 string
		actual := tester(
			big.NewInt(test.n), big.NewInt(test.k),
		).Text(10)

		// Check result matches or signal fatal error
		if actual != test.result {
			t.Fatalf("expected %s(%d, %d) == %v but got %v",
				name, test.n, test.k, test.result, actual,
			)
		}
	}
}

func TestReplaceOrdered(t *testing.T) {
	// tests is a list to run with the expectation that
	// prob.ReplaceOrdered(n, k) == result (where n and k are converted to
	// big.Int values and the result is tested as a base10 string)
	tests := []test{
		{5, 4, "625"},
		{10, 2, "100"},
		{0, 21, "0"},
	}

	runTests(t, tests, prob.ReplaceOrdered, "prob.ReplaceOrdered")
}

func TestNoReplaceOrdered(t *testing.T) {
	// tests is a list to run with the expectation that
	// prob.NoReplaceOrdered(n, k) == result (where n and k are converted to
	// big.Int values and the result is tested as a base10 string)
	tests := []test{
		{100, 3, "970200"},
		{5, 6, "0"},
	}

	runTests(t, tests, prob.NoReplaceOrdered, "prob.NoReplaceOrdered")
}

func TestNoReplaceUnordered(t *testing.T) {

}
<|endoftext|>