<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"regexp"
	"runtime"
	"runtime/pprof"
	"time"
)

var dbRoot = flag.String("root", "db", "Root directory for database files.")
var flushTime = flag.Duration("flushDelay", time.Second*5,
	"Maximum amount of time to wait before flushing")
var maxOpQueue = flag.Int("maxOpQueue", 1000,
	"Maximum number of queued items before flushing")
var staticPath = flag.String("static", "static", "Path to static data")
var queryTimeout = flag.Duration("maxQueryTime", time.Minute*5,
	"Maximum amount of time a query is allowed to process.")
var queryBacklog = flag.Int("queryBacklog", 0, "Query scan/group backlog size")
var docBacklog = flag.Int("docBacklog", 0, "MR group request backlog size")
var cacheAddr = flag.String("memcache", "", "Memcached server to connect to")
var cacheBacklog = flag.Int("cacheBacklog", 1000, "Cache backlog size")
var cacheWorkers = flag.Int("cacheWorkers", 4, "Number of cache workers")

// Profiling
var pprofFile = flag.String("proFile", "", "File to write profiling info into")
var pprofStart = flag.Duration("proStart", 5*time.Second,
	"How long after startup to start profiling")
var pprofDuration = flag.Duration("proDuration", 5*time.Minute,
	"How long to run the profiler before shutting it down")

type routeHandler func(parts []string, w http.ResponseWriter, req *http.Request)

type routingEntry struct {
	Method   string
	Path     *regexp.Regexp
	Handler  routeHandler
	Deadline time.Duration
}

const dbMatch = "[-%+()$_a-zA-Z0-9]+"

var defaultDeadline = time.Millisecond * 50

var routingTable []routingEntry = []routingEntry{
	routingEntry{"GET", regexp.MustCompile("^/$"),
		serverInfo, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/_static/(.*)"),
		staticHandler, defaultDeadline},
	// Database stuff
	routingEntry{"GET", regexp.MustCompile("^/_all_dbs$"),
		listDatabases, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/_(.*)"),
		reservedHandler, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		dbInfo, defaultDeadline},
	routingEntry{"HEAD", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		checkDB, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/_changes$"),
		dbChanges, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/_query$"),
		query, *queryTimeout},
	routingEntry{"DELETE", regexp.MustCompile("^/(" + dbMatch + ")/_bulk$"),
		deleteBulk, *queryTimeout},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/_all"),
		allDocs, *queryTimeout},
	routingEntry{"POST", regexp.MustCompile("^/(" + dbMatch + ")/_compact"),
		compact, time.Second * 30},
	routingEntry{"PUT", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		createDB, defaultDeadline},
	routingEntry{"DELETE", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		deleteDB, defaultDeadline},
	routingEntry{"POST", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		newDocument, defaultDeadline},
	// Document stuff
	routingEntry{"PUT", regexp.MustCompile("^/(" + dbMatch + ")/([^/]+)$"),
		putDocument, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/([^/]+)$"),
		getDocument, defaultDeadline},
	routingEntry{"DELETE", regexp.MustCompile("^/(" + dbMatch + ")/([^/]+)$"),
		rmDocument, defaultDeadline},
}

func mustEncode(status int, w http.ResponseWriter, ob interface{}) {
	b, err := json.Marshal(ob)
	if err != nil {
		log.Fatalf("Error encoding %v.", ob)
	}
	w.Header().Set("Content-Length", fmt.Sprintf("%d", len(b)))
	w.WriteHeader(status)
	w.Write(b)
}

func emitError(status int, w http.ResponseWriter, e, reason string) {
	m := map[string]string{"error": e, "reason": reason}
	mustEncode(status, w, m)
}

func staticHandler(parts []string, w http.ResponseWriter, req *http.Request) {
	w.Header().Del("Content-type")
	http.StripPrefix("/_static/",
		http.FileServer(http.Dir(*staticPath))).ServeHTTP(w, req)
}

func reservedHandler(parts []string, w http.ResponseWriter, req *http.Request) {
	emitError(400,
		w, "illegal_database_name",
		"Only lowercase characters (a-z), digits (0-9), "+
			"and any of the characters _, $, (, ), +, -, and / are allowed. "+
			"Must begin with a letter.")

}

func defaultHandler(parts []string, w http.ResponseWriter, req *http.Request) {
	emitError(400,

		w, "no_handler",
		fmt.Sprintf("Can't handle %v to %v\n", req.Method, req.URL.Path))

}

func findHandler(method, path string) (routingEntry, []string) {
	for _, r := range routingTable {
		if r.Method == method {
			matches := r.Path.FindAllStringSubmatch(path, 1)
			if len(matches) > 0 {
				return r, matches[0][1:]
			}
		}
	}
	return routingEntry{"DEFAULT", nil, defaultHandler, defaultDeadline},
		[]string{}
}

func handler(w http.ResponseWriter, req *http.Request) {
	defer req.Body.Close()
	start := time.Now()
	route, hparts := findHandler(req.Method, req.URL.Path)
	wd := time.AfterFunc(route.Deadline, func() {
		log.Printf("%v:%v is taking longer than %v",
			req.Method, req.URL.Path, route.Deadline)
	})

	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-type", "application/json")
	route.Handler(hparts, w, req)

	if !wd.Stop() {
		log.Printf("%v:%v eventually finished in %v",
			req.Method, req.URL.Path, time.Since(start))
	}
}

func startProfiler() {
	time.Sleep(*pprofStart)
	log.Printf("Starting profiler")
	f, err := os.OpenFile(*pprofFile, os.O_WRONLY|os.O_CREATE, 0666)
	if err == nil {
		err = pprof.StartCPUProfile(f)
		if err != nil {
			log.Fatalf("Can't start profiler")
		}
		time.AfterFunc(*pprofDuration, func() {
			log.Printf("Shutting down profiler")
			pprof.StopCPUProfile()
			f.Close()
		})
	} else {
		log.Printf("Can't open profilefile")
	}

}

func main() {
	halfProcs := runtime.GOMAXPROCS(0) / 2
	if halfProcs < 1 {
		halfProcs = 1
	}
	queryWorkers := flag.Int("queryWorkers", halfProcs,
		"Number of query tree walkers.")
	docWorkers := flag.Int("docWorkers", halfProcs,
		"Number of document mapreduce workers.")

	addr := flag.String("addr", ":3133", "Address to bind to")
	mcaddr := flag.String("memcbind", "", "Memcached server bind address")
	flag.Parse()

	// Update the query handler deadline to the query timeout
	found := false
	for i := range routingTable {
		matches := routingTable[i].Path.FindAllStringSubmatch("/x/_query", 1)
		if len(matches) > 0 {
			routingTable[i].Deadline = *queryTimeout
			found = true
			break
		}
	}
	if !found {
		log.Fatalf("Programming error:  Could not find query handler")
	}

	processorInput = make(chan *processIn, *docBacklog)
	for i := 0; i < *docWorkers; i++ {
		go docProcessor(processorInput)
	}

	if *cacheAddr == "" {
		cacheInput = processorInput
		// Note: cacheInputSet will be null here, there should be no caching
	} else {
		cacheInput = make(chan *processIn, *cacheBacklog)
		cacheInputSet = make(chan *processOut, *cacheBacklog)
		for i := 0; i < *cacheWorkers; i++ {
			go cacheProcessor(cacheInput, cacheInputSet)
		}
	}

	queryInput = make(chan *queryIn, *queryBacklog)
	for i := 0; i < *queryWorkers; i++ {
		go queryExecutor(queryInput)
	}

	if *pprofFile != "" {
		go startProfiler()
	}

	if *mcaddr != "" {
		go listenMC(*mcaddr)
	}

	s := &http.Server{
		Addr:        *addr,
		Handler:     http.HandlerFunc(handler),
		ReadTimeout: 5 * time.Second,
	}
	log.Printf("Listening to web requests on %s", *addr)
	log.Fatal(s.ListenAndServe())
}
<commit_msg>creating root folder if missing<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"regexp"
	"runtime"
	"runtime/pprof"
	"time"
)

var dbRoot = flag.String("root", "db", "Root directory for database files.")
var flushTime = flag.Duration("flushDelay", time.Second*5,
	"Maximum amount of time to wait before flushing")
var maxOpQueue = flag.Int("maxOpQueue", 1000,
	"Maximum number of queued items before flushing")
var staticPath = flag.String("static", "static", "Path to static data")
var queryTimeout = flag.Duration("maxQueryTime", time.Minute*5,
	"Maximum amount of time a query is allowed to process.")
var queryBacklog = flag.Int("queryBacklog", 0, "Query scan/group backlog size")
var docBacklog = flag.Int("docBacklog", 0, "MR group request backlog size")
var cacheAddr = flag.String("memcache", "", "Memcached server to connect to")
var cacheBacklog = flag.Int("cacheBacklog", 1000, "Cache backlog size")
var cacheWorkers = flag.Int("cacheWorkers", 4, "Number of cache workers")

// Profiling
var pprofFile = flag.String("proFile", "", "File to write profiling info into")
var pprofStart = flag.Duration("proStart", 5*time.Second,
	"How long after startup to start profiling")
var pprofDuration = flag.Duration("proDuration", 5*time.Minute,
	"How long to run the profiler before shutting it down")

type routeHandler func(parts []string, w http.ResponseWriter, req *http.Request)

type routingEntry struct {
	Method   string
	Path     *regexp.Regexp
	Handler  routeHandler
	Deadline time.Duration
}

const dbMatch = "[-%+()$_a-zA-Z0-9]+"

var defaultDeadline = time.Millisecond * 50

var routingTable []routingEntry = []routingEntry{
	routingEntry{"GET", regexp.MustCompile("^/$"),
		serverInfo, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/_static/(.*)"),
		staticHandler, defaultDeadline},
	// Database stuff
	routingEntry{"GET", regexp.MustCompile("^/_all_dbs$"),
		listDatabases, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/_(.*)"),
		reservedHandler, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		dbInfo, defaultDeadline},
	routingEntry{"HEAD", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		checkDB, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/_changes$"),
		dbChanges, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/_query$"),
		query, *queryTimeout},
	routingEntry{"DELETE", regexp.MustCompile("^/(" + dbMatch + ")/_bulk$"),
		deleteBulk, *queryTimeout},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/_all"),
		allDocs, *queryTimeout},
	routingEntry{"POST", regexp.MustCompile("^/(" + dbMatch + ")/_compact"),
		compact, time.Second * 30},
	routingEntry{"PUT", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		createDB, defaultDeadline},
	routingEntry{"DELETE", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		deleteDB, defaultDeadline},
	routingEntry{"POST", regexp.MustCompile("^/(" + dbMatch + ")/?$"),
		newDocument, defaultDeadline},
	// Document stuff
	routingEntry{"PUT", regexp.MustCompile("^/(" + dbMatch + ")/([^/]+)$"),
		putDocument, defaultDeadline},
	routingEntry{"GET", regexp.MustCompile("^/(" + dbMatch + ")/([^/]+)$"),
		getDocument, defaultDeadline},
	routingEntry{"DELETE", regexp.MustCompile("^/(" + dbMatch + ")/([^/]+)$"),
		rmDocument, defaultDeadline},
}

func mustEncode(status int, w http.ResponseWriter, ob interface{}) {
	b, err := json.Marshal(ob)
	if err != nil {
		log.Fatalf("Error encoding %v.", ob)
	}
	w.Header().Set("Content-Length", fmt.Sprintf("%d", len(b)))
	w.WriteHeader(status)
	w.Write(b)
}

func emitError(status int, w http.ResponseWriter, e, reason string) {
	m := map[string]string{"error": e, "reason": reason}
	mustEncode(status, w, m)
}

func staticHandler(parts []string, w http.ResponseWriter, req *http.Request) {
	w.Header().Del("Content-type")
	http.StripPrefix("/_static/",
		http.FileServer(http.Dir(*staticPath))).ServeHTTP(w, req)
}

func reservedHandler(parts []string, w http.ResponseWriter, req *http.Request) {
	emitError(400,
		w, "illegal_database_name",
		"Only lowercase characters (a-z), digits (0-9), "+
			"and any of the characters _, $, (, ), +, -, and / are allowed. "+
			"Must begin with a letter.")

}

func defaultHandler(parts []string, w http.ResponseWriter, req *http.Request) {
	emitError(400,

		w, "no_handler",
		fmt.Sprintf("Can't handle %v to %v\n", req.Method, req.URL.Path))

}

func findHandler(method, path string) (routingEntry, []string) {
	for _, r := range routingTable {
		if r.Method == method {
			matches := r.Path.FindAllStringSubmatch(path, 1)
			if len(matches) > 0 {
				return r, matches[0][1:]
			}
		}
	}
	return routingEntry{"DEFAULT", nil, defaultHandler, defaultDeadline},
		[]string{}
}

func handler(w http.ResponseWriter, req *http.Request) {
	defer req.Body.Close()
	start := time.Now()
	route, hparts := findHandler(req.Method, req.URL.Path)
	wd := time.AfterFunc(route.Deadline, func() {
		log.Printf("%v:%v is taking longer than %v",
			req.Method, req.URL.Path, route.Deadline)
	})

	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-type", "application/json")
	route.Handler(hparts, w, req)

	if !wd.Stop() {
		log.Printf("%v:%v eventually finished in %v",
			req.Method, req.URL.Path, time.Since(start))
	}
}

func startProfiler() {
	time.Sleep(*pprofStart)
	log.Printf("Starting profiler")
	f, err := os.OpenFile(*pprofFile, os.O_WRONLY|os.O_CREATE, 0666)
	if err == nil {
		err = pprof.StartCPUProfile(f)
		if err != nil {
			log.Fatalf("Can't start profiler")
		}
		time.AfterFunc(*pprofDuration, func() {
			log.Printf("Shutting down profiler")
			pprof.StopCPUProfile()
			f.Close()
		})
	} else {
		log.Printf("Can't open profilefile")
	}

}

func main() {
	halfProcs := runtime.GOMAXPROCS(0) / 2
	if halfProcs < 1 {
		halfProcs = 1
	}
	queryWorkers := flag.Int("queryWorkers", halfProcs,
		"Number of query tree walkers.")
	docWorkers := flag.Int("docWorkers", halfProcs,
		"Number of document mapreduce workers.")

	addr := flag.String("addr", ":3133", "Address to bind to")
	mcaddr := flag.String("memcbind", "", "Memcached server bind address")
	flag.Parse()

	if err := os.MkdirAll(*dbRoot, 0777); err != nil {
		log.Fatalf("Could not create %v: %v", *dbRoot, err)
	}

	// Update the query handler deadline to the query timeout
	found := false
	for i := range routingTable {
		matches := routingTable[i].Path.FindAllStringSubmatch("/x/_query", 1)
		if len(matches) > 0 {
			routingTable[i].Deadline = *queryTimeout
			found = true
			break
		}
	}
	if !found {
		log.Fatalf("Programming error:  Could not find query handler")
	}

	processorInput = make(chan *processIn, *docBacklog)
	for i := 0; i < *docWorkers; i++ {
		go docProcessor(processorInput)
	}

	if *cacheAddr == "" {
		cacheInput = processorInput
		// Note: cacheInputSet will be null here, there should be no caching
	} else {
		cacheInput = make(chan *processIn, *cacheBacklog)
		cacheInputSet = make(chan *processOut, *cacheBacklog)
		for i := 0; i < *cacheWorkers; i++ {
			go cacheProcessor(cacheInput, cacheInputSet)
		}
	}

	queryInput = make(chan *queryIn, *queryBacklog)
	for i := 0; i < *queryWorkers; i++ {
		go queryExecutor(queryInput)
	}

	if *pprofFile != "" {
		go startProfiler()
	}

	if *mcaddr != "" {
		go listenMC(*mcaddr)
	}

	s := &http.Server{
		Addr:        *addr,
		Handler:     http.HandlerFunc(handler),
		ReadTimeout: 5 * time.Second,
	}
	log.Printf("Listening to web requests on %s", *addr)
	log.Fatal(s.ListenAndServe())
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/nlopes/slack"
	"log"
	"os"
	"strings"
)

var (
	helpText []string = []string{
		"Available commands are:",
		"	- `nowplaying` // Display information on the current song",
		"	- `play (song|album) <search text>`	// Play the first song/album result for _search text_ & add it to the queue",
		"	- `search (song|album) <search text>` // Print the first song/album result for _search text_",
		"	- `boombox (start|stop)` // Start or stop displaying the current song in this channel",
	}
)

func main() {
	SLACK_TOKEN := os.Getenv("SLACK_TOKEN")
	slack_api := slack.New(SLACK_TOKEN)

	slack_message_parameters := slack.NewPostMessageParameters()
	slack_message_parameters.AsUser = true

	// Start the boombox thread
	boombox := boomBox{}
	go boombox.start(slack_api)

	logger := log.New(
		os.Stdout,
		"slack-bot: ",
		log.Lshortfile|log.LstdFlags,
	)

	slack.SetLogger(logger)

	rtm := slack_api.NewRTM()
	go rtm.ManageConnection()

	for msg := range rtm.IncomingEvents {
		switch ev := msg.Data.(type) {
		case *slack.MessageEvent:
			casabot_command := parseCommand(ev)
			if casabot_command != nil && casabot_command.UserID == rtm.GetInfo().User.ID {
				switch strings.ToLower(casabot_command.Command) {
				case "nowplaying":
					casa_NowPlaying(slack_api, casabot_command)
				case "play":
					switch casabot_command.verb([]string{"song", "album"}) {
					case "song":
						casa_PlaySong(slack_api, casabot_command)
					case "album":
						casa_PlayAlbum(slack_api, casabot_command)
					default:
						casa_PlaySong(slack_api, casabot_command)
					}
				case "search":
					switch casabot_command.verb([]string{"song", "album"}) {
					default:
						casa_SearchSong(slack_api, casabot_command)
					}
				case "boombox":
					switch casabot_command.verb([]string{"song", "album"}) {
					case "start":
						boombox.addChannel(ev.Channel, slack_api)
					case "stop":
						boombox.removeChannel(ev.Channel, slack_api)
					}
				case "pause", "resume", "next", "previous":
					casa_PlayerAction(slack_api, casabot_command)
				default:
					var text string
					for _, line := range helpText {
						text += line + "\n"
					}
					slack_api.PostMessage(ev.Channel, text, slack_message_parameters)
				}
			}

		case *slack.RTMError:
			log.Printf("Error: %s\n", ev.Error())

		case *slack.InvalidAuthEvent:
			log.Fatal("Invalid credentials")

		case *slack.ConnectionErrorEvent:
			log.Fatal("Failed to authenticate with Slack API")

		case *slack.ConnectingEvent:
			log.Printf("Connecting to Slack (attempt %d)", ev.Attempt)

		case *slack.HelloEvent:
			log.Printf("Received hello from Slack API.")

		case *slack.ConnectedEvent:
			log.Printf("Connected to %s as %s.", ev.Info.Team.Name, ev.Info.User.Name)

		case *slack.LatencyReport:
			log.Printf("Latency report: %s", ev.Value)

		default:
			// Ignore other events..
			// fmt.Printf("Unexpected: %v\n", msg.Data)
		}
	}
}
<commit_msg>Fixed boombox bug<commit_after>package main

import (
	"github.com/nlopes/slack"
	"log"
	"os"
	"strings"
)

var (
	helpText []string = []string{
		"Available commands are:",
		"	- `nowplaying` // Display information on the current song",
		"	- `play (song|album) <search text>`	// Play the first song/album result for _search text_ & add it to the queue",
		"	- `search (song|album) <search text>` // Print the first song/album result for _search text_",
		"	- `boombox (start|stop)` // Start or stop displaying the current song in this channel",
	}
)

func main() {
	SLACK_TOKEN := os.Getenv("SLACK_TOKEN")
	slack_api := slack.New(SLACK_TOKEN)

	slack_message_parameters := slack.NewPostMessageParameters()
	slack_message_parameters.AsUser = true

	// Start the boombox thread
	boombox := boomBox{}
	go boombox.start(slack_api)

	logger := log.New(
		os.Stdout,
		"slack-bot: ",
		log.Lshortfile|log.LstdFlags,
	)

	slack.SetLogger(logger)

	rtm := slack_api.NewRTM()
	go rtm.ManageConnection()

	for msg := range rtm.IncomingEvents {
		switch ev := msg.Data.(type) {
		case *slack.MessageEvent:
			casabot_command := parseCommand(ev)
			if casabot_command != nil && casabot_command.UserID == rtm.GetInfo().User.ID {
				switch strings.ToLower(casabot_command.Command) {
				case "nowplaying":
					casa_NowPlaying(slack_api, casabot_command)
				case "play":
					switch casabot_command.verb([]string{"song", "album"}) {
					case "song":
						casa_PlaySong(slack_api, casabot_command)
					case "album":
						casa_PlayAlbum(slack_api, casabot_command)
					default:
						casa_PlaySong(slack_api, casabot_command)
					}
				case "search":
					switch casabot_command.verb([]string{"song", "album"}) {
					default:
						casa_SearchSong(slack_api, casabot_command)
					}
				case "boombox":
					switch casabot_command.verb([]string{"start", "stop"}) {
					case "start":
						boombox.addChannel(ev.Channel, slack_api)
					case "stop":
						boombox.removeChannel(ev.Channel, slack_api)
					}
				case "pause", "resume", "next", "previous":
					casa_PlayerAction(slack_api, casabot_command)
				default:
					var text string
					for _, line := range helpText {
						text += line + "\n"
					}
					slack_api.PostMessage(ev.Channel, text, slack_message_parameters)
				}
			}

		case *slack.RTMError:
			log.Printf("Error: %s\n", ev.Error())

		case *slack.InvalidAuthEvent:
			log.Fatal("Invalid credentials")

		case *slack.ConnectionErrorEvent:
			log.Fatal("Failed to authenticate with Slack API")

		case *slack.ConnectingEvent:
			log.Printf("Connecting to Slack (attempt %d)", ev.Attempt)

		case *slack.HelloEvent:
			log.Printf("Received hello from Slack API.")

		case *slack.ConnectedEvent:
			log.Printf("Connected to %s as %s.", ev.Info.Team.Name, ev.Info.User.Name)

		case *slack.LatencyReport:
			log.Printf("Latency report: %s", ev.Value)

		default:
			// Ignore other events..
			// fmt.Printf("Unexpected: %v\n", msg.Data)
		}
	}
}
<|endoftext|>


<commit_before>// Package cloudflare implements the CloudFlare v4 API.
package cloudflare

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/pkg/errors"
)

const apiURL = "https://api.cloudflare.com/client/v4"

// API holds the configuration for the current API client. A client should not
// be modified concurrently.
type API struct {
	APIKey     string
	APIEmail   string
	BaseURL    string
	headers    http.Header
	httpClient *http.Client
}

// New creates a new CloudFlare v4 API client.
func New(key, email string, opts ...Option) (*API, error) {
	if key == "" || email == "" {
		return nil, errors.New(errEmptyCredentials)
	}

	api := &API{
		APIKey:   key,
		APIEmail: email,
		headers:  make(http.Header),
	}

	err := api.parseOptions(opts...)
	if err != nil {
		return nil, errors.Wrap(err, "options parsing failed")
	}

	// Fall back to http.DefaultClient if the package user does not provide
	// their own.
	if api.httpClient == nil {
		api.httpClient = http.DefaultClient
	}

	return api, nil
}

// NewZone initializes Zone.
func NewZone() *Zone {
	return &Zone{}
}

// ZoneIDByName retrieves a zone's ID from the name.
func (api *API) ZoneIDByName(zoneName string) (string, error) {
	res, err := api.ListZones(zoneName)
	if err != nil {
		return "", errors.Wrap(err, "ListZones command failed")
	}
	for _, zone := range res {
		if zone.Name == zoneName {
			return zone.ID, nil
		}
	}
	return "", errors.New("Zone could not be found")
}

// Params can be turned into a URL query string or a body
// TODO: Give this func a better name
func (api *API) makeRequest(method, uri string, params interface{}) ([]byte, error) {
	// Replace nil with a JSON object if needed
	var reqBody io.Reader
	if params != nil {
		json, err := json.Marshal(params)
		if err != nil {
			return nil, errors.Wrap(err, "Error marshalling params to JSON")
		}
		reqBody = bytes.NewReader(json)
	} else {
		reqBody = nil
	}
	req, err := http.NewRequest(method, api.BaseURL+uri, reqBody)
	if err != nil {
		return nil, errors.Wrap(err, "HTTP request creation failed")
	}

	// Apply any user-defined headers first.
	req.Header = api.headers

	req.Header.Set("X-Auth-Key", api.APIKey)
	req.Header.Set("X-Auth-Email", api.APIEmail)

	// Could be application/json or multipart/form-data
	// req.Header.Add("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, errors.Wrap(err, "HTTP request failed")
	}
	defer resp.Body.Close()
	resBody, err := ioutil.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK {
		if err != nil {
			return nil, errors.Wrap(err, "Error returned from API")
		} else if resBody != nil {
			return nil, errors.New(string(resBody))
		} else {
			return nil, errors.New(resp.Status)
		}
	}

	return resBody, nil
}

// Response is a template.  There will also be a result struct.  There will be a
// unique response type for each response, which will include this type.
type Response struct {
	Success  bool     `json:"success"`
	Errors   []string `json:"errors"`
	Messages []string `json:"messages"`
}

// ResultInfo contains metadata about the Response.
type ResultInfo struct {
	Page    int `json:"page"`
	PerPage int `json:"per_page"`
	Count   int `json:"count"`
	Total   int `json:"total_count"`
}

// User describes a user account.
type User struct {
	ID            string         `json:"id"`
	Email         string         `json:"email"`
	FirstName     string         `json:"first_name"`
	LastName      string         `json:"last_name"`
	Username      string         `json:"username"`
	Telephone     string         `json:"telephone"`
	Country       string         `json:"country"`
	Zipcode       string         `json:"zipcode"`
	CreatedOn     string         `json:"created_on"` // Should this be a time.Date?
	ModifiedOn    string         `json:"modified_on"`
	APIKey        string         `json:"api_key"`
	TwoFA         bool           `json:"two_factor_authentication_enabled"`
	Betas         []string       `json:"betas"`
	Organizations []Organization `json:"organizations"`
}

// UserResponse wraps a response containing User accounts.
type UserResponse struct {
	Response
	Result User `json:"result"`
}

// Owner describes the resource owner.
type Owner struct {
	ID        string `json:"id"`
	Email     string `json:"email"`
	OwnerType string `json:"owner_type"`
}

// Zone describes a CloudFlare zone.
type Zone struct {
	ID                string   `json:"id"`
	Name              string   `json:"name"`
	DevMode           int      `json:"development_mode"`
	OriginalNS        []string `json:"original_name_servers"`
	OriginalRegistrar string   `json:"original_registrar"`
	OriginalDNSHost   string   `json:"original_dnshost"`
	CreatedOn         string   `json:"created_on"`
	ModifiedOn        string   `json:"modified_on"`
	NameServers       []string `json:"name_servers"`
	Owner             Owner    `json:"owner"`
	Permissions       []string `json:"permissions"`
	Plan              ZonePlan `json:"plan"`
	Status            string   `json:"status"`
	Paused            bool     `json:"paused"`
	Type              string   `json:"type"`
	Host              struct {
		Name    string
		Website string
	} `json:"host"`
	VanityNS    []string `json:"vanity_name_servers"`
	Betas       []string `json:"betas"`
	DeactReason string   `json:"deactivation_reason"`
	Meta        ZoneMeta `json:"meta"`
}

// ZoneMeta metadata about a zone.
type ZoneMeta struct {
	// custom_certificate_quota is broken - sometimes it's a string, sometimes a number!
	// CustCertQuota     int    `json:"custom_certificate_quota"`
	PageRuleQuota     int  `json:"page_rule_quota"`
	WildcardProxiable bool `json:"wildcard_proxiable"`
	PhishingDetected  bool `json:"phishing_detected"`
}

// ZonePlan contains the plan information for a zone.
type ZonePlan struct {
	ID           string `json:"id"`
	Name         string `json:"name"`
	Price        int    `json:"price"`
	Currency     string `json:"currency"`
	Frequency    string `json:"frequency"`
	LegacyID     string `json:"legacy_id"`
	IsSubscribed bool   `json:"is_subscribed"`
	CanSubscribe bool   `json:"can_subscribe"`
}

// ZoneResponse represents the response from the Zone endpoint.
type ZoneResponse struct {
	Response
	Result []Zone `json:"result"`
}

// ZonePlanResponse represents the response from the Zone Plan endpoint.
type ZonePlanResponse struct {
	Response
	Result []ZonePlan `json:"result"`
}

// type zoneSetting struct {
// 	ID         string `json:"id"`
// 	Editable   bool   `json:"editable"`
// 	ModifiedOn string `json:"modified_on"`
// }
// type zoneSettingStringVal struct {
// 	zoneSetting
// 	Value string `json:"value"`
// }
// type zoneSettingIntVal struct {
// 	zoneSetting
// 	Value int64 `json:"value"`
// }

// ZoneSetting contains settings for a zone.
type ZoneSetting struct {
	ID            string      `json:"id"`
	Editable      bool        `json:"editable"`
	ModifiedOn    string      `json:"modified_on"`
	Value         interface{} `json:"value"`
	TimeRemaining int         `json:"time_remaining"`
}

// ZoneSettingResponse represents the response from the Zone Setting endpoint.
type ZoneSettingResponse struct {
	Response
	Result []ZoneSetting `json:"result"`
}

// DNSRecord represents a DNS record in a zone.
type DNSRecord struct {
	ID         string      `json:"id,omitempty"`
	Type       string      `json:"type,omitempty"`
	Name       string      `json:"name,omitempty"`
	Content    string      `json:"content,omitempty"`
	Proxiable  bool        `json:"proxiable,omitempty"`
	Proxied    bool        `json:"proxied,omitempty"`
	TTL        int         `json:"ttl,omitempty"`
	Locked     bool        `json:"locked,omitempty"`
	ZoneID     string      `json:"zone_id,omitempty"`
	ZoneName   string      `json:"zone_name,omitempty"`
	CreatedOn  string      `json:"created_on,omitempty"`
	ModifiedOn string      `json:"modified_on,omitempty"`
	Data       interface{} `json:"data,omitempty"` // data returned by: SRV, LOC
	Meta       interface{} `json:"meta,omitempty"`
	Priority   int         `json:"priority,omitempty"`
}

// DNSRecordResponse represents the response from the DNS endpoint.
type DNSRecordResponse struct {
	Response
	Result DNSRecord `json:"result"`
}

// DNSListResponse represents the response from the list DNS records endpoint.
type DNSListResponse struct {
	Response
	Result []DNSRecord `json:"result"`
}

// ZoneRailgun represents the status of a Railgun on a zone.
type ZoneRailgun struct {
	ID        string `json:"id"`
	Name      string `json:"string"`
	Enabled   bool   `json:"enabled"`
	Connected bool   `json:"connected"`
}

// ZoneRailgunResponse represents the response from the zone Railgun endpoint.
type ZoneRailgunResponse struct {
	Response
	Result []ZoneRailgun `json:"result"`
}

// ZoneCustomSSL represents custom SSL certificate metadata.
type ZoneCustomSSL struct {
	ID            string     `json:"id"`
	Hosts         []string   `json:"hosts"`
	Issuer        string     `json:"issuer"`
	Priority      int        `json:"priority"`
	Status        string     `json:"success"`
	BundleMethod  string     `json:"bundle_method"`
	ZoneID        string     `json:"zone_id"`
	Permissions   []string   `json:"permissions"`
	UploadedOn    string     `json:"uploaded_on"`
	ModifiedOn    string     `json:"modified_on"`
	ExpiresOn     string     `json:"expires_on"`
	KeylessServer KeylessSSL `json:"keyless_server"`
}

// ZoneCustomSSLResponse represents the response from the zone SSL endpoint.
type ZoneCustomSSLResponse struct {
	Response
	Result []ZoneCustomSSL `json:"result"`
}

// KeylessSSL represents Keyless SSL configuration.
type KeylessSSL struct {
	ID          string   `json:"id"`
	Name        string   `json:"name"`
	Host        string   `json:"host"`
	Port        int      `json:"port"`
	Status      string   `json:"success"`
	Enabled     bool     `json:"enabled"`
	Permissions []string `json:"permissions"`
	CreatedOn   string   `json:"created_on"`
	ModifiedOn  string   `json:"modifed_on"`
}

// KeylessSSLResponse represents the response from the Keyless SSL endpoint.
type KeylessSSLResponse struct {
	Response
	Result []KeylessSSL `json:"result"`
}

// Railgun represents a Railgun configuration.
type Railgun struct {
	ID             string `json:"id"`
	Name           string `json:"name"`
	Status         string `json:"success"`
	Enabled        bool   `json:"enabled"`
	ZonesConnected int    `json:"zones_connected"`
	Build          string `json:"build"`
	Version        string `json:"version"`
	Revision       string `json:"revision"`
	ActivationKey  string `json:"activation_key"`
	ActivatedOn    string `json:"activated_on"`
	CreatedOn      string `json:"created_on"`
	ModifiedOn     string `json:"modified_on"`
	// XXX: UpgradeInfo struct {
	// version string
	// url string
	// } `json:"upgrade_info"`
}

// RailgunResponse represents the response from the Railgun endpoint.
type RailgunResponse struct {
	Response
	Result []Railgun `json:"result"`
}

// CustomPage represents a custom page configuration.
type CustomPage struct {
	CreatedOn      string   `json:"created_on"`
	ModifiedOn     string   `json:"modified_on"`
	URL            string   `json:"url"`
	State          string   `json:"state"`
	RequiredTokens []string `json:"required_tokens"`
	PreviewTarget  string   `json:"preview_target"`
	Description    string   `json:"description"`
}

// CustomPageResponse represents the response from the custom pages endpoint.
type CustomPageResponse struct {
	Response
	Result []CustomPage `json:"result"`
}

// WAFPackage represents a WAF package configuration.
type WAFPackage struct {
	ID            string `json:"id"`
	Name          string `json:"name"`
	Description   string `json:"description"`
	ZoneID        string `json:"zone_id"`
	DetectionMode string `json:"detection_mode"`
	Sensitivity   string `json:"sensitivity"`
	ActionMode    string `json:"action_mode"`
}

// WAFPackagesResponse represents the response from the WAF packages endpoint.
type WAFPackagesResponse struct {
	Response
	Result     []WAFPackage `json:"result"`
	ResultInfo ResultInfo   `json:"result_info"`
}

// WAFRule represents a WAF rule.
type WAFRule struct {
	ID          string `json:"id"`
	Description string `json:"description"`
	Priority    string `json:"priority"`
	PackageID   string `json:"package_id"`
	Group       struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	} `json:"group"`
	Mode         string   `json:"mode"`
	DefaultMode  string   `json:"default_mode"`
	AllowedModes []string `json:"allowed_modes"`
}

// WAFRulesResponse represents the response from the WAF rule endpoint.
type WAFRulesResponse struct {
	Response
	Result     []WAFRule  `json:"result"`
	ResultInfo ResultInfo `json:"result_info"`
}

// PurgeCacheRequest represents the request format made to the purge endpoint.
type PurgeCacheRequest struct {
	Everything bool     `json:"purge_everything,omitempty"`
	Files      []string `json:"files,omitempty"`
	Tags       []string `json:"tags,omitempty"`
}

// PurgeCacheResponse represents the response from the purge endpoint.
type PurgeCacheResponse struct {
	Response
}

// IPs contains a list of IPv4 and IPv6 CIDRs
type IPRanges struct {
	IPv4CIDRs []string `json:"ipv4_cidrs"`
	IPv6CIDRs []string `json:"ipv6_cidrs"`
}

// IPsResponse is the API response containing a list of IPs
type IPsResponse struct {
	Response
	Result IPRanges `json:"result"`
}
<commit_msg>[bugfix] Re-add BaseURL to New()<commit_after>// Package cloudflare implements the CloudFlare v4 API.
package cloudflare

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/pkg/errors"
)

const apiURL = "https://api.cloudflare.com/client/v4"

// API holds the configuration for the current API client. A client should not
// be modified concurrently.
type API struct {
	APIKey     string
	APIEmail   string
	BaseURL    string
	headers    http.Header
	httpClient *http.Client
}

// New creates a new CloudFlare v4 API client.
func New(key, email string, opts ...Option) (*API, error) {
	if key == "" || email == "" {
		return nil, errors.New(errEmptyCredentials)
	}

	api := &API{
		APIKey:   key,
		APIEmail: email,
		BaseURL:  apiURL,
		headers:  make(http.Header),
	}

	err := api.parseOptions(opts...)
	if err != nil {
		return nil, errors.Wrap(err, "options parsing failed")
	}

	// Fall back to http.DefaultClient if the package user does not provide
	// their own.
	if api.httpClient == nil {
		api.httpClient = http.DefaultClient
	}

	return api, nil
}

// NewZone initializes Zone.
func NewZone() *Zone {
	return &Zone{}
}

// ZoneIDByName retrieves a zone's ID from the name.
func (api *API) ZoneIDByName(zoneName string) (string, error) {
	res, err := api.ListZones(zoneName)
	if err != nil {
		return "", errors.Wrap(err, "ListZones command failed")
	}
	for _, zone := range res {
		if zone.Name == zoneName {
			return zone.ID, nil
		}
	}
	return "", errors.New("Zone could not be found")
}

// Params can be turned into a URL query string or a body
// TODO: Give this func a better name
func (api *API) makeRequest(method, uri string, params interface{}) ([]byte, error) {
	// Replace nil with a JSON object if needed
	var reqBody io.Reader
	if params != nil {
		json, err := json.Marshal(params)
		if err != nil {
			return nil, errors.Wrap(err, "Error marshalling params to JSON")
		}
		reqBody = bytes.NewReader(json)
	} else {
		reqBody = nil
	}
	req, err := http.NewRequest(method, api.BaseURL+uri, reqBody)
	if err != nil {
		return nil, errors.Wrap(err, "HTTP request creation failed")
	}

	// Apply any user-defined headers first.
	req.Header = api.headers

	req.Header.Set("X-Auth-Key", api.APIKey)
	req.Header.Set("X-Auth-Email", api.APIEmail)

	// Could be application/json or multipart/form-data
	// req.Header.Add("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, errors.Wrap(err, "HTTP request failed")
	}
	defer resp.Body.Close()
	resBody, err := ioutil.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK {
		if err != nil {
			return nil, errors.Wrap(err, "Error returned from API")
		} else if resBody != nil {
			return nil, errors.New(string(resBody))
		} else {
			return nil, errors.New(resp.Status)
		}
	}

	return resBody, nil
}

// Response is a template.  There will also be a result struct.  There will be a
// unique response type for each response, which will include this type.
type Response struct {
	Success  bool     `json:"success"`
	Errors   []string `json:"errors"`
	Messages []string `json:"messages"`
}

// ResultInfo contains metadata about the Response.
type ResultInfo struct {
	Page    int `json:"page"`
	PerPage int `json:"per_page"`
	Count   int `json:"count"`
	Total   int `json:"total_count"`
}

// User describes a user account.
type User struct {
	ID            string         `json:"id"`
	Email         string         `json:"email"`
	FirstName     string         `json:"first_name"`
	LastName      string         `json:"last_name"`
	Username      string         `json:"username"`
	Telephone     string         `json:"telephone"`
	Country       string         `json:"country"`
	Zipcode       string         `json:"zipcode"`
	CreatedOn     string         `json:"created_on"` // Should this be a time.Date?
	ModifiedOn    string         `json:"modified_on"`
	APIKey        string         `json:"api_key"`
	TwoFA         bool           `json:"two_factor_authentication_enabled"`
	Betas         []string       `json:"betas"`
	Organizations []Organization `json:"organizations"`
}

// UserResponse wraps a response containing User accounts.
type UserResponse struct {
	Response
	Result User `json:"result"`
}

// Owner describes the resource owner.
type Owner struct {
	ID        string `json:"id"`
	Email     string `json:"email"`
	OwnerType string `json:"owner_type"`
}

// Zone describes a CloudFlare zone.
type Zone struct {
	ID                string   `json:"id"`
	Name              string   `json:"name"`
	DevMode           int      `json:"development_mode"`
	OriginalNS        []string `json:"original_name_servers"`
	OriginalRegistrar string   `json:"original_registrar"`
	OriginalDNSHost   string   `json:"original_dnshost"`
	CreatedOn         string   `json:"created_on"`
	ModifiedOn        string   `json:"modified_on"`
	NameServers       []string `json:"name_servers"`
	Owner             Owner    `json:"owner"`
	Permissions       []string `json:"permissions"`
	Plan              ZonePlan `json:"plan"`
	Status            string   `json:"status"`
	Paused            bool     `json:"paused"`
	Type              string   `json:"type"`
	Host              struct {
		Name    string
		Website string
	} `json:"host"`
	VanityNS    []string `json:"vanity_name_servers"`
	Betas       []string `json:"betas"`
	DeactReason string   `json:"deactivation_reason"`
	Meta        ZoneMeta `json:"meta"`
}

// ZoneMeta metadata about a zone.
type ZoneMeta struct {
	// custom_certificate_quota is broken - sometimes it's a string, sometimes a number!
	// CustCertQuota     int    `json:"custom_certificate_quota"`
	PageRuleQuota     int  `json:"page_rule_quota"`
	WildcardProxiable bool `json:"wildcard_proxiable"`
	PhishingDetected  bool `json:"phishing_detected"`
}

// ZonePlan contains the plan information for a zone.
type ZonePlan struct {
	ID           string `json:"id"`
	Name         string `json:"name"`
	Price        int    `json:"price"`
	Currency     string `json:"currency"`
	Frequency    string `json:"frequency"`
	LegacyID     string `json:"legacy_id"`
	IsSubscribed bool   `json:"is_subscribed"`
	CanSubscribe bool   `json:"can_subscribe"`
}

// ZoneResponse represents the response from the Zone endpoint.
type ZoneResponse struct {
	Response
	Result []Zone `json:"result"`
}

// ZonePlanResponse represents the response from the Zone Plan endpoint.
type ZonePlanResponse struct {
	Response
	Result []ZonePlan `json:"result"`
}

// type zoneSetting struct {
// 	ID         string `json:"id"`
// 	Editable   bool   `json:"editable"`
// 	ModifiedOn string `json:"modified_on"`
// }
// type zoneSettingStringVal struct {
// 	zoneSetting
// 	Value string `json:"value"`
// }
// type zoneSettingIntVal struct {
// 	zoneSetting
// 	Value int64 `json:"value"`
// }

// ZoneSetting contains settings for a zone.
type ZoneSetting struct {
	ID            string      `json:"id"`
	Editable      bool        `json:"editable"`
	ModifiedOn    string      `json:"modified_on"`
	Value         interface{} `json:"value"`
	TimeRemaining int         `json:"time_remaining"`
}

// ZoneSettingResponse represents the response from the Zone Setting endpoint.
type ZoneSettingResponse struct {
	Response
	Result []ZoneSetting `json:"result"`
}

// DNSRecord represents a DNS record in a zone.
type DNSRecord struct {
	ID         string      `json:"id,omitempty"`
	Type       string      `json:"type,omitempty"`
	Name       string      `json:"name,omitempty"`
	Content    string      `json:"content,omitempty"`
	Proxiable  bool        `json:"proxiable,omitempty"`
	Proxied    bool        `json:"proxied,omitempty"`
	TTL        int         `json:"ttl,omitempty"`
	Locked     bool        `json:"locked,omitempty"`
	ZoneID     string      `json:"zone_id,omitempty"`
	ZoneName   string      `json:"zone_name,omitempty"`
	CreatedOn  string      `json:"created_on,omitempty"`
	ModifiedOn string      `json:"modified_on,omitempty"`
	Data       interface{} `json:"data,omitempty"` // data returned by: SRV, LOC
	Meta       interface{} `json:"meta,omitempty"`
	Priority   int         `json:"priority,omitempty"`
}

// DNSRecordResponse represents the response from the DNS endpoint.
type DNSRecordResponse struct {
	Response
	Result DNSRecord `json:"result"`
}

// DNSListResponse represents the response from the list DNS records endpoint.
type DNSListResponse struct {
	Response
	Result []DNSRecord `json:"result"`
}

// ZoneRailgun represents the status of a Railgun on a zone.
type ZoneRailgun struct {
	ID        string `json:"id"`
	Name      string `json:"string"`
	Enabled   bool   `json:"enabled"`
	Connected bool   `json:"connected"`
}

// ZoneRailgunResponse represents the response from the zone Railgun endpoint.
type ZoneRailgunResponse struct {
	Response
	Result []ZoneRailgun `json:"result"`
}

// ZoneCustomSSL represents custom SSL certificate metadata.
type ZoneCustomSSL struct {
	ID            string     `json:"id"`
	Hosts         []string   `json:"hosts"`
	Issuer        string     `json:"issuer"`
	Priority      int        `json:"priority"`
	Status        string     `json:"success"`
	BundleMethod  string     `json:"bundle_method"`
	ZoneID        string     `json:"zone_id"`
	Permissions   []string   `json:"permissions"`
	UploadedOn    string     `json:"uploaded_on"`
	ModifiedOn    string     `json:"modified_on"`
	ExpiresOn     string     `json:"expires_on"`
	KeylessServer KeylessSSL `json:"keyless_server"`
}

// ZoneCustomSSLResponse represents the response from the zone SSL endpoint.
type ZoneCustomSSLResponse struct {
	Response
	Result []ZoneCustomSSL `json:"result"`
}

// KeylessSSL represents Keyless SSL configuration.
type KeylessSSL struct {
	ID          string   `json:"id"`
	Name        string   `json:"name"`
	Host        string   `json:"host"`
	Port        int      `json:"port"`
	Status      string   `json:"success"`
	Enabled     bool     `json:"enabled"`
	Permissions []string `json:"permissions"`
	CreatedOn   string   `json:"created_on"`
	ModifiedOn  string   `json:"modifed_on"`
}

// KeylessSSLResponse represents the response from the Keyless SSL endpoint.
type KeylessSSLResponse struct {
	Response
	Result []KeylessSSL `json:"result"`
}

// Railgun represents a Railgun configuration.
type Railgun struct {
	ID             string `json:"id"`
	Name           string `json:"name"`
	Status         string `json:"success"`
	Enabled        bool   `json:"enabled"`
	ZonesConnected int    `json:"zones_connected"`
	Build          string `json:"build"`
	Version        string `json:"version"`
	Revision       string `json:"revision"`
	ActivationKey  string `json:"activation_key"`
	ActivatedOn    string `json:"activated_on"`
	CreatedOn      string `json:"created_on"`
	ModifiedOn     string `json:"modified_on"`
	// XXX: UpgradeInfo struct {
	// version string
	// url string
	// } `json:"upgrade_info"`
}

// RailgunResponse represents the response from the Railgun endpoint.
type RailgunResponse struct {
	Response
	Result []Railgun `json:"result"`
}

// CustomPage represents a custom page configuration.
type CustomPage struct {
	CreatedOn      string   `json:"created_on"`
	ModifiedOn     string   `json:"modified_on"`
	URL            string   `json:"url"`
	State          string   `json:"state"`
	RequiredTokens []string `json:"required_tokens"`
	PreviewTarget  string   `json:"preview_target"`
	Description    string   `json:"description"`
}

// CustomPageResponse represents the response from the custom pages endpoint.
type CustomPageResponse struct {
	Response
	Result []CustomPage `json:"result"`
}

// WAFPackage represents a WAF package configuration.
type WAFPackage struct {
	ID            string `json:"id"`
	Name          string `json:"name"`
	Description   string `json:"description"`
	ZoneID        string `json:"zone_id"`
	DetectionMode string `json:"detection_mode"`
	Sensitivity   string `json:"sensitivity"`
	ActionMode    string `json:"action_mode"`
}

// WAFPackagesResponse represents the response from the WAF packages endpoint.
type WAFPackagesResponse struct {
	Response
	Result     []WAFPackage `json:"result"`
	ResultInfo ResultInfo   `json:"result_info"`
}

// WAFRule represents a WAF rule.
type WAFRule struct {
	ID          string `json:"id"`
	Description string `json:"description"`
	Priority    string `json:"priority"`
	PackageID   string `json:"package_id"`
	Group       struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	} `json:"group"`
	Mode         string   `json:"mode"`
	DefaultMode  string   `json:"default_mode"`
	AllowedModes []string `json:"allowed_modes"`
}

// WAFRulesResponse represents the response from the WAF rule endpoint.
type WAFRulesResponse struct {
	Response
	Result     []WAFRule  `json:"result"`
	ResultInfo ResultInfo `json:"result_info"`
}

// PurgeCacheRequest represents the request format made to the purge endpoint.
type PurgeCacheRequest struct {
	Everything bool     `json:"purge_everything,omitempty"`
	Files      []string `json:"files,omitempty"`
	Tags       []string `json:"tags,omitempty"`
}

// PurgeCacheResponse represents the response from the purge endpoint.
type PurgeCacheResponse struct {
	Response
}

// IPs contains a list of IPv4 and IPv6 CIDRs
type IPRanges struct {
	IPv4CIDRs []string `json:"ipv4_cidrs"`
	IPv6CIDRs []string `json:"ipv6_cidrs"`
}

// IPsResponse is the API response containing a list of IPs
type IPsResponse struct {
	Response
	Result IPRanges `json:"result"`
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

// If n <= 0, dump everything, else only dump the first n blocks.
// n is 1 relative, i.e., if you want the first two blocks dumped, pass
// n==2, not n==1.
func dumpBucket(label string, bucket *ScriptBucket, n int) {
	fmt.Printf("#\n# Script @%s from %s \n#\n", label, bucket.fileName)
	delimFmt := "#" + strings.Repeat("-", 70) + "#  %s %d\n"
	for i, block := range bucket.script {
		if n > 0 && i >= n {
			break
		}
		fmt.Printf(delimFmt, "Start", i+1)
		fmt.Printf("echo \"Block '%s' (%d/%d in %s) of %s\"\n####\n",
			block.labels[0], i+1, len(bucket.script), label, bucket.fileName)
		fmt.Print(block.codeText)
		fmt.Printf(delimFmt, "End", i+1)
		fmt.Println()
	}
}

func emitStraightScript(label string, scriptBuckets []*ScriptBucket) {
	for _, bucket := range scriptBuckets {
		dumpBucket(label, bucket, 0)
	}
	fmt.Printf("echo \" \"\n")
	fmt.Printf("echo \"All done.  No errors.\"\n")
}

// Emit the first script normally, then emit it again, as well as the
// the remaining scripts, so that they run in a subshell.
//
// This allows the aggregrate script to be structured as 1) a preamble
// initialization script that impacts the environment of the active
// shell, followed by 2) a script that executes as a subshell that
// exits on error.  An exit in (2) won't cause the active shell (most
// likely a terminal) to close.
//
// The first script must be able to complete without exit on error
// because its not running as a subshell.  So it should just set
// environment variables and/or define shell funtions.
func emitPreambledScript(label string, scriptBuckets []*ScriptBucket, n int) {
	dumpBucket(label, scriptBuckets[0], n)
	delim := "HANDLED_SCRIPT"
	fmt.Printf(" bash -e <<'%s'\n", delim)
	fmt.Printf("function handledTrouble() {\n")
	fmt.Printf("  echo \" \"\n")
	fmt.Printf("  echo \"Unable to continue!\"\n")
	fmt.Printf("  exit 1\n")
	fmt.Printf("}\n")
	fmt.Printf("trap handledTrouble INT TERM\n")
	emitStraightScript(label, scriptBuckets)
	fmt.Printf("%s\n", delim)
}

func usage() {
	fmt.Fprintf(os.Stderr, "\nUsage:  %s {label} {fileName}...\n", os.Args[0])
	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr,
		`
Reads markdown files, extracts code blocks with a given @label, and
either runs them in a subshell or emits them to stdout.

If the markdown file contains

  Blah blah blah.
  <!-- @goHome @foo -->
  '''
  cd $HOME
  '''
  Blah blah blah.
  <!-- @echoApple @apple -->
  '''
  echo "an apple a day keeps the doctor away"
  '''
  Blah blah blah.
  <!-- @echoCloseStar @foo @baz -->
  '''
  echo "Proxima Centauri"
  '''
  Blah blah blah.

then the command '{this} foo {fileName}' emits:

  cd $HOME
  echo "Proxima Centauri"

Pipe output to 'source /dev/stdin' to run it directly.

Use --subshell to run the blocks in a subshell leaving your current
shell env vars and pwd unchanged.  The code blocks can, however, do
anything to your computer that you can.
`)
}

func main() {
	flag.Usage = usage
	preambled := flag.Bool("preambled", false,
		"Place all scripts in a subshell, preambled by the first script.")
	monkey := flag.Int("monkey", -1,
		"Place all scripts in a subshell, preambled by the first {n} blocks in the first script.")
	subshell := flag.Bool("subshell", false,
		"Run extracted blocks in subshell (leaves your env vars and pwd unchanged).")
	swallow := flag.Bool("swallow", false,
		"Swallow errors from subshell (non-zero exit only on problems in driver code).")
	flag.Parse()
	if *swallow && !*subshell {
		fmt.Fprintf(os.Stderr, "Makes no sense to specify --swallow but not --subshell.\n")
		usage()
		os.Exit(1)
	}
	if flag.NArg() < 2 {
		usage()
		os.Exit(1)
	}
	label := flag.Arg(0)
	scriptBuckets := make([]*ScriptBucket, flag.NArg()-1)

	for i := 1; i < flag.NArg(); i++ {
		fileName := flag.Arg(i)
		contents, err := ioutil.ReadFile(fileName)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to read %q\n", fileName)
			usage()
			os.Exit(2)
		}
		m := Parse(string(contents))
		script, ok := m[label]
		if !ok {
			fmt.Fprintf(os.Stderr, "No block labelled %q in file %q.\n", label, fileName)
			os.Exit(3)
		}
		scriptBuckets[i-1] = &ScriptBucket{fileName, script}
	}

	if len(scriptBuckets) < 1 {
		return
	}

	// Plan
	// 1) Leave existing behavior, but push a new mdrip binary with a
	//	  new flag "monkey".  Existing Makefile and tests pass.
	// 2) modify Makefile to use the new "monkey" flag
	//    everything still works.  push new website, using the new flag only.
	// 3) Modify the old (unused) "preambled" flag to work just like the new flag.
	// 4) modify Makefile to use the "preambled" flag in the new way.
	//    Everything still works.  push new website.
	// 5) remove the "monkey" flag from mdrip
	if !*subshell {
		n := *monkey
		if *preambled {
			// Trumps for now
			n = 0
		}
		if *preambled || n >= 0 {
			emitPreambledScript(label, scriptBuckets, n)
		} else {
			emitStraightScript(label, scriptBuckets)
		}
		return
	}

	result := RunInSubShell(scriptBuckets)
	if result.err != nil {
		Complain(result, label)
		if !*swallow {
			log.Fatal(result.err)
		}
	}
}
<commit_msg>make preambled identical to monkey<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

// If n <= 0, dump everything, else only dump the first n blocks.
// n is 1 relative, i.e., if you want the first two blocks dumped, pass
// n==2, not n==1.
func dumpBucket(label string, bucket *ScriptBucket, n int) {
	fmt.Printf("#\n# Script @%s from %s \n#\n", label, bucket.fileName)
	delimFmt := "#" + strings.Repeat("-", 70) + "#  %s %d\n"
	for i, block := range bucket.script {
		if n > 0 && i >= n {
			break
		}
		fmt.Printf(delimFmt, "Start", i+1)
		fmt.Printf("echo \"Block '%s' (%d/%d in %s) of %s\"\n####\n",
			block.labels[0], i+1, len(bucket.script), label, bucket.fileName)
		fmt.Print(block.codeText)
		fmt.Printf(delimFmt, "End", i+1)
		fmt.Println()
	}
}

func emitStraightScript(label string, scriptBuckets []*ScriptBucket) {
	for _, bucket := range scriptBuckets {
		dumpBucket(label, bucket, 0)
	}
	fmt.Printf("echo \" \"\n")
	fmt.Printf("echo \"All done.  No errors.\"\n")
}

// Emit the first script normally, then emit it again, as well as the
// the remaining scripts, so that they run in a subshell.
//
// This allows the aggregrate script to be structured as 1) a preamble
// initialization script that impacts the environment of the active
// shell, followed by 2) a script that executes as a subshell that
// exits on error.  An exit in (2) won't cause the active shell (most
// likely a terminal) to close.
//
// The first script must be able to complete without exit on error
// because its not running as a subshell.  So it should just set
// environment variables and/or define shell funtions.
func emitPreambledScript(label string, scriptBuckets []*ScriptBucket, n int) {
	dumpBucket(label, scriptBuckets[0], n)
	delim := "HANDLED_SCRIPT"
	fmt.Printf(" bash -e <<'%s'\n", delim)
	fmt.Printf("function handledTrouble() {\n")
	fmt.Printf("  echo \" \"\n")
	fmt.Printf("  echo \"Unable to continue!\"\n")
	fmt.Printf("  exit 1\n")
	fmt.Printf("}\n")
	fmt.Printf("trap handledTrouble INT TERM\n")
	emitStraightScript(label, scriptBuckets)
	fmt.Printf("%s\n", delim)
}

func usage() {
	fmt.Fprintf(os.Stderr, "\nUsage:  %s {label} {fileName}...\n", os.Args[0])
	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr,
		`
Reads markdown files, extracts code blocks with a given @label, and
either runs them in a subshell or emits them to stdout.

If the markdown file contains

  Blah blah blah.
  <!-- @goHome @foo -->
  '''
  cd $HOME
  '''
  Blah blah blah.
  <!-- @echoApple @apple -->
  '''
  echo "an apple a day keeps the doctor away"
  '''
  Blah blah blah.
  <!-- @echoCloseStar @foo @baz -->
  '''
  echo "Proxima Centauri"
  '''
  Blah blah blah.

then the command '{this} foo {fileName}' emits:

  cd $HOME
  echo "Proxima Centauri"

Pipe output to 'source /dev/stdin' to run it directly.

Use --subshell to run the blocks in a subshell leaving your current
shell env vars and pwd unchanged.  The code blocks can, however, do
anything to your computer that you can.
`)
}

func main() {
	flag.Usage = usage
	preambled := flag.Int("preambled", -1,
		"Place all scripts in a subshell, preambled by the first {n} blocks in the first script.")
	monkey := flag.Int("monkey", -2,
		"Place all scripts in a subshell, preambled by the first {n} blocks in the first script.")
	subshell := flag.Bool("subshell", false,
		"Run extracted blocks in subshell (leaves your env vars and pwd unchanged).")
	swallow := flag.Bool("swallow", false,
		"Swallow errors from subshell (non-zero exit only on problems in driver code).")
	flag.Parse()
	if *swallow && !*subshell {
		fmt.Fprintf(os.Stderr, "Makes no sense to specify --swallow but not --subshell.\n")
		usage()
		os.Exit(1)
	}
	if flag.NArg() < 2 {
		usage()
		os.Exit(1)
	}
	label := flag.Arg(0)
	scriptBuckets := make([]*ScriptBucket, flag.NArg()-1)

	for i := 1; i < flag.NArg(); i++ {
		fileName := flag.Arg(i)
		contents, err := ioutil.ReadFile(fileName)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to read %q\n", fileName)
			usage()
			os.Exit(2)
		}
		m := Parse(string(contents))
		script, ok := m[label]
		if !ok {
			fmt.Fprintf(os.Stderr, "No block labelled %q in file %q.\n", label, fileName)
			os.Exit(3)
		}
		scriptBuckets[i-1] = &ScriptBucket{fileName, script}
	}

	if len(scriptBuckets) < 1 {
		return
	}

	// Plan
	// DONE 1) Leave existing behavior, but push a new mdrip binary with a
	//	  new flag "monkey".  Existing Makefile and tests pass.
	// DONE 2) modify Makefile to use the new "monkey" flag
	//    everything still works.  push new website, using the new flag only.
	// 3) Modify the old (now unused) "preambled" flag to work just like the new flag.
	// 4) modify Makefile to use the "preambled" flag in the new way.
	//    Everything still works.  push new website.
	// 5) remove the "monkey" flag from mdrip
	if !*subshell {
		n := *preambled
		if *monkey != -2 {
			// monkey trumps for now
			n = *monkey
		}
		if n >= 0 {
			emitPreambledScript(label, scriptBuckets, n)
		} else {
			emitStraightScript(label, scriptBuckets)
		}
		return
	}

	result := RunInSubShell(scriptBuckets)
	if result.err != nil {
		Complain(result, label)
		if !*swallow {
			log.Fatal(result.err)
		}
	}
}
<|endoftext|>


<commit_before>// +build linux darwin freebsd

package main

import (
	_ "expvar"
	"fmt"
	"github.com/darron/goshe/cmd"
	"log"
	"log/syslog"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"syscall"
)

// CompileDate tracks when the binary was compiled. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var CompileDate = "No date provided."

// GitCommit tracks the SHA of the built binary. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var GitCommit = "No revision provided."

// Version is the version of the built binary. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var Version = "No version provided."

// GoVersion details the version of Go this was compiled with.
var GoVersion = runtime.Version()

// The name of the program.
var programName = "goshe"

func main() {
	logwriter, e := syslog.New(syslog.LOG_NOTICE, programName)
	if e == nil {
		log.SetOutput(logwriter)
	}
	cmd.Log(fmt.Sprintf("%s version: %s", programName, Version), "info")

	args := os.Args[1:]
	for _, arg := range args {
		if arg == "-v" || arg == "--version" {
			fmt.Printf("Version  : %s\nRevision : %s\nDate     : %s\nGo       : %s\n", Version, GitCommit, CompileDate, GoVersion)
			os.Exit(0)
		}
	}
	// Setup nice shutdown with CTRL-C.
	c := make(chan os.Signal)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go handleCtrlC(c)

	// Listen for expvar
	go setupExpvarHTTP()

	cmd.RootCmd.Execute()
}

func setupExpvarHTTP() {
	// Listen for expvar
	http.ListenAndServe(":1313", nil)
}

// Any cleanup tasks on shutdown could happen here.
func handleCtrlC(c chan os.Signal) {
	sig := <-c
	message := fmt.Sprintf("Received '%s' - shutting down.", sig)
	cmd.Log(message, "info")
	fmt.Printf("%s\n", message)
	os.Exit(0)
}
<commit_msg>If we have GOSHE_DEBUG set - then listen with expvar.<commit_after>// +build linux darwin freebsd

package main

import (
	_ "expvar"
	"fmt"
	"github.com/darron/goshe/cmd"
	"log"
	"log/syslog"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"syscall"
)

// CompileDate tracks when the binary was compiled. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var CompileDate = "No date provided."

// GitCommit tracks the SHA of the built binary. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var GitCommit = "No revision provided."

// Version is the version of the built binary. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var Version = "No version provided."

// GoVersion details the version of Go this was compiled with.
var GoVersion = runtime.Version()

// The name of the program.
var programName = "goshe"

func main() {
	logwriter, e := syslog.New(syslog.LOG_NOTICE, programName)
	if e == nil {
		log.SetOutput(logwriter)
	}
	cmd.Log(fmt.Sprintf("%s version: %s", programName, Version), "info")

	args := os.Args[1:]
	for _, arg := range args {
		if arg == "-v" || arg == "--version" {
			fmt.Printf("Version  : %s\nRevision : %s\nDate     : %s\nGo       : %s\n", Version, GitCommit, CompileDate, GoVersion)
			os.Exit(0)
		}
	}
	// Setup nice shutdown with CTRL-C.
	c := make(chan os.Signal)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go handleCtrlC(c)

	// Listen for expvar if we have GOSHE_DEBUG set.
	if os.Getenv("GOSHE_DEBUG") != "" {
		go setupExpvarHTTP()
	}

	cmd.RootCmd.Execute()
}

func setupExpvarHTTP() {
	// Listen for expvar
	http.ListenAndServe(":1313", nil)
}

// Any cleanup tasks on shutdown could happen here.
func handleCtrlC(c chan os.Signal) {
	sig := <-c
	message := fmt.Sprintf("Received '%s' - shutting down.", sig)
	cmd.Log(message, "info")
	fmt.Printf("%s\n", message)
	os.Exit(0)
}
<|endoftext|>


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

// Pythia is a web application front-end for the Go source code guru.
package main // import "github.com/fzipp/pythia"

import (
	"flag"
	"fmt"
	"go/build"
	"go/token"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"sort"
	"strings"

	"golang.org/x/tools/go/loader"
)

var (
	guruPath = ""
	httpAddr = flag.String("http", ":8080", "HTTP listen address")
	verbose  = flag.Bool("v", false, "Verbose mode: print incoming queries")
	open     = flag.Bool("open", true, "Try to open browser")
	tags     = flag.String("tags", "", "Tags to use when importing packages")
	args     []string
	files    []string
	packages []*loader.PackageInfo
	prog     *loader.Program
)

func init() {
	if os.Getenv("GOMAXPROCS") == "" {
		n := runtime.NumCPU()
		if n < 4 {
			n = 4
		}
		runtime.GOMAXPROCS(n)
	}
}

const useHelp = "Run 'pythia -help' for more information.\n"

const helpMessage = `Web frontend for the Go source code guru.
Usage: pythia [<flag> ...] <args> ...

The -http flag specifies the HTTP service address (e.g., ':6060').

The -tags flag specifies comma separated tags to use when importing
code (e.g., 'foo,!darwin').

The -open flag determines, whether the application should try to
open the browser. It is set to 'true' by default. If set to 'false'
the browser will not be launched.

The -v flag enables verbose mode, in which every incoming query
to the guru is logged to the standard output.
` + loader.FromArgsUsage + `
Examples:

Start pythia with the scope of package guru:
% pythia golang.org/x/tools/cmd/guru

Start pythia with the scope of package image/png on port 8081,
but don't open the browser:
% pythia -http=:8081 -open=false image/png
`

func main() {
	var err error
	// Check if guru is in the path.
	guruPath, err = exec.LookPath("guru")
	if err != nil {
		log.Fatal("Can't find guru in your path")
		return
	}
	flag.Usage = func() {}
	flag.CommandLine.Init(os.Args[0], flag.ContinueOnError)
	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
		if err == flag.ErrHelp {
			fmt.Println(helpMessage)
		} else {
			fmt.Fprint(os.Stderr, useHelp)
		}
		os.Exit(2)
	}
	args = flag.Args()
	if len(args) == 0 {
		fmt.Fprint(os.Stderr, "Error: no package arguments.\n"+useHelp)
		os.Exit(2)
	}

	settings := build.Default
	settings.BuildTags = strings.Split(*tags, ",")
	conf := loader.Config{Build: &settings}
	_, err = conf.FromArgs(args, true)
	exitOn(err)
	prog, err = conf.Load()
	exitOn(err)
	files = scopeFiles(prog)
	packages = sortedPackages(prog)

	registerHandlers()

	srv := &http.Server{Addr: *httpAddr}
	l, err := net.Listen("tcp", srv.Addr)
	exitOn(err)
	if *open {
		url := fmt.Sprintf("http://localhost%s/", *httpAddr)
		if !startBrowser(url) {
			fmt.Println(url)
		}
	}
	exitError(srv.Serve(l))
}

func registerHandlers() {
	http.HandleFunc("/", serveIndex)
	http.HandleFunc("/source", serveSource)
	http.HandleFunc("/file", serveFile)
	http.HandleFunc("/query", serveQuery)
	staticPrefix := "/static/"
	http.Handle(staticPrefix, http.StripPrefix(staticPrefix, http.HandlerFunc(serveStatic)))
}

// byPath makes a slice of package infos sortable by package path.
type byPath []*loader.PackageInfo

// sortedPackages returns all packages of a program, sorted by package path.
func sortedPackages(prog *loader.Program) []*loader.PackageInfo {
	pkgs := make([]*loader.PackageInfo, 0, len(prog.AllPackages))
	for _, p := range prog.AllPackages {
		pkgs = append(pkgs, p)
	}
	sort.Slice(pkgs, func(i, j int) bool {
		return pkgs[i].Pkg.Path() < pkgs[j].Pkg.Path()
	})
	return pkgs
}

// scopeFiles returns a new slice containing the full paths of all the files
// imported by the loader, sorted in increasing order.
func scopeFiles(prog *loader.Program) []string {
	var files []string
	prog.Fset.Iterate(func(f *token.File) bool {
		files = append(files, f.Name())
		return true
	})
	sort.Strings(files)
	return files
}

// startBrowser tries to open the URL in a browser
// and reports whether it succeeds.
func startBrowser(url string) bool {
	// try to start the browser
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}
	cmd := exec.Command(args[0], append(args[1:], url)...)
	return cmd.Start() == nil
}

func exitOn(err error) {
	if err != nil {
		exitError(err)
	}
}

func exitError(err error) {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}
<commit_msg>remove unused type<commit_after>// Copyright 2013 Frederik Zipp.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Pythia is a web application front-end for the Go source code guru.
package main // import "github.com/fzipp/pythia"

import (
	"flag"
	"fmt"
	"go/build"
	"go/token"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"sort"
	"strings"

	"golang.org/x/tools/go/loader"
)

var (
	guruPath = ""
	httpAddr = flag.String("http", ":8080", "HTTP listen address")
	verbose  = flag.Bool("v", false, "Verbose mode: print incoming queries")
	open     = flag.Bool("open", true, "Try to open browser")
	tags     = flag.String("tags", "", "Tags to use when importing packages")
	args     []string
	files    []string
	packages []*loader.PackageInfo
	prog     *loader.Program
)

func init() {
	if os.Getenv("GOMAXPROCS") == "" {
		n := runtime.NumCPU()
		if n < 4 {
			n = 4
		}
		runtime.GOMAXPROCS(n)
	}
}

const useHelp = "Run 'pythia -help' for more information.\n"

const helpMessage = `Web frontend for the Go source code guru.
Usage: pythia [<flag> ...] <args> ...

The -http flag specifies the HTTP service address (e.g., ':6060').

The -tags flag specifies comma separated tags to use when importing
code (e.g., 'foo,!darwin').

The -open flag determines, whether the application should try to
open the browser. It is set to 'true' by default. If set to 'false'
the browser will not be launched.

The -v flag enables verbose mode, in which every incoming query
to the guru is logged to the standard output.
` + loader.FromArgsUsage + `
Examples:

Start pythia with the scope of package guru:
% pythia golang.org/x/tools/cmd/guru

Start pythia with the scope of package image/png on port 8081,
but don't open the browser:
% pythia -http=:8081 -open=false image/png
`

func main() {
	var err error
	// Check if guru is in the path.
	guruPath, err = exec.LookPath("guru")
	if err != nil {
		log.Fatal("Can't find guru in your path")
		return
	}
	flag.Usage = func() {}
	flag.CommandLine.Init(os.Args[0], flag.ContinueOnError)
	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
		if err == flag.ErrHelp {
			fmt.Println(helpMessage)
		} else {
			fmt.Fprint(os.Stderr, useHelp)
		}
		os.Exit(2)
	}
	args = flag.Args()
	if len(args) == 0 {
		fmt.Fprint(os.Stderr, "Error: no package arguments.\n"+useHelp)
		os.Exit(2)
	}

	settings := build.Default
	settings.BuildTags = strings.Split(*tags, ",")
	conf := loader.Config{Build: &settings}
	_, err = conf.FromArgs(args, true)
	exitOn(err)
	prog, err = conf.Load()
	exitOn(err)
	files = scopeFiles(prog)
	packages = sortedPackages(prog)

	registerHandlers()

	srv := &http.Server{Addr: *httpAddr}
	l, err := net.Listen("tcp", srv.Addr)
	exitOn(err)
	if *open {
		url := fmt.Sprintf("http://localhost%s/", *httpAddr)
		if !startBrowser(url) {
			fmt.Println(url)
		}
	}
	exitError(srv.Serve(l))
}

func registerHandlers() {
	http.HandleFunc("/", serveIndex)
	http.HandleFunc("/source", serveSource)
	http.HandleFunc("/file", serveFile)
	http.HandleFunc("/query", serveQuery)
	staticPrefix := "/static/"
	http.Handle(staticPrefix, http.StripPrefix(staticPrefix, http.HandlerFunc(serveStatic)))
}

// sortedPackages returns all packages of a program, sorted by package path.
func sortedPackages(prog *loader.Program) []*loader.PackageInfo {
	pkgs := make([]*loader.PackageInfo, 0, len(prog.AllPackages))
	for _, p := range prog.AllPackages {
		pkgs = append(pkgs, p)
	}
	sort.Slice(pkgs, func(i, j int) bool {
		return pkgs[i].Pkg.Path() < pkgs[j].Pkg.Path()
	})
	return pkgs
}

// scopeFiles returns a new slice containing the full paths of all the files
// imported by the loader, sorted in increasing order.
func scopeFiles(prog *loader.Program) []string {
	var files []string
	prog.Fset.Iterate(func(f *token.File) bool {
		files = append(files, f.Name())
		return true
	})
	sort.Strings(files)
	return files
}

// startBrowser tries to open the URL in a browser
// and reports whether it succeeds.
func startBrowser(url string) bool {
	// try to start the browser
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}
	cmd := exec.Command(args[0], append(args[1:], url)...)
	return cmd.Start() == nil
}

func exitOn(err error) {
	if err != nil {
		exitError(err)
	}
}

func exitError(err error) {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"log"
	"io"
)

func main() {
	http.HandleFunc("/", defaultHandler)
	http.ListenAndServe(":8080",nil)
}

// Default Request Handler
func defaultHandler(w http.ResponseWriter, r *http.Request) {
	client := http.Client{}
	req, _ := http.NewRequest(r.Method, r.RequestURI, nil)
	req.Header.Set("Range", r.Header.Get("Range"))
	resp, err := client.Do(req)
	if err != nil {
		log.Println(err.Error())
	}
	for k, v := range resp.Header {
		w.Header().Set(k, v[0])
	}
	w.WriteHeader(resp.StatusCode)
	_, err = io.Copy(w, resp.Body)
	if err != nil {
		log.Println(err.Error())
	}

}

<commit_msg>support post<commit_after>package main

import (
	"io"
	"log"
	"net/http"
)

func main() {
	log.Println("proxy started")
	http.HandleFunc("/", defaultHandler)
	http.ListenAndServe(":8088", nil)
}

// Default Request Handler
func defaultHandler(w http.ResponseWriter, r *http.Request) {
	client := http.Client{}
	req, _ := http.NewRequest(r.Method, r.RequestURI, r.Body)
	req.Header.Set("Range", r.Header.Get("Range"))
	resp, err := client.Do(req)
	if err != nil {
		log.Println(err.Error())
	}
	for k, v := range resp.Header {
		w.Header().Set(k, v[0])
	}
	w.WriteHeader(resp.StatusCode)
	_, err = io.Copy(w, resp.Body)
	if err != nil {
		log.Println(err.Error())
	}

}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/textproto"
	"os"
	"time"
)

func init() {
	log.SetFlags(log.Lshortfile)
}

const PORT = "1039"

var duration = flag.Int("duration", 2, "How long the app runs in days.")

func main() {
	flag.Parse()

	expiretimer := time.NewTimer(time.Hour * 24 * time.Duration(*duration))
	go func() {
		<-expiretimer.C
		println("Logger expired after days:", duration)
		os.Exit(0)
	}()

	host := flag.Arg(0)
	conn, err := net.Dial("tcp", host+":"+PORT)
	if err != nil {
		// handle error
		log.Println("Could not connect to demon", err)
		os.Exit(1)
	}
	defer conn.Close()

	var buffer bytes.Buffer

	check(err)

	reader := bufio.NewReader(conn)
	tp := textproto.NewReader(reader)

	f, err := os.Create("file.txt")
	check(err)
	defer f.Close()
	w := bufio.NewWriter(f)

	flushticker := time.NewTicker(time.Hour)
	go func() {
		for t := range flushticker.C {
			fmt.Println("Writting file to disk at", t)
			err := w.Flush()
			check(err)
		}
	}()

	for {
		line, _ := tp.ReadLine()
		fmt.Fprintln(w, line)
		fmt.Println(line)
		buffer.WriteString(line + "\n")
		err := ioutil.WriteFile("test", buffer.Bytes(), 0644)
		check(err)
	}
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}
<commit_msg>handling interrupt<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/textproto"
	"os"
	"os/signal"
	"time"
)

func init() {
	log.SetFlags(log.Lshortfile)
}

const PORT = "1039"

var age = flag.Int("age", 2, "How long the app runs in days.")
var host = flag.String("host", "127.0.0.1", "Host IP")
var interval = flag.Int("flush", 3600, "Flush interval in seconds")

func main() {
	flag.Parse()
	// TODO: loop over do manual retry, block with a channel
	// http://stackoverflow.com/questions/23395519/reconnect-tcp-on-eof-in-go
	conn, err := net.Dial("tcp", *host+":"+PORT)
	if err != nil {
		log.Println("Could not connect to demon", err)
		os.Exit(1)
	}
	defer conn.Close()

	var buffer bytes.Buffer

	check(err)

	reader := bufio.NewReader(conn)
	tp := textproto.NewReader(reader)

	// todo: append if exists
	f, err := os.Create("file.txt")
	check(err)
	defer f.Close()
	w := bufio.NewWriter(f)

	flushticker := time.NewTicker(time.Second * time.Duration(*interval))
	go func() {
		for t := range flushticker.C {
			fmt.Println("Writting file to disk at", t)
			err := w.Flush()
			check(err)
		}
	}()

	expiretimer := time.NewTimer(time.Hour * 24 * time.Duration(*age))
	go func() {
		<-expiretimer.C
		err := w.Flush()
		check(err)
		println("Logger expired after days:", *age)
		os.Exit(0)
	}()

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for sig := range c {
			err := w.Flush()
			check(err)
			println("Stopping because of interrupt", sig)
			os.Exit(1)
		}
	}()

	for {
		line, _ := tp.ReadLine()
		fmt.Fprintln(w, line)
		fmt.Println(line)
		buffer.WriteString(line + "\n")
		err := ioutil.WriteFile("test", buffer.Bytes(), 0644)
		check(err)
	}
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"flag"
	"bufio"
	"log"
	"os"
	"math/rand"
	"strconv"
	"time"
)

var SAMPLE_TYPE int
const (
	INTEGER = iota
	PERCENTAGE
	)

var COUNT int // a count of how many lines have been collected
var SAMPLE = make([]string, 0)
var SAMPLE_VALUE int // either a percentage or a sum to keep

var command = os.Args[0]
var invocation = fmt.Sprintf("%s [[sample size]%%] [file path]\n", command)

var logger *log.Logger

// flag.Usage help message override
var Usage = func() {
	fmt.Fprintf(os.Stderr, "Usage: %s", invocation)
}

func init() {
	logger = log.New(os.Stderr, "[SNL] ", log.LstdFlags|log.Lshortfile)
	rand.Seed(time.Now().UTC().UnixNano())

	flag.Usage = Usage
	flag.Parse()
}

// parseValue determines if the value is a percentage or
// an integer, and sets the global value `SAMPLE_VALUE`,
func parseValue(s string) {
	var value string
	if string(s[len(s) - 1]) == "%" {
		SAMPLE_TYPE = PERCENTAGE
		value = s[:len(s)-1]
	} else {
		SAMPLE_TYPE = INTEGER
		value = s
	}

	// convert value to integer
	intValue, err := strconv.Atoi(value)
	if err != nil {
		logger.Printf("[Error] error converting sample_size: %s to integer: %s", value, err)
		fmt.Printf("Usage: %s", invocation)
		os.Exit(1)
	}
	SAMPLE_VALUE = intValue
}

// parseFile validates a string and returns an *os.File
func parseFile(s string) (file *os.File) {
	if s == "" {
		logger.Print("[Error] missing filename argument")
		fmt.Printf("Usage: %s", invocation)
		os.Exit(1)
	}

	file, err := os.Open(s)
	if err != nil {
		logger.Fatalf("[Error] error opening %s: %s", s, err)
	}

	return file
}

// keepPercentage returns a function that closes over
// an argument that represents a percentage. The function it returns
// accepts a count and it returns.
func keepPercentage(percentage float64) (fn func(int) int){
	return func(count int) int {
		return int(percentage * float64(count))
	}
}

// forgetOrReplace will choose a number, N, between
// 0 and count, if N is >= threshold we return the sample;
// if N is < len(`sample`) we replace it with `value`
func forgetOrReplace(sample []string, count, threshold int, value string){
	var candidate = rand.Intn(count)

	if candidate < threshold {
		sample[candidate] = value
	}
}

func printSample() {
	for _, line := range SAMPLE {
		fmt.Println(line)
	}
}

func main () {

	var file *os.File

	sampleSize := flag.Arg(0)
	parseValue(sampleSize)

	if SAMPLE_TYPE == INTEGER {
		SAMPLE = make([]string, SAMPLE_VALUE)
	} else if SAMPLE_TYPE == PERCENTAGE {
		// make a default size to collect
	}

	fileName := flag.Arg(1)
	if fileName == "-" {
		file = os.Stdin
	} else {
		file = parseFile(fileName)
		defer file.Close()
	}

	var line string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line = fmt.Sprint(scanner.Text())

		if SAMPLE_TYPE == PERCENTAGE {

			logger.Println("percentage sampling not implemented yet")
			os.Exit(0)
		}

		if COUNT < SAMPLE_VALUE {
			SAMPLE[COUNT] = line
		} else {
			forgetOrReplace(SAMPLE, COUNT, SAMPLE_VALUE, line)
		}
		COUNT++
	}
	printSample()
}
<commit_msg>need to implement handleSignal<commit_after>package main

import (
	"fmt"
	"flag"
	"bufio"
	"log"
	"os"
	"math/rand"
	"strconv"
	"time"
)

var SAMPLE_TYPE int
const (
	INTEGER = iota
	PERCENTAGE
	)

var COUNT int // a count of how many lines have been collected
var SAMPLE = make([]string, 0)
var SAMPLE_VALUE int // either a percentage or a sum to keep

var command = os.Args[0]
var invocation = fmt.Sprintf("%s [[sample size]%%] [file path]\n", command)

var logger *log.Logger

// flag.Usage help message override
var Usage = func() {
	fmt.Fprintf(os.Stderr, "Usage: %s", invocation)
}

func init() {
	logger = log.New(os.Stderr, "[SNL] ", log.LstdFlags|log.Lshortfile)
	rand.Seed(time.Now().UTC().UnixNano())

	flag.Usage = Usage
	flag.Parse()
}

// parseValue determines if the value is a percentage or
// an integer, and sets the global value `SAMPLE_VALUE`,
func parseValue(s string) {
	var value string
	if string(s[len(s) - 1]) == "%" {
		SAMPLE_TYPE = PERCENTAGE
		value = s[:len(s)-1]
	} else {
		SAMPLE_TYPE = INTEGER
		value = s
	}

	// convert value to integer
	intValue, err := strconv.Atoi(value)
	if err != nil {
		logger.Printf("[Error] error converting sample_size: %s to integer: %s", value, err)
		fmt.Printf("Usage: %s", invocation)
		os.Exit(1)
	}
	SAMPLE_VALUE = intValue
}

// parseFile validates a string and returns an *os.File
func parseFile(s string) (file *os.File) {
	if s == "" {
		logger.Print("[Error] missing filename argument")
		fmt.Printf("Usage: %s", invocation)
		os.Exit(1)
	}

	file, err := os.Open(s)
	if err != nil {
		logger.Fatalf("[Error] error opening %s: %s", s, err)
	}

	return file
}

// keepPercentage returns a function that closes over
// an argument that represents a percentage. The function it returns
// accepts a count and it returns.
func keepPercentage(percentage float64) (fn func(int) int) {
	return func(count int) int {
		return int(percentage * float64(count))
	}
}

// forgetOrReplace will choose a number, N, between
// 0 and count, if N is >= threshold we return the sample;
// if N is < len(`sample`) we replace it with `value`
func forgetOrReplace(sample []string, count, threshold int, value string){
	var candidate = rand.Intn(count)

	if candidate < threshold {
		sample[candidate] = value
	}
}

func printSample() {
	for _, line := range SAMPLE {
		fmt.Println(line)
	}
}

type PercentageSample struct {
	total []string
	percentage float64
}

// add saved values to array
func (container *PercentageSample) addPercentageToTotal(sample []string) {

}

func handleSignal() {
	sigChannel := make(chan os.Signal, 1)
	signal.Notify(sigChannel, os.Interrupt)
	<- sigChannel

	// check if this is a percentage or integer sample

	keepPercentage()

	printSample()
}

func main () {

	var file *os.File

	sampleSize := flag.Arg(0)
	parseValue(sampleSize)

	if SAMPLE_TYPE == INTEGER {
		SAMPLE = make([]string, SAMPLE_VALUE)
	} else if SAMPLE_TYPE == PERCENTAGE {
		// create a PercentageSample object and set it's percentage

		// make sample a defualt size of 100

	}

	fileName := flag.Arg(1)
	if fileName == "-" {
		file = os.Stdin
	} else {
		file = parseFile(fileName)
		defer file.Close()
	}

	var line string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line = fmt.Sprint(scanner.Text())

		if SAMPLE_TYPE == PERCENTAGE {
			// collect the number of values

			// call collect at each threshold to siphon samples to objec
			logger.Println("percentage sampling not implemented yet")
			os.Exit(0)
		}

		if COUNT < SAMPLE_VALUE {
			SAMPLE[COUNT] = line
		} else {
			forgetOrReplace(SAMPLE, COUNT, SAMPLE_VALUE, line)
		}
		COUNT++
	}
	printSample()
}
<|endoftext|>