<commit_before>package main

// URL matching and regular expressions

import (
	"code.google.com/p/go-idn/idna/punycode"
	"log"
	"net/url"
	"regexp"
	"strings"
)

type regexRule struct {
	rule
	*regexp.Regexp
}

// A regexMap is a set of regular-expression rules.
// As an optimization, it uses Aho-Corasick string matching find which regular
// expressions might match—instead of trying them all.
type regexMap struct {
	prefixList phraseList
	rules      map[string][]regexRule
}

func newRegexMap() *regexMap {
	return &regexMap{
		prefixList: newPhraseList(),
		rules:      make(map[string][]regexRule),
	}
}

func (rm *regexMap) findMatches(s string, tally map[rule]int) {
	tried := map[string]bool{}
	scanner := newPhraseScanner(rm.prefixList, func(prefix string) {
		if tried[prefix] {
			return
		}
		for _, r := range rm.rules[prefix] {
			if r.MatchString(s) {
				tally[r.rule] = 1
			}
		}
		tried[prefix] = true
	})

	for i := 0; i < len(s); i++ {
		scanner.scanByte(s[i])
	}

	// Now try the regexes that have no literal string prefix.
	for _, r := range rm.rules[""] {
		if r.MatchString(s) {
			tally[r.rule] = 1
		}
	}
}

// addRule adds a rule to the map.
func (rm *regexMap) addRule(r rule) {
	s := r.content

	re, err := regexp.Compile(s)
	if err != nil {
		log.Printf("Error parsing URL regular expression %s: %v", r, err)
		return
	}

	prefix, _ := re.LiteralPrefix()
	if prefix != "" {
		rm.prefixList.addPhrase(prefix)
	}
	rm.rules[prefix] = append(rm.rules[prefix], regexRule{r, re})
}

type URLMatcher struct {
	fragments    map[string]rule // a set of domain or domain+path URL fragments to test against
	regexes      *regexMap       // to match whole URL
	hostRegexes  *regexMap       // to match hostname only
	pathRegexes  *regexMap
	queryRegexes *regexMap
}

// finalize should be called after all rules have been added, but before
// using the URLMatcher.
func (m *URLMatcher) finalize() {
	m.regexes.prefixList.findFallbackNodes(0, nil)
	m.hostRegexes.prefixList.findFallbackNodes(0, nil)
	m.pathRegexes.prefixList.findFallbackNodes(0, nil)
	m.queryRegexes.prefixList.findFallbackNodes(0, nil)
}

func newURLMatcher() *URLMatcher {
	m := new(URLMatcher)
	m.fragments = make(map[string]rule)
	m.regexes = newRegexMap()
	m.hostRegexes = newRegexMap()
	m.pathRegexes = newRegexMap()
	m.queryRegexes = newRegexMap()
	return m
}

// AddRule adds a rule to the matcher (unless it's already there).
func (m *URLMatcher) AddRule(r rule) {
	switch r.t {
	case urlMatch:
		m.fragments[r.content] = r
	case urlRegex:
		m.regexes.addRule(r)
	case hostRegex:
		m.hostRegexes.addRule(r)
	case pathRegex:
		m.pathRegexes.addRule(r)
	case queryRegex:
		m.queryRegexes.addRule(r)
	}
}

// MatchingRules returns a list of the rules that u matches.
// For consistency with phrase matching, it is a map with rules for keys
// and with all values equal to 1.
func (m *URLMatcher) MatchingRules(u *url.URL) map[rule]int {
	result := make(map[rule]int)

	host := strings.ToLower(u.Host)

	// strip off the port number, if present
	colon := strings.LastIndex(host, ":")
	// IPv6 addresses contain colons inside brackets, so be careful.
	if colon != -1 && !strings.Contains(host[colon:], "]") {
		host = host[:colon]
	}

	// Handle internationalized domain names.
	if strings.Contains(host, "xn--") {
		labels := strings.Split(host, ".")
		for i, puny := range labels {
			if !strings.HasPrefix(puny, "xn--") {
				continue
			}
			uni, err := punycode.DecodeString(puny[len("xn--"):])
			if err == nil {
				labels[i] = uni
			}
		}
		host = strings.ToLower(strings.Join(labels, "."))
	}

	urlString := ""
	if u.Scheme != "" {
		urlString += strings.ToLower(u.Scheme) + ":"
	}
	if host != "" {
		urlString += "//" + host
		m.hostRegexes.findMatches(urlString, result)
	}

	path := strings.ToLower(u.Path)
	m.pathRegexes.findMatches(path, result)
	urlString += path

	query := strings.ToLower(u.RawQuery)
	if query != "" {
		m.queryRegexes.findMatches(query, result)
		urlString += "?" + query
	}

	m.regexes.findMatches(urlString, result)

	// Test for matches of the host and of the domains it belongs to.
	s := host
	for {
		// Test for matches with the path.
		s2 := s + path
		for {
			if r, ok := m.fragments[s2]; ok {
				result[r] = 1
			}
			slash := strings.LastIndex(s2[:len(s2)-1], "/")
			if slash == -1 {
				break
			}
			s2 = s2[:slash+1]
		}

		if r, ok := m.fragments[s]; ok {
			result[r] = 1
		}
		dot := strings.Index(s, ".")
		if dot == -1 {
			break
		}
		s = s[dot+1:]
	}

	return result
}
<commit_msg>Decode percent escapes in queries<commit_after>package main

// URL matching and regular expressions

import (
	"code.google.com/p/go-idn/idna/punycode"
	"log"
	"net/url"
	"regexp"
	"strings"
)

type regexRule struct {
	rule
	*regexp.Regexp
}

// A regexMap is a set of regular-expression rules.
// As an optimization, it uses Aho-Corasick string matching find which regular
// expressions might match—instead of trying them all.
type regexMap struct {
	prefixList phraseList
	rules      map[string][]regexRule
}

func newRegexMap() *regexMap {
	return &regexMap{
		prefixList: newPhraseList(),
		rules:      make(map[string][]regexRule),
	}
}

func (rm *regexMap) findMatches(s string, tally map[rule]int) {
	tried := map[string]bool{}
	scanner := newPhraseScanner(rm.prefixList, func(prefix string) {
		if tried[prefix] {
			return
		}
		for _, r := range rm.rules[prefix] {
			if r.MatchString(s) {
				tally[r.rule] = 1
			}
		}
		tried[prefix] = true
	})

	for i := 0; i < len(s); i++ {
		scanner.scanByte(s[i])
	}

	// Now try the regexes that have no literal string prefix.
	for _, r := range rm.rules[""] {
		if r.MatchString(s) {
			tally[r.rule] = 1
		}
	}
}

// addRule adds a rule to the map.
func (rm *regexMap) addRule(r rule) {
	s := r.content

	re, err := regexp.Compile(s)
	if err != nil {
		log.Printf("Error parsing URL regular expression %s: %v", r, err)
		return
	}

	prefix, _ := re.LiteralPrefix()
	if prefix != "" {
		rm.prefixList.addPhrase(prefix)
	}
	rm.rules[prefix] = append(rm.rules[prefix], regexRule{r, re})
}

type URLMatcher struct {
	fragments    map[string]rule // a set of domain or domain+path URL fragments to test against
	regexes      *regexMap       // to match whole URL
	hostRegexes  *regexMap       // to match hostname only
	pathRegexes  *regexMap
	queryRegexes *regexMap
}

// finalize should be called after all rules have been added, but before
// using the URLMatcher.
func (m *URLMatcher) finalize() {
	m.regexes.prefixList.findFallbackNodes(0, nil)
	m.hostRegexes.prefixList.findFallbackNodes(0, nil)
	m.pathRegexes.prefixList.findFallbackNodes(0, nil)
	m.queryRegexes.prefixList.findFallbackNodes(0, nil)
}

func newURLMatcher() *URLMatcher {
	m := new(URLMatcher)
	m.fragments = make(map[string]rule)
	m.regexes = newRegexMap()
	m.hostRegexes = newRegexMap()
	m.pathRegexes = newRegexMap()
	m.queryRegexes = newRegexMap()
	return m
}

// AddRule adds a rule to the matcher (unless it's already there).
func (m *URLMatcher) AddRule(r rule) {
	switch r.t {
	case urlMatch:
		m.fragments[r.content] = r
	case urlRegex:
		m.regexes.addRule(r)
	case hostRegex:
		m.hostRegexes.addRule(r)
	case pathRegex:
		m.pathRegexes.addRule(r)
	case queryRegex:
		m.queryRegexes.addRule(r)
	}
}

// MatchingRules returns a list of the rules that u matches.
// For consistency with phrase matching, it is a map with rules for keys
// and with all values equal to 1.
func (m *URLMatcher) MatchingRules(u *url.URL) map[rule]int {
	result := make(map[rule]int)

	host := strings.ToLower(u.Host)

	// strip off the port number, if present
	colon := strings.LastIndex(host, ":")
	// IPv6 addresses contain colons inside brackets, so be careful.
	if colon != -1 && !strings.Contains(host[colon:], "]") {
		host = host[:colon]
	}

	// Handle internationalized domain names.
	if strings.Contains(host, "xn--") {
		labels := strings.Split(host, ".")
		for i, puny := range labels {
			if !strings.HasPrefix(puny, "xn--") {
				continue
			}
			uni, err := punycode.DecodeString(puny[len("xn--"):])
			if err == nil {
				labels[i] = uni
			}
		}
		host = strings.ToLower(strings.Join(labels, "."))
	}

	urlString := ""
	if u.Scheme != "" {
		urlString += strings.ToLower(u.Scheme) + ":"
	}
	if host != "" {
		urlString += "//" + host
		m.hostRegexes.findMatches(urlString, result)
	}

	path := strings.ToLower(u.Path)
	m.pathRegexes.findMatches(path, result)
	urlString += path

	query := strings.ToLower(u.RawQuery)
	if query != "" {
		q, err := url.QueryUnescape(query)
		if err == nil {
			// Change ' ' back to '+'.
			query = strings.Replace(q, " ", "+", -1)
		}
		m.queryRegexes.findMatches(query, result)
		urlString += "?" + query
	}

	m.regexes.findMatches(urlString, result)

	// Test for matches of the host and of the domains it belongs to.
	s := host
	for {
		// Test for matches with the path.
		s2 := s + path
		for {
			if r, ok := m.fragments[s2]; ok {
				result[r] = 1
			}
			slash := strings.LastIndex(s2[:len(s2)-1], "/")
			if slash == -1 {
				break
			}
			s2 = s2[:slash+1]
		}

		if r, ok := m.fragments[s]; ok {
			result[r] = 1
		}
		dot := strings.Index(s, ".")
		if dot == -1 {
			break
		}
		s = s[dot+1:]
	}

	return result
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
)

const vmrun = "/Applications/VMware Fusion.app/Contents/Library/vmrun"

var (
	home = os.Getenv("HOME")
	vmdir = fmt.Sprintf("%s/%s", home, "Documents/Virtual Machines.localized")
)

func extractVMName(vmpath string) string {
	relpath := strings.TrimPrefix(vmpath, vmdir)
	vmwarevm := path.Base(path.Dir(relpath))
	return strings.TrimSuffix(vmwarevm, ".vmwarevm")
}

func listVMs() (map[string]string) {
	glob := fmt.Sprintf("%s/**/*.vmx", vmdir)
	paths, err := filepath.Glob(glob)
	if err != nil {
		fmt.Printf("%s\n\n", err.Error())
	}

	vmx := make(map[string]string)
	for _, path := range paths {
		name := extractVMName(path)
		vmx[name] = path
	}

	return vmx
}

// Returns vmx file path from name.
// If name is vmx file path itself, returns that unchanged.
// If vmx path is not found, returns empty string.
func findVmxPath(name string) string {
	path := name
	if _, err := os.Stat(name); os.IsNotExist(err) {
		// If calling listVMs is heavy, consider to cache this value.
		path = listVMs()[name]
	}
	return path
}

// Convert VM name to vmx path in original args.
func convertArgs(args []string) []string {
	if len(args) == 0 {
		return args
	}

	originalArgs := args
	args = make([]string, len(args))
	copy(args, originalArgs)

	var command, vmName, guiMode string
	optionArgs := false
	for i, v := range args {
		switch {
		case optionArgs:
			optionArgs = false
		case strings.HasPrefix(v, "-"):
			optionArgs = true
		case command == "":
			command = v
		case vmName == "":
			vmName = v
			args[i] = findVmxPath(v)
		case v == "gui" || v == "nogui":
			guiMode = v
		}
	}
	if command == "start" && guiMode == "" {
		args = append(args, "nogui")
	}
	return args
}

func main() {
	args := convertArgs(os.Args[1:])
	cmd := exec.Command(vmrun, args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Printf("%s\n\n", err.Error())
	}
	fmt.Printf("%s", out)

	if len(args) > 0 && args[0] == "list" {
		fmt.Printf("\nVMs in %s:\n", vmdir)
		vms := listVMs()
		maxNameLen := 0
		for name, _ := range vms {
			l := len(name)
			if maxNameLen < l {
				maxNameLen = l
			}
		}

		format := fmt.Sprintf("  %%-%ds (%%s)\n", maxNameLen + 2)
		for name, path := range vms {
			fmt.Printf(format, name, path)
		}
	}

	if !cmd.ProcessState.Success() {
		os.Exit(1)
	}
}
<commit_msg>Supports prefix for VM image<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
)

const vmrun = "/Applications/VMware Fusion.app/Contents/Library/vmrun"

var (
	home = os.Getenv("HOME")
	vmdir = fmt.Sprintf("%s/%s", home, "Documents/Virtual Machines.localized")
)

func extractVMName(vmpath string) string {
	relpath := strings.TrimPrefix(vmpath, vmdir)
	vmwarevm := path.Base(path.Dir(relpath))
	return strings.TrimSuffix(vmwarevm, ".vmwarevm")
}

func listVMs() (map[string]string) {
	glob := fmt.Sprintf("%s/**/*.vmx", vmdir)
	paths, err := filepath.Glob(glob)
	if err != nil {
		fmt.Printf("%s\n\n", err.Error())
	}

	vmx := make(map[string]string)
	for _, path := range paths {
		name := extractVMName(path)
		vmx[name] = path
	}

	return vmx
}

// Returns vmx file path from name.
// If name is vmx file path itself, returns that unchanged.
// If vmx path is not found, returns empty string.
func findVmxPath(name string) string {
	path := name
	if _, err := os.Stat(name); os.IsNotExist(err) {
		glob := fmt.Sprintf("%s/%s*/*.vmx", vmdir, name)
		paths, err := filepath.Glob(glob)
		if err != nil {
			fmt.Printf("%s\n\n", err.Error())
		} else if paths == nil {
			fmt.Printf("Error: No VM image found like: %s\n", name)
			list()
			os.Exit(2)
		} else if len(paths) > 1 {
			fmt.Printf("Error: Two or more VM images found like: %s\n", name)
			list()
			os.Exit(2)
		} else {
			path = paths[0]
		}
	}
	return path
}

// Convert VM name to vmx path in original args.
func convertArgs(args []string) []string {
	if len(args) == 0 {
		return args
	}

	originalArgs := args
	args = make([]string, len(args))
	copy(args, originalArgs)

	var command, vmName, guiMode string
	optionArgs := false
	for i, v := range args {
		switch {
		case optionArgs:
			optionArgs = false
		case strings.HasPrefix(v, "-"):
			optionArgs = true
		case command == "":
			command = v
		case vmName == "":
			vmName = v
			args[i] = findVmxPath(v)
		case v == "gui" || v == "nogui":
			guiMode = v
		}
	}
	if command == "start" && guiMode == "" {
		args = append(args, "nogui")
	}
	return args
}

func list() {
	fmt.Printf("\nVMs in %s:\n", vmdir)
	vms := listVMs()
	maxNameLen := 0
	for name, _ := range vms {
		l := len(name)
		if maxNameLen < l {
			maxNameLen = l
		}
	}

	format := fmt.Sprintf("  %%-%ds (%%s)\n", maxNameLen + 2)
	for name, path := range vms {
		fmt.Printf(format, name, path)
	}
}

func main() {
	args := convertArgs(os.Args[1:])
	cmd := exec.Command(vmrun, args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Printf("%s\n\n", err.Error())
	}
	fmt.Printf("%s", out)

	if len(args) > 0 && args[0] == "list" {
		list()
	}

	if !cmd.ProcessState.Success() {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package web

import (
	"errors"
	"net/http"
	"os"
	"os/signal"

	"github.com/issue9/logs"
	"github.com/issue9/middleware"

	"github.com/issue9/web/context"
	"github.com/issue9/web/internal/app"
	"github.com/issue9/web/module"
	"github.com/issue9/web/result"
)

var defaultApp *app.App

// Init 初始化整个应用环境
//
// configDir 表示配置文件的目录；
func Init(configDir string) (err error) {
	if defaultApp != nil {
		return errors.New("不能重复调用 Init")
	}

	defaultApp, err = app.New(configDir)
	return
}

// Grace 指定触发 Shutdown() 的信号，若为空，则任意信号都触发。
//
// 多次调用，则每次指定的信号都会起作用，如果由传递了相同的值，
// 则有可能多次触发 Shutdown()。
//
// NOTE: 传递空值，与不调用，其结果是不同的。
// 若是不调用，则不会处理任何信号；若是传递空值调用，则是处理任何要信号。
func Grace(sig ...os.Signal) {
	go func() {
		signalChannel := make(chan os.Signal)
		signal.Notify(signalChannel, sig...)

		<-signalChannel
		signal.Stop(signalChannel)

		if err := Shutdown(); err != nil {
			logs.Error(err)
		}
	}()
}

// SetMiddleware 设置一个全局的中间件，多次设置，只有最后一次会启作用。
func SetMiddleware(m middleware.Middleware) {
	defaultApp.SetMiddleware(m)
}

// IsDebug 是否处在调试模式
func IsDebug() bool {
	return defaultApp.Debug()
}

// Handler 将当前实例当作一个 http.Handler 返回。一般用于测试。
// 比如在 httptest.NewServer 中使用。
func Handler() (http.Handler, error) {
	return defaultApp.Handler()
}

// Run 运行路由，执行监听程序。
func Run() error {
	return defaultApp.Serve()
}

// Install 执行指定版本的安装功能
func Install(version string) error {
	return defaultApp.Install(version)
}

// Close 关闭服务。
//
// 无论配置文件如果设置，此函数都是直接关闭服务，不会等待。
func Close() error {
	return defaultApp.Close()
}

// Shutdown 关闭所有服务。
//
// 根据配置文件中的配置项，决定当前是直接关闭还是延时之后关闭。
func Shutdown() error {
	return defaultApp.Shutdown()
}

// File 获取配置目录下的文件。
func File(path string) string {
	return defaultApp.File(path)
}

// URL 构建一条完整 URL
func URL(path string) string {
	return defaultApp.URL(path)
}

// Modules 当前系统使用的所有模块信息
func Modules() []*module.Module {
	return defaultApp.Modules()
}

// LoadConfig 从配置目录中加载数据到对象 v 中。
func LoadConfig(path string, v interface{}) error {
	return defaultApp.LoadConfig(path, v)
}

// NewModule 注册一个模块
func NewModule(name, desc string, deps ...string) *module.Module {
	return defaultApp.NewModule(name, desc, deps...)
}

// NewContext 根据当前配置，生成 context.Context 对象，若是出错则 panic
func NewContext(w http.ResponseWriter, r *http.Request) *context.Context {
	return context.New(w, r, logs.ERROR())
}

// NewResult 生成一个 *result.Result 对象
func NewResult(code int) *result.Result {
	return &result.Result{Code: code}
}
<commit_msg>由 Serve 代替 Run<commit_after>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package web

import (
	"errors"
	"net/http"
	"os"
	"os/signal"

	"github.com/issue9/logs"
	"github.com/issue9/middleware"

	"github.com/issue9/web/context"
	"github.com/issue9/web/internal/app"
	"github.com/issue9/web/module"
	"github.com/issue9/web/result"
)

var defaultApp *app.App

// Init 初始化整个应用环境
//
// configDir 表示配置文件的目录；
func Init(configDir string) (err error) {
	if defaultApp != nil {
		return errors.New("不能重复调用 Init")
	}

	defaultApp, err = app.New(configDir)
	return
}

// Grace 指定触发 Shutdown() 的信号，若为空，则任意信号都触发。
//
// 多次调用，则每次指定的信号都会起作用，如果由传递了相同的值，
// 则有可能多次触发 Shutdown()。
//
// NOTE: 传递空值，与不调用，其结果是不同的。
// 若是不调用，则不会处理任何信号；若是传递空值调用，则是处理任何要信号。
func Grace(sig ...os.Signal) {
	go func() {
		signalChannel := make(chan os.Signal)
		signal.Notify(signalChannel, sig...)

		<-signalChannel
		signal.Stop(signalChannel)

		if err := Shutdown(); err != nil {
			logs.Error(err)
		}
	}()
}

// SetMiddleware 设置一个全局的中间件，多次设置，只有最后一次会启作用。
func SetMiddleware(m middleware.Middleware) {
	defaultApp.SetMiddleware(m)
}

// IsDebug 是否处在调试模式
func IsDebug() bool {
	return defaultApp.Debug()
}

// Handler 将当前实例当作一个 http.Handler 返回。一般用于测试。
// 比如在 httptest.NewServer 中使用。
func Handler() (http.Handler, error) {
	return defaultApp.Handler()
}

// Run 运行路由，执行监听程序。
//
// Deprecated: 由 Serve 代替
func Run() error {
	return defaultApp.Serve()
}

// Serve 运行路由，执行监听程序。
func Serve() error {
	return defaultApp.Serve()
}

// Install 执行指定版本的安装功能
func Install(version string) error {
	return defaultApp.Install(version)
}

// Close 关闭服务。
//
// 无论配置文件如果设置，此函数都是直接关闭服务，不会等待。
func Close() error {
	return defaultApp.Close()
}

// Shutdown 关闭所有服务。
//
// 根据配置文件中的配置项，决定当前是直接关闭还是延时之后关闭。
func Shutdown() error {
	return defaultApp.Shutdown()
}

// File 获取配置目录下的文件。
func File(path string) string {
	return defaultApp.File(path)
}

// URL 构建一条完整 URL
func URL(path string) string {
	return defaultApp.URL(path)
}

// Modules 当前系统使用的所有模块信息
func Modules() []*module.Module {
	return defaultApp.Modules()
}

// LoadConfig 从配置目录中加载数据到对象 v 中。
func LoadConfig(path string, v interface{}) error {
	return defaultApp.LoadConfig(path, v)
}

// NewModule 注册一个模块
func NewModule(name, desc string, deps ...string) *module.Module {
	return defaultApp.NewModule(name, desc, deps...)
}

// NewContext 根据当前配置，生成 context.Context 对象，若是出错则 panic
func NewContext(w http.ResponseWriter, r *http.Request) *context.Context {
	return context.New(w, r, logs.ERROR())
}

// NewResult 生成一个 *result.Result 对象
func NewResult(code int) *result.Result {
	return &result.Result{Code: code}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/LogvinovLeon/UberChallenge/definitions"
	"github.com/LogvinovLeon/UberChallenge/email-providers/mailgun"
	"github.com/LogvinovLeon/UberChallenge/email-providers/sendgrid"
	"log"
	"net/http"
	"os"
)

type SenderType func(*definitions.EmailSendPayload) error

func sendEmailWithFallback(payload *definitions.EmailSendPayload, primarySender, secondarySender SenderType) error {
	return primarySender(payload)
}

func handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodPost {
		if r.Body == nil {
			http.Error(w, "Please send a request body", 400)
			return
		}
		var payload definitions.EmailSendPayload
		err := json.NewDecoder(r.Body).Decode(&payload)
		if err != nil {
			http.Error(w, err.Error(), 400)
			return
		}
		fmt.Println(payload)
		var e error
		if payload.PreferredProvider == "mailgun" {
			e = sendEmailWithFallback(&payload, mailgun.Send, sendgrid.Send)
		} else {
			e = sendEmailWithFallback(&payload, sendgrid.Send, mailgun.Send)
		}
		if e != nil {
			log.Println(e)
			return
		}
		w.Header().Set("Access-Control-Allow-Origin", "www.uberchallenge.email")
	}
}

func main() {
	http.HandleFunc("/email/", handler)
	http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}
<commit_msg>Add * CORS header<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/LogvinovLeon/UberChallenge/definitions"
	"github.com/LogvinovLeon/UberChallenge/email-providers/mailgun"
	"github.com/LogvinovLeon/UberChallenge/email-providers/sendgrid"
	"log"
	"net/http"
	"os"
)

type SenderType func(*definitions.EmailSendPayload) error

func sendEmailWithFallback(payload *definitions.EmailSendPayload, primarySender, secondarySender SenderType) error {
	return primarySender(payload)
}

func handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodPost {
		if r.Body == nil {
			http.Error(w, "Please send a request body", 400)
			return
		}
		var payload definitions.EmailSendPayload
		err := json.NewDecoder(r.Body).Decode(&payload)
		if err != nil {
			http.Error(w, err.Error(), 400)
			return
		}
		fmt.Println(payload)
		var e error
		if payload.PreferredProvider == "mailgun" {
			e = sendEmailWithFallback(&payload, mailgun.Send, sendgrid.Send)
		} else {
			e = sendEmailWithFallback(&payload, sendgrid.Send, mailgun.Send)
		}
		if e != nil {
			log.Println(e)
			return
		}
		w.Header().Set("Access-Control-Allow-Origin", "*")
		//w.Header().Set("Access-Control-Allow-Origin", "www.uberchallenge.email")
		fmt.Fprintf(w, "OK\n")
	}
}

func main() {
	http.HandleFunc("/email/", handler)
	http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}
<|endoftext|>


<commit_before>package gisp

import (
	"fmt"
	p "github.com/Dwarfartisan/goparsec"
	px "github.com/Dwarfartisan/goparsec/parsex"
	"reflect"
)

type Bracket struct {
	obj  interface{}
	expr []interface{}
}

func (bracket Bracket) Eval(env Env) (interface{}, error) {
	obj, err := Eval(env, bracket.obj)
	if err != nil {
		return nil, err
	}
	val := reflect.ValueOf(obj)
	switch val.Kind() {
	case reflect.Slice, reflect.String, reflect.Array:
		switch len(bracket.expr) {
		case 1:
			return bracket.evalIndex(env, val)
		case 2, 3:
			return bracket.evalSlice(env, val)
		default:
			return nil, fmt.Errorf("Unknow howto index or slice:%v[%v]",
				bracket.obj, bracket.expr)
		}

	case reflect.Map:
		if len(bracket.expr) == 1 {
			key := reflect.ValueOf(bracket.expr[0])
			return val.MapIndex(key).Interface(), nil
		}
		return nil, fmt.Errorf("Unknow howto parse map %v[%v]",
			bracket.obj, bracket.expr)
	}
	return nil, fmt.Errorf("Unknow howto parse formal as %v[%v]",
		bracket.obj, bracket.expr)
}

func (bracket Bracket) evalIndex(env Env, val reflect.Value) (interface{}, error) {
	i, err := Eval(env, bracket.expr[0])
	if err != nil {
		return nil, err
	}
	if idx, ok := i.(Int); ok {
		return val.Index(int(idx)).Interface(), nil
	}
	return nil, fmt.Errorf("Index for slice %v[%v]  is invalid data: %v",
		bracket.obj, bracket.expr, i)
}

func (bracket Bracket) evalSlice(env Env, val reflect.Value) (interface{}, error) {
	items, err := Evals(env, bracket.expr...)
	if err != nil {
		return nil, err
	}
	indexs, err := bracket.computeIndexs(val, items)
	if err != nil {
		return nil, err
	}
	switch len(indexs) {
	case 2:
		return val.Slice(indexs[0], indexs[1]).Interface(), nil
	case 3:
		return val.Slice3(indexs[0], indexs[1], indexs[2]).Interface(), nil
	}

	return nil, fmt.Errorf("Index for slice %v[%v]  is invalid",
		bracket.obj, bracket.expr)
}
func (bracket Bracket) computeIndexs(val reflect.Value, input []interface{}) ([]int, error) {
	indexs := make([]int, len(input))
	for idx, item := range input {
		i, err := bracket.computeIndex(val, item)
		if err != nil {
			return nil, err
		}
		indexs[idx] = i
	}
	return indexs, nil
}

func (bracket Bracket) computeIndex(val reflect.Value, input interface{}) (int, error) {
	l := val.Len()
	if index, ok := input.(Int); ok {
		i := int(index)
		if i < 0 {
			i = l - i
		}
		if i < 0 || i > l-1 {
			return 0, fmt.Errorf("Try to slice %v[%v] but %v out range",
				bracket.obj, bracket.expr, index)
		}
		return i, nil
	}
	return 0, fmt.Errorf("Try to slice %v[%v] but %v is invalid",
		bracket.obj, bracket.expr, input)
}

func BracketParser(st p.ParseState) (interface{}, error) {
	bracket := p.Between(p.Rune('['), p.Rune(']'),
		p.SepBy1(ValueParser, p.Rune(':')),
	)
	t, err := bracket(st)
	if err != nil {
		return nil, err
	}
	tokens := t.([]interface{})
	stx := px.NewStateInMemory(tokens)
	format := px.Choice(
		px.Binds_(px.StringVal, px.Eof),
		px.Binds_(IntVal, px.Eof),
		px.Binds_(IntVal, IntVal, px.Eof),
		px.Binds_(IntVal, IntVal, IntVal, px.Eof),
	)
	_, err = format(stx)
	if err != nil {
		return nil, err
	}

	return tokens, nil
}

func IntVal(st px.ParsexState) (interface{}, error) {
	x, err := st.Next(px.Always)
	if err != nil {
		return nil, err
	}
	if _, ok := x.(Int); ok {
		return x, nil
	}
	return nil, fmt.Errorf("except a Int value but got %v", x)
}
<commit_msg>check nil from bracket eval<commit_after>package gisp

import (
	"fmt"
	p "github.com/Dwarfartisan/goparsec"
	px "github.com/Dwarfartisan/goparsec/parsex"
	"reflect"
)

type Bracket struct {
	obj  interface{}
	expr []interface{}
}

func (bracket Bracket) Eval(env Env) (interface{}, error) {
	obj, err := Eval(env, bracket.obj)
	if err != nil {
		return nil, err
	}
	val := reflect.ValueOf(obj)
	switch val.Kind() {
	case reflect.Slice, reflect.String, reflect.Array:
		switch len(bracket.expr) {
		case 1:
			return bracket.evalIndex(env, val)
		case 2, 3:
			return bracket.evalSlice(env, val)
		default:
			return nil, fmt.Errorf("Unknow howto index or slice:%v[%v]",
				bracket.obj, bracket.expr)
		}

	case reflect.Map:
		if len(bracket.expr) == 1 {
			key := reflect.ValueOf(bracket.expr[0])
			v := val.MapIndex(key)
			return bracket.inter(v), nil
		}
		return nil, fmt.Errorf("Unknow howto parse map %v[%v]",
			bracket.obj, bracket.expr)
	}
	return nil, fmt.Errorf("Unknow howto parse formal as %v[%v]",
		bracket.obj, bracket.expr)
}

func (bracket Bracket) inter(value reflect.Value) interface{} {
	if value.IsValid() {
		return value.Interface()
	}
	return nil
}

func (bracket Bracket) evalIndex(env Env, val reflect.Value) (interface{}, error) {
	i, err := Eval(env, bracket.expr[0])
	if err != nil {
		return nil, err
	}
	if idx, ok := i.(Int); ok {
		v := val.Index(int(idx))
		return bracket.inter(v), nil
	}
	return nil, fmt.Errorf("Index for slice %v[%v]  is invalid data: %v",
		bracket.obj, bracket.expr, i)
}

func (bracket Bracket) evalSlice(env Env, val reflect.Value) (interface{}, error) {
	items, err := Evals(env, bracket.expr...)
	if err != nil {
		return nil, err
	}
	indexs, err := bracket.computeIndexs(val, items)
	if err != nil {
		return nil, err
	}
	switch len(indexs) {
	case 2:
		v := val.Slice(indexs[0], indexs[1])
		return bracket.inter(v), nil
	case 3:
		v := val.Slice3(indexs[0], indexs[1], indexs[2])
		return bracket.inter(v), nil
	}

	return nil, fmt.Errorf("Index for slice %v[%v]  is invalid",
		bracket.obj, bracket.expr)
}
func (bracket Bracket) computeIndexs(val reflect.Value, input []interface{}) ([]int, error) {
	indexs := make([]int, len(input))
	for idx, item := range input {
		i, err := bracket.computeIndex(val, item)
		if err != nil {
			return nil, err
		}
		indexs[idx] = i
	}
	return indexs, nil
}

func (bracket Bracket) computeIndex(val reflect.Value, input interface{}) (int, error) {
	l := val.Len()
	if index, ok := input.(Int); ok {
		i := int(index)
		if i < 0 {
			i = l - i
		}
		if i < 0 || i > l-1 {
			return 0, fmt.Errorf("Try to slice %v[%v] but %v out range",
				bracket.obj, bracket.expr, index)
		}
		return i, nil
	}
	return 0, fmt.Errorf("Try to slice %v[%v] but %v is invalid",
		bracket.obj, bracket.expr, input)
}

func BracketParser(st p.ParseState) (interface{}, error) {
	bracket := p.Between(p.Rune('['), p.Rune(']'),
		p.SepBy1(ValueParser, p.Rune(':')),
	)
	t, err := bracket(st)
	if err != nil {
		return nil, err
	}
	tokens := t.([]interface{})
	stx := px.NewStateInMemory(tokens)
	format := px.Choice(
		px.Binds_(px.StringVal, px.Eof),
		px.Binds_(IntVal, px.Eof),
		px.Binds_(IntVal, IntVal, px.Eof),
		px.Binds_(IntVal, IntVal, IntVal, px.Eof),
	)
	_, err = format(stx)
	if err != nil {
		return nil, err
	}

	return tokens, nil
}

func IntVal(st px.ParsexState) (interface{}, error) {
	x, err := st.Next(px.Always)
	if err != nil {
		return nil, err
	}
	if _, ok := x.(Int); ok {
		return x, nil
	}
	return nil, fmt.Errorf("except a Int value but got %v", x)
}
<|endoftext|>


<commit_before>package surf

import (
	"github.com/PuerkitoBio/goquery"
	"github.com/headzoo/surf/agents"
	"github.com/headzoo/surf/errors"
	"github.com/headzoo/surf/jars"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"time"
)

// Attribute represents a Browser capability.
type Attribute int

// AttributeMap represents a map of Attribute values.
type AttributeMap map[Attribute]bool

const (
	// SendRefererAttribute instructs a Browser to send the Referer header.
	SendRefererAttribute Attribute = iota

	// MetaRefreshHandlingAttribute instructs a Browser to handle the refresh meta tag.
	MetaRefreshHandlingAttribute

	// FollowRedirectsAttribute instructs a Browser to follow Location headers.
	FollowRedirectsAttribute
)

var (
	// DefaultUserAgent is the global user agent value.
	DefaultUserAgent = agents.Create()

	// DefaultSendRefererAttribute is the global value for the AttributeSendReferer attribute.
	DefaultSendRefererAttribute = true

	// DefaultMetaRefreshHandlingAttribute is the global value for the AttributeHandleRefresh attribute.
	DefaultMetaRefreshHandlingAttribute = true

	// DefaultFollowRedirectsAttribute is the global value for the AttributeFollowRedirects attribute.
	DefaultFollowRedirectsAttribute = true
)

// exprPrefixesImplied are strings a selection expr may start with, and the tag is implied.
var exprPrefixesImplied = []string{":", ".", "["}

// Link stores the properties of a page link.
type Link struct {
	// ID is the value of the id attribute or empty when there is no id.
	ID string

	// Href is the value of the href attribute.
	Href string

	// Text is the text appearing between the opening and closing anchor tag.
	Text string
}

// Browsable represents an HTTP web browser.
type Browsable interface {
	Document

	// Open requests the given URL using the GET method.
	Open(url string) error

	// OpenForm appends the data values to the given URL and sends a GET request.
	OpenForm(url string, data url.Values) error

	// OpenBookmark calls Get() with the URL for the bookmark with the given name.
	OpenBookmark(name string) error

	// Post requests the given URL using the POST method.
	Post(url string, bodyType string, body io.Reader) error

	// PostForm requests the given URL using the POST method with the given data.
	PostForm(url string, data url.Values) error

	// Back loads the previously requested page.
	Back() bool

	// Reload duplicates the last successful request.
	Reload() error

	// BookmarkPage saves the page URL in the bookmarks with the given name.
	BookmarkPage(name string) error

	// Click clicks on the page element matched by the given expression.
	Click(expr string) error

	// Form returns the form in the current page that matches the given expr.
	Form(expr string) (FormElement, error)

	// Forms returns an array of every form in the page.
	Forms() []FormElement

	// Links returns an array of every link found in the page.
	Links() []*Link

	// SiteCookies returns the cookies for the current site.
	SiteCookies() []*http.Cookie

	// SetAttribute sets a browser instruction attribute.
	SetAttribute(a Attribute, v bool)

	// ResolveUrl returns an absolute URL for a possibly relative URL.
	ResolveUrl(u *url.URL) *url.URL

	// ResolveStringUrl works just like ResolveUrl, but the argument and return value are strings.
	ResolveStringUrl(u string) (string, error)
}

// Browser is the default Browser implementation.
type Browser struct {
	*Page

	// UserAgent is the User-Agent header value sent with requests.
	UserAgent string

	// Cookies stores cookies for every site visited by the browser.
	Cookies http.CookieJar

	// Bookmarks stores the saved bookmarks.
	Bookmarks jars.BookmarksJar

	// History stores the visited pages.
	History *PageStack

	// RequestHeaders are additional headers to send with each request.
	RequestHeaders http.Header

	// lastRequest is the *http.Request for the last successful request.
	lastRequest *http.Request

	// attributes is the set browser attributes.
	attributes AttributeMap

	// refresh is a timer used to meta refresh pages.
	refresh *time.Timer
}

// NewBrowser creates and returns a *Browser type.
func NewBrowser() (*Browser, error) {
	cookies, err := cookiejar.New(nil)
	if err != nil {
		return nil, err
	}

	return &Browser{
		UserAgent:      DefaultUserAgent,
		Cookies:        cookies,
		Bookmarks:      jars.NewMemoryBookmarks(),
		History:        NewPageStack(),
		RequestHeaders: make(http.Header, 10),
		attributes: AttributeMap{
			SendRefererAttribute:         DefaultSendRefererAttribute,
			MetaRefreshHandlingAttribute: DefaultMetaRefreshHandlingAttribute,
			FollowRedirectsAttribute:     DefaultFollowRedirectsAttribute,
		},
	}, nil
}

// Open requests the given URL using the GET method.
func (b *Browser) Open(u string) error {
	return b.sendGet(u, nil)
}

// OpenForm appends the data values to the given URL and sends a GET request.
func (b *Browser) OpenForm(u string, data url.Values) error {
	ul, err := url.Parse(u)
	if err != nil {
		return err
	}
	ul.RawQuery = data.Encode()

	return b.Open(ul.String())
}

// OpenBookmark calls Open() with the URL for the bookmark with the given name.
func (b *Browser) OpenBookmark(name string) error {
	url, err := b.Bookmarks.Read(name)
	if err != nil {
		return err
	}
	return b.Open(url)
}

// Post requests the given URL using the POST method.
func (b *Browser) Post(u string, bodyType string, body io.Reader) error {
	return b.sendPost(u, bodyType, body, nil)
}

// PostForm requests the given URL using the POST method with the given data.
func (b *Browser) PostForm(u string, data url.Values) error {
	return b.Post(u, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}

// Back loads the previously requested page.
func (b *Browser) Back() bool {
	if b.History.Len() > 0 {
		b.Page = b.History.Pop()
		return true
	}
	return false
}

// Reload duplicates the last successful request.
func (b *Browser) Reload() error {
	if b.lastRequest != nil {
		return b.send(b.lastRequest)
	}
	return errors.NewPageNotLoaded("Cannot reload, the previous request failed.")
}

// BookmarkPage saves the page URL in the bookmarks with the given name.
func (b *Browser) BookmarkPage(name string) error {
	return b.Bookmarks.Save(name, b.ResolveUrl(b.Page.Url()).String())
}

// Click clicks on the page element matched by the given expression.
//
// Currently this is only useful for click on links, which will cause the browser
// to load the page pointed at by the link. Future versions of Surf may support
// JavaScript and clicking on elements will fire the click event.
func (b *Browser) Click(expr string) error {
	sel := b.Page.doc.Find(prefixSelection(expr, "a"))
	if sel.Length() == 0 {
		return errors.NewElementNotFound(
			"Element not found matching expr '%s'.", expr)
	}
	if !sel.Is("a") {
		return errors.NewElementNotFound(
			"Expr '%s' must match an anchor tag.", expr)
	}

	href, ok := sel.Attr("href")
	if !ok {
		return errors.NewLinkNotFound(
			"No link found matching expr '%s'.", expr)
	}
	href, err := b.ResolveStringUrl(href)
	if err != nil {
		return err
	}

	return b.sendGet(href, b.Page)
}

// Form returns the form in the current page that matches the given expr.
//
// The expr can be any valid goquery expression, and the "form" tag is implied. The
// method can be called using only ".login-form" and the expr is automatically
// converted to "form.login-form". A complete expression can still be used, for
// instance "div.login form".
func (b *Browser) Form(expr string) (FormElement, error) {
	sel := b.Page.doc.Find(prefixSelection(expr, "form"))
	if sel.Length() == 0 {
		return nil, errors.NewElementNotFound(
			"Form not found matching expr '%s'.", expr)
	}
	if !sel.Is("form") {
		return nil, errors.NewElementNotFound(
			"Expr '%s' does not match a form tag.", expr)
	}

	return NewForm(b, sel), nil
}

// Forms returns an array of every form in the page.
func (b *Browser) Forms() []FormElement {
	sel := b.Page.doc.Find("form")
	len := sel.Length()
	if len == 0 {
		return nil
	}

	forms := make([]FormElement, len)
	sel.Each(func(_ int, s *goquery.Selection) {
		forms = append(forms, NewForm(b, s))
	})
	return forms
}

// Links returns an array of every link found in the page.
func (b *Browser) Links() []*Link {
	sel := b.Page.doc.Find("a")
	links := make([]*Link, 0, sel.Length())

	sel.Each(func(_ int, s *goquery.Selection) {
		id, _ := s.Attr("id")
		href, ok := s.Attr("href")
		if ok {
			href, err := b.ResolveStringUrl(href)
			if err == nil {
				links = append(links, &Link{
					ID:   id,
					Href: href,
					Text: s.Text(),
				})
			}
		}
	})

	return links
}

// SiteCookies returns the cookies for the current site.
func (b *Browser) SiteCookies() []*http.Cookie {
	return b.Cookies.Cookies(b.Page.Url())
}

// SetAttribute sets a browser instruction attribute.
func (b *Browser) SetAttribute(a Attribute, v bool) {
	b.attributes[a] = v
}

// ResolveUrl returns an absolute URL for a possibly relative URL.
func (b *Browser) ResolveUrl(u *url.URL) *url.URL {
	return b.Url().ResolveReference(u)
}

// ResolveStringUrl works just like ResolveUrl, but the argument and return value are strings.
func (b *Browser) ResolveStringUrl(u string) (string, error) {
	pu, err := url.Parse(u)
	if err != nil {
		return "", err
	}
	pu = b.Url().ResolveReference(pu)
	return pu.String(), nil
}

// client creates, configures, and returns a *http.Client type.
func (b *Browser) client() *http.Client {
	client := &http.Client{}
	client.Jar = b.Cookies
	client.CheckRedirect = b.shouldRedirect
	return client
}

// request creates and returns a *http.Request type.
// Sets any headers that need to be sent with the request.
func (b *Browser) request(method, url string) (*http.Request, error) {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header = b.RequestHeaders
	req.Header["User-Agent"] = []string{b.UserAgent}
	return req, nil
}

// sendGet makes an HTTP GET request for the given URL.
// When via is not nil, and AttributeSendReferer is true, the Referer header will
// be set to via's URL.
func (b *Browser) sendGet(url string, via *Page) error {
	req, err := b.request("GET", url)
	if err != nil {
		return err
	}
	if b.attributes[SendRefererAttribute] && via != nil {
		req.Header["Referer"] = []string{via.Url().String()}
	}

	return b.send(req)
}

// sendPost makes an HTTP POST request for the given URL.
// When via is not nil, and AttributeSendReferer is true, the Referer header will
// be set to via's URL.
func (b *Browser) sendPost(url string, bodyType string, body io.Reader, via *Page) error {
	req, err := b.request("POST", url)
	if err != nil {
		return err
	}
	rc, ok := body.(io.ReadCloser)
	if !ok && body != nil {
		rc = ioutil.NopCloser(body)
	}
	req.Body = rc
	req.Header["Content-Type"] = []string{bodyType}
	if b.attributes[SendRefererAttribute] && via != nil {
		req.Header["Referer"] = []string{via.Url().String()}
	}

	return b.send(req)
}

// send uses the given *http.Request to make an HTTP request.
func (b *Browser) send(req *http.Request) error {
	b.preSend()
	resp, err := b.client().Do(req)
	if err != nil {
		return err
	}
	body, err := goquery.NewDocumentFromResponse(resp)
	if err != nil {
		return err
	}

	b.lastRequest = req
	b.History.Push(b.Page)
	b.Page = NewPage(resp, body)
	b.postSend()

	return nil
}

// preSend sets browser state before sending a request.
func (b *Browser) preSend() {
	if b.refresh != nil {
		b.refresh.Stop()
	}
}

// postSend sets browser state after sending a request.
func (b *Browser) postSend() {
	if b.attributes[MetaRefreshHandlingAttribute] {
		sel := b.Page.doc.Find("meta[http-equiv='refresh']")
		if sel.Length() > 0 {
			attr, ok := sel.Attr("content")
			if ok {
				dur, err := time.ParseDuration(attr + "s")
				if err == nil {
					b.refresh = time.NewTimer(dur)
					go func() {
						<-b.refresh.C
						b.Reload()
					}()
				}
			}
		}
	}
}

// shouldRedirect is used as the value to http.Client.CheckRedirect.
func (b *Browser) shouldRedirect(req *http.Request, _ []*http.Request) error {
	if b.attributes[FollowRedirectsAttribute] {
		return nil
	}
	return errors.NewLocation(
		"Redirects are disabled. Cannot follow '%s'.", req.URL.String())
}

// prefixSelection prefixes a selection expr with elm when sel is prefixed with
// one of the values from exprPrefixesImplied.
func prefixSelection(sel, elm string) string {
	for _, prefix := range exprPrefixesImplied {
		if strings.HasPrefix(sel, prefix) {
			return elm + sel
		}
	}
	return sel
}
<commit_msg>Updated comments<commit_after>package surf

import (
	"github.com/PuerkitoBio/goquery"
	"github.com/headzoo/surf/agents"
	"github.com/headzoo/surf/errors"
	"github.com/headzoo/surf/jars"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"time"
)

// Attribute represents a Browser capability.
type Attribute int

// AttributeMap represents a map of Attribute values.
type AttributeMap map[Attribute]bool

const (
	// SendRefererAttribute instructs a Browser to send the Referer header.
	SendRefererAttribute Attribute = iota

	// MetaRefreshHandlingAttribute instructs a Browser to handle the refresh meta tag.
	MetaRefreshHandlingAttribute

	// FollowRedirectsAttribute instructs a Browser to follow Location headers.
	FollowRedirectsAttribute
)

var (
	// DefaultUserAgent is the global user agent value.
	DefaultUserAgent = agents.Create()

	// DefaultSendRefererAttribute is the global value for the AttributeSendReferer attribute.
	DefaultSendRefererAttribute = true

	// DefaultMetaRefreshHandlingAttribute is the global value for the AttributeHandleRefresh attribute.
	DefaultMetaRefreshHandlingAttribute = true

	// DefaultFollowRedirectsAttribute is the global value for the AttributeFollowRedirects attribute.
	DefaultFollowRedirectsAttribute = true
)

// exprPrefixesImplied are strings a selection expr may start with, and the tag is implied.
var exprPrefixesImplied = []string{":", ".", "["}

// Link stores the properties of a page link.
type Link struct {
	// ID is the value of the id attribute or empty when there is no id.
	ID string

	// Href is the value of the href attribute.
	Href string

	// Text is the text appearing between the opening and closing anchor tag.
	Text string
}

// Browsable represents an HTTP web browser.
type Browsable interface {
	Document

	// Open requests the given URL using the GET method.
	Open(url string) error

	// OpenForm appends the data values to the given URL and sends a GET request.
	OpenForm(url string, data url.Values) error

	// OpenBookmark calls Get() with the URL for the bookmark with the given name.
	OpenBookmark(name string) error

	// Post requests the given URL using the POST method.
	Post(url string, bodyType string, body io.Reader) error

	// PostForm requests the given URL using the POST method with the given data.
	PostForm(url string, data url.Values) error

	// Back loads the previously requested page.
	Back() bool

	// Reload duplicates the last successful request.
	Reload() error

	// BookmarkPage saves the page URL in the bookmarks with the given name.
	BookmarkPage(name string) error

	// Click clicks on the page element matched by the given expression.
	Click(expr string) error

	// Form returns the form in the current page that matches the given expr.
	Form(expr string) (FormElement, error)

	// Forms returns an array of every form in the page.
	Forms() []FormElement

	// Links returns an array of every link found in the page.
	Links() []*Link

	// SiteCookies returns the cookies for the current site.
	SiteCookies() []*http.Cookie

	// SetAttribute sets a browser instruction attribute.
	SetAttribute(a Attribute, v bool)

	// ResolveUrl returns an absolute URL for a possibly relative URL.
	ResolveUrl(u *url.URL) *url.URL

	// ResolveStringUrl works just like ResolveUrl, but the argument and return value are strings.
	ResolveStringUrl(u string) (string, error)
}

// Browser is the default Browser implementation.
type Browser struct {
	*Page

	// UserAgent is the User-Agent header value sent with requests.
	UserAgent string

	// Cookies stores cookies for every site visited by the browser.
	Cookies http.CookieJar

	// Bookmarks stores the saved bookmarks.
	Bookmarks jars.BookmarksJar

	// History stores the visited pages.
	History *PageStack

	// RequestHeaders are additional headers to send with each request.
	RequestHeaders http.Header

	// lastRequest is the *http.Request for the last successful request.
	lastRequest *http.Request

	// attributes is the set browser attributes.
	attributes AttributeMap

	// refresh is a timer used to meta refresh pages.
	refresh *time.Timer
}

// NewBrowser creates and returns a *Browser type.
func NewBrowser() (*Browser, error) {
	cookies, err := cookiejar.New(nil)
	if err != nil {
		return nil, err
	}

	return &Browser{
		UserAgent:      DefaultUserAgent,
		Cookies:        cookies,
		Bookmarks:      jars.NewMemoryBookmarks(),
		History:        NewPageStack(),
		RequestHeaders: make(http.Header, 10),
		attributes: AttributeMap{
			SendRefererAttribute:         DefaultSendRefererAttribute,
			MetaRefreshHandlingAttribute: DefaultMetaRefreshHandlingAttribute,
			FollowRedirectsAttribute:     DefaultFollowRedirectsAttribute,
		},
	}, nil
}

// Open requests the given URL using the GET method.
func (b *Browser) Open(u string) error {
	return b.sendGet(u, nil)
}

// OpenForm appends the data values to the given URL and sends a GET request.
func (b *Browser) OpenForm(u string, data url.Values) error {
	ul, err := url.Parse(u)
	if err != nil {
		return err
	}
	ul.RawQuery = data.Encode()

	return b.Open(ul.String())
}

// OpenBookmark calls Open() with the URL for the bookmark with the given name.
func (b *Browser) OpenBookmark(name string) error {
	url, err := b.Bookmarks.Read(name)
	if err != nil {
		return err
	}
	return b.Open(url)
}

// Post requests the given URL using the POST method.
func (b *Browser) Post(u string, bodyType string, body io.Reader) error {
	return b.sendPost(u, bodyType, body, nil)
}

// PostForm requests the given URL using the POST method with the given data.
func (b *Browser) PostForm(u string, data url.Values) error {
	return b.Post(u, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}

// Back loads the previously requested page.
//
// Returns a boolean value indicating whether a previous page existed, and was
// successfully loaded.
func (b *Browser) Back() bool {
	if b.History.Len() > 0 {
		b.Page = b.History.Pop()
		return true
	}
	return false
}

// Reload duplicates the last successful request.
func (b *Browser) Reload() error {
	if b.lastRequest != nil {
		return b.send(b.lastRequest)
	}
	return errors.NewPageNotLoaded("Cannot reload, the previous request failed.")
}

// BookmarkPage saves the page URL in the bookmarks with the given name.
func (b *Browser) BookmarkPage(name string) error {
	return b.Bookmarks.Save(name, b.ResolveUrl(b.Page.Url()).String())
}

// Click clicks on the page element matched by the given expression.
//
// Currently this is only useful for click on links, which will cause the browser
// to load the page pointed at by the link. Future versions of Surf may support
// JavaScript and clicking on elements will fire the click event.
func (b *Browser) Click(expr string) error {
	sel := b.Page.doc.Find(prefixSelection(expr, "a"))
	if sel.Length() == 0 {
		return errors.NewElementNotFound(
			"Element not found matching expr '%s'.", expr)
	}
	if !sel.Is("a") {
		return errors.NewElementNotFound(
			"Expr '%s' must match an anchor tag.", expr)
	}

	href, ok := sel.Attr("href")
	if !ok {
		return errors.NewLinkNotFound(
			"No link found matching expr '%s'.", expr)
	}
	href, err := b.ResolveStringUrl(href)
	if err != nil {
		return err
	}

	return b.sendGet(href, b.Page)
}

// Form returns the form in the current page that matches the given expr.
//
// The expr can be any valid goquery expression, and the "form" tag is implied. The
// method can be called using only ".login-form" and the expr is automatically
// converted to "form.login-form". A complete expression can still be used, for
// instance "div.login form".
func (b *Browser) Form(expr string) (FormElement, error) {
	sel := b.Page.doc.Find(prefixSelection(expr, "form"))
	if sel.Length() == 0 {
		return nil, errors.NewElementNotFound(
			"Form not found matching expr '%s'.", expr)
	}
	if !sel.Is("form") {
		return nil, errors.NewElementNotFound(
			"Expr '%s' does not match a form tag.", expr)
	}

	return NewForm(b, sel), nil
}

// Forms returns an array of every form in the page.
//
// Returns nil when the page does not contain any forms.
func (b *Browser) Forms() []FormElement {
	sel := b.Page.doc.Find("form")
	len := sel.Length()
	if len == 0 {
		return nil
	}

	forms := make([]FormElement, len)
	sel.Each(func(_ int, s *goquery.Selection) {
		forms = append(forms, NewForm(b, s))
	})
	return forms
}

// Links returns an array of every link found in the page.
func (b *Browser) Links() []*Link {
	sel := b.Page.doc.Find("a")
	links := make([]*Link, 0, sel.Length())

	sel.Each(func(_ int, s *goquery.Selection) {
		id, _ := s.Attr("id")
		href, ok := s.Attr("href")
		if ok {
			href, err := b.ResolveStringUrl(href)
			if err == nil {
				links = append(links, &Link{
					ID:   id,
					Href: href,
					Text: s.Text(),
				})
			}
		}
	})

	return links
}

// SiteCookies returns the cookies for the current site.
func (b *Browser) SiteCookies() []*http.Cookie {
	return b.Cookies.Cookies(b.Page.Url())
}

// SetAttribute sets a browser instruction attribute.
func (b *Browser) SetAttribute(a Attribute, v bool) {
	b.attributes[a] = v
}

// ResolveUrl returns an absolute URL for a possibly relative URL.
func (b *Browser) ResolveUrl(u *url.URL) *url.URL {
	return b.Url().ResolveReference(u)
}

// ResolveStringUrl works just like ResolveUrl, but the argument and return value are strings.
func (b *Browser) ResolveStringUrl(u string) (string, error) {
	pu, err := url.Parse(u)
	if err != nil {
		return "", err
	}
	pu = b.Url().ResolveReference(pu)
	return pu.String(), nil
}

// client creates, configures, and returns a *http.Client type.
func (b *Browser) client() *http.Client {
	client := &http.Client{}
	client.Jar = b.Cookies
	client.CheckRedirect = b.shouldRedirect
	return client
}

// request creates and returns a *http.Request type.
// Sets any headers that need to be sent with the request.
func (b *Browser) request(method, url string) (*http.Request, error) {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header = b.RequestHeaders
	req.Header["User-Agent"] = []string{b.UserAgent}
	return req, nil
}

// sendGet makes an HTTP GET request for the given URL.
// When via is not nil, and AttributeSendReferer is true, the Referer header will
// be set to via's URL.
func (b *Browser) sendGet(url string, via *Page) error {
	req, err := b.request("GET", url)
	if err != nil {
		return err
	}
	if b.attributes[SendRefererAttribute] && via != nil {
		req.Header["Referer"] = []string{via.Url().String()}
	}

	return b.send(req)
}

// sendPost makes an HTTP POST request for the given URL.
// When via is not nil, and AttributeSendReferer is true, the Referer header will
// be set to via's URL.
func (b *Browser) sendPost(url string, bodyType string, body io.Reader, via *Page) error {
	req, err := b.request("POST", url)
	if err != nil {
		return err
	}
	rc, ok := body.(io.ReadCloser)
	if !ok && body != nil {
		rc = ioutil.NopCloser(body)
	}
	req.Body = rc
	req.Header["Content-Type"] = []string{bodyType}
	if b.attributes[SendRefererAttribute] && via != nil {
		req.Header["Referer"] = []string{via.Url().String()}
	}

	return b.send(req)
}

// send uses the given *http.Request to make an HTTP request.
func (b *Browser) send(req *http.Request) error {
	b.preSend()
	resp, err := b.client().Do(req)
	if err != nil {
		return err
	}
	body, err := goquery.NewDocumentFromResponse(resp)
	if err != nil {
		return err
	}

	b.lastRequest = req
	b.History.Push(b.Page)
	b.Page = NewPage(resp, body)
	b.postSend()

	return nil
}

// preSend sets browser state before sending a request.
func (b *Browser) preSend() {
	if b.refresh != nil {
		b.refresh.Stop()
	}
}

// postSend sets browser state after sending a request.
func (b *Browser) postSend() {
	if b.attributes[MetaRefreshHandlingAttribute] {
		sel := b.Page.doc.Find("meta[http-equiv='refresh']")
		if sel.Length() > 0 {
			attr, ok := sel.Attr("content")
			if ok {
				dur, err := time.ParseDuration(attr + "s")
				if err == nil {
					b.refresh = time.NewTimer(dur)
					go func() {
						<-b.refresh.C
						b.Reload()
					}()
				}
			}
		}
	}
}

// shouldRedirect is used as the value to http.Client.CheckRedirect.
func (b *Browser) shouldRedirect(req *http.Request, _ []*http.Request) error {
	if b.attributes[FollowRedirectsAttribute] {
		return nil
	}
	return errors.NewLocation(
		"Redirects are disabled. Cannot follow '%s'.", req.URL.String())
}

// prefixSelection prefixes a selection expr with elm when sel is prefixed with
// one of the values from exprPrefixesImplied.
func prefixSelection(sel, elm string) string {
	for _, prefix := range exprPrefixesImplied {
		if strings.HasPrefix(sel, prefix) {
			return elm + sel
		}
	}
	return sel
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"regexp"
)

// OptionType allows for the enumeration of different CLI option types.
type OptionType int

const (
	// None indicates that no option type is available.
	None OptionType = iota

	// Arg indicates that the option is an argument to be passed to the
	// executing code.
	Arg OptionType = iota

	// BuildArg indicates that the option is an argument to be passed to the
	// compiler if one is used for the target language.
	BuildArg OptionType = iota

	// Source indicates that the option is a source file.
	Source OptionType = iota

	// Include indicates that the option is a file or folder to be mounted
	// in the Docker container without passing it to the compiler or
	// executing code.
	Include OptionType = iota

	// Image indicates that the option value should be used to
	// override the image worked out based on the file extension.
	Image OptionType = iota

	// TargetDir indicates that the option specifies a custom location (i.e.
	// not the current working directory) to which the sources are
	// relatively specified.
	TargetDir OptionType = iota

	// UpdateFlag indicates that the option specifies that Docker images should
	// be manually updated before being used.
	UpdateFlag OptionType = iota

	// HelpFlag indicates that the option specifies the help flag.
	HelpFlag OptionType = iota

	// VersionFlag indicates that the option specifies the version flag.
	VersionFlag OptionType = iota

	// Extension specifies the override file extenision to use.
	Extension OptionType = iota

	// CleanFlag indicates that the option specifies the clean flag.
	CleanFlag OptionType = iota
)

// CLI defines a data structure that represents the application's name and
// a map of the various options to be used when starting the container.
type CLI struct {
	Filename string
	Options  map[OptionType][]string
}

// ArgToOption takes two candidate strings and returns a tuple consisting of
// what type of option the strings define, the value of the option, how many
// of the strings it took to extract the option value, and a nillable error.
func ArgToOption(opt string, next string) (OptionType, string, int, error) {
	patternStandaloneA := regexp.MustCompile(`^-(a|-arg)$`)
	patternStandaloneB := regexp.MustCompile(`^-(b|-build-arg)$`)
	patternStandaloneI := regexp.MustCompile(`^-(i|-include)$`)
	patternStandaloneM := regexp.MustCompile(`^-(m|-image)$`)
	patternStandaloneE := regexp.MustCompile(`^-(e|-extension)$`)
	patternStandaloneC := regexp.MustCompile(`^-C$`)
	patternCombinationA := regexp.MustCompile(`^--arg=(.+)$`)
	patternCombinationB := regexp.MustCompile(`^--build-arg=(.+)$`)
	patternCombinationI := regexp.MustCompile(`^--include=(.+)$`)
	patternCombinationM := regexp.MustCompile(`^--image=(.+)$`)
	patternCombinationE := regexp.MustCompile(`^--extension=(.+)$`)
	patternSource := regexp.MustCompile(`^[^-_].*\..+`)
	patternUpdateFlag := regexp.MustCompile(`^-(-update|u)$`)
	patternHelpFlag := regexp.MustCompile(`^-(-help|h)$`)
	patternVersionFlag := regexp.MustCompile(`^-(-version|v)$`)
	patternCleanFlag := regexp.MustCompile(`^--clean$`)

	switch {
	case patternStandaloneA.FindStringIndex(opt) != nil:
		return Arg, next, 2, nil
	case patternStandaloneB.FindStringIndex(opt) != nil:
		return BuildArg, next, 2, nil
	case patternStandaloneI.FindStringIndex(opt) != nil:
		return Include, next, 2, nil
	case patternStandaloneM.FindStringIndex(opt) != nil:
		return Image, next, 2, nil
	case patternStandaloneE.FindStringIndex(opt) != nil:
		return Extension, next, 2, nil
	case patternStandaloneC.FindStringIndex(opt) != nil:
		return TargetDir, next, 2, nil
	case patternCombinationA.FindStringIndex(opt) != nil:
		return Arg, patternCombinationA.FindStringSubmatch(opt)[1], 1, nil
	case patternCombinationB.FindStringIndex(opt) != nil:
		return BuildArg, patternCombinationB.FindStringSubmatch(opt)[1], 1, nil
	case patternCombinationI.FindStringIndex(opt) != nil:
		return Include, patternCombinationI.FindStringSubmatch(opt)[1], 1, nil
	case patternCombinationM.FindStringIndex(opt) != nil:
		return Image, patternCombinationM.FindStringSubmatch(opt)[1], 1, nil
	case patternCombinationE.FindStringIndex(opt) != nil:
		return Extension, patternCombinationE.FindStringSubmatch(opt)[1], 1, nil
	case patternUpdateFlag.FindStringIndex(opt) != nil:
		return UpdateFlag, "", 1, nil
	case patternHelpFlag.FindStringIndex(opt) != nil:
		return HelpFlag, "", 1, nil
	case patternVersionFlag.FindStringIndex(opt) != nil:
		return VersionFlag, "", 1, nil
	case patternCleanFlag.FindStringIndex(opt) != nil:
		return CleanFlag, "", 1, nil
	case patternSource.FindStringIndex(opt) != nil:
		return Source, opt, 1, nil
	default:
		return None, "", 0, fmt.Errorf("Unknown option: %s", opt)
	}
}

// ParseArgs take a string slice comprised of sources, includes, flags, switches
// and their values and returns a map of these types to a string slice
// of the values of each type of option.
func ParseArgs(args []string) map[OptionType][]string {
	if len(args) == 0 {
		return map[OptionType][]string{}
	}

	var next string
	if len(args) > 1 {
		next = args[1]
	}

	optionType, optionValue, nextIndex, _ := ArgToOption(args[0], next)

	if len(args) < nextIndex || nextIndex == 0 {
		return map[OptionType][]string{}
	}

	optionMap := ParseArgs(args[nextIndex:])
	optionMap[optionType] = append([]string{optionValue}, optionMap[optionType]...)
	return optionMap
}

// ParseOsArgs takes a string slice representing the full arguments passed to
// the program, including the filename and returns a CLI containing the
// filename and map of option types to their values.
func ParseOsArgs(args []string) CLI {
	return CLI{
		Filename: args[0],
		Options:  ParseArgs(args[1:]),
	}
}

// DisplayHelp takes a filename and prints the help information for the program.
func DisplayHelp(filename string) {
	fmt.Println("Name:")
	fmt.Printf("\t%s - Execute code in many languages with Docker!\n", filename)
	fmt.Println()
	fmt.Println("Usage:")
	fmt.Printf("\t%s [options] <source files...>\n", filename)
	fmt.Println()
	fmt.Println("Options:")
	fmt.Printf("\t%-36s%s\n", "-C <dir>", "Specify source directory")
	fmt.Printf("\t%-36s%s\n", "--arg, -a <argument>", "Pass <argument> to the executing code")
	fmt.Printf("\t%-36s%s\n", "--build-arg, -b <build argument>", "Pass <build argument> to compiler")
	fmt.Printf("\t%-36s%s\n", "--include, -i <file|path>", "Mount local <file|path> in dexec container")
	fmt.Printf("\t%-36s%s\n", "--extension, -e <extension>", "Override the image used by <extension>")
	fmt.Printf("\t%-36s%s\n", "--image, -m <name>", "Override the image used by <name>")
	fmt.Printf("\t%-36s%s\n", "--update, -u", "Force update of image")
	fmt.Printf("\t%-36s%s\n", "--clean", "Remove all local dexec images")
	fmt.Printf("\t%-36s%s\n", "--help, -h", "Show help")
	fmt.Printf("\t%-36s%s\n", "--version, -v", "Display version info")
}

// DisplayVersion prints the version information for the program.
func DisplayVersion(filename string) {
	fmt.Printf("%s 1.0.7\n", filename)
}
<commit_msg>Bump master version to 1.0.8-SNAPSHOT<commit_after>package cli

import (
	"fmt"
	"regexp"
)

// OptionType allows for the enumeration of different CLI option types.
type OptionType int

const (
	// None indicates that no option type is available.
	None OptionType = iota

	// Arg indicates that the option is an argument to be passed to the
	// executing code.
	Arg OptionType = iota

	// BuildArg indicates that the option is an argument to be passed to the
	// compiler if one is used for the target language.
	BuildArg OptionType = iota

	// Source indicates that the option is a source file.
	Source OptionType = iota

	// Include indicates that the option is a file or folder to be mounted
	// in the Docker container without passing it to the compiler or
	// executing code.
	Include OptionType = iota

	// Image indicates that the option value should be used to
	// override the image worked out based on the file extension.
	Image OptionType = iota

	// TargetDir indicates that the option specifies a custom location (i.e.
	// not the current working directory) to which the sources are
	// relatively specified.
	TargetDir OptionType = iota

	// UpdateFlag indicates that the option specifies that Docker images should
	// be manually updated before being used.
	UpdateFlag OptionType = iota

	// HelpFlag indicates that the option specifies the help flag.
	HelpFlag OptionType = iota

	// VersionFlag indicates that the option specifies the version flag.
	VersionFlag OptionType = iota

	// Extension specifies the override file extenision to use.
	Extension OptionType = iota

	// CleanFlag indicates that the option specifies the clean flag.
	CleanFlag OptionType = iota
)

// CLI defines a data structure that represents the application's name and
// a map of the various options to be used when starting the container.
type CLI struct {
	Filename string
	Options  map[OptionType][]string
}

// ArgToOption takes two candidate strings and returns a tuple consisting of
// what type of option the strings define, the value of the option, how many
// of the strings it took to extract the option value, and a nillable error.
func ArgToOption(opt string, next string) (OptionType, string, int, error) {
	patternStandaloneA := regexp.MustCompile(`^-(a|-arg)$`)
	patternStandaloneB := regexp.MustCompile(`^-(b|-build-arg)$`)
	patternStandaloneI := regexp.MustCompile(`^-(i|-include)$`)
	patternStandaloneM := regexp.MustCompile(`^-(m|-image)$`)
	patternStandaloneE := regexp.MustCompile(`^-(e|-extension)$`)
	patternStandaloneC := regexp.MustCompile(`^-C$`)
	patternCombinationA := regexp.MustCompile(`^--arg=(.+)$`)
	patternCombinationB := regexp.MustCompile(`^--build-arg=(.+)$`)
	patternCombinationI := regexp.MustCompile(`^--include=(.+)$`)
	patternCombinationM := regexp.MustCompile(`^--image=(.+)$`)
	patternCombinationE := regexp.MustCompile(`^--extension=(.+)$`)
	patternSource := regexp.MustCompile(`^[^-_].*\..+`)
	patternUpdateFlag := regexp.MustCompile(`^-(-update|u)$`)
	patternHelpFlag := regexp.MustCompile(`^-(-help|h)$`)
	patternVersionFlag := regexp.MustCompile(`^-(-version|v)$`)
	patternCleanFlag := regexp.MustCompile(`^--clean$`)

	switch {
	case patternStandaloneA.FindStringIndex(opt) != nil:
		return Arg, next, 2, nil
	case patternStandaloneB.FindStringIndex(opt) != nil:
		return BuildArg, next, 2, nil
	case patternStandaloneI.FindStringIndex(opt) != nil:
		return Include, next, 2, nil
	case patternStandaloneM.FindStringIndex(opt) != nil:
		return Image, next, 2, nil
	case patternStandaloneE.FindStringIndex(opt) != nil:
		return Extension, next, 2, nil
	case patternStandaloneC.FindStringIndex(opt) != nil:
		return TargetDir, next, 2, nil
	case patternCombinationA.FindStringIndex(opt) != nil:
		return Arg, patternCombinationA.FindStringSubmatch(opt)[1], 1, nil
	case patternCombinationB.FindStringIndex(opt) != nil:
		return BuildArg, patternCombinationB.FindStringSubmatch(opt)[1], 1, nil
	case patternCombinationI.FindStringIndex(opt) != nil:
		return Include, patternCombinationI.FindStringSubmatch(opt)[1], 1, nil
	case patternCombinationM.FindStringIndex(opt) != nil:
		return Image, patternCombinationM.FindStringSubmatch(opt)[1], 1, nil
	case patternCombinationE.FindStringIndex(opt) != nil:
		return Extension, patternCombinationE.FindStringSubmatch(opt)[1], 1, nil
	case patternUpdateFlag.FindStringIndex(opt) != nil:
		return UpdateFlag, "", 1, nil
	case patternHelpFlag.FindStringIndex(opt) != nil:
		return HelpFlag, "", 1, nil
	case patternVersionFlag.FindStringIndex(opt) != nil:
		return VersionFlag, "", 1, nil
	case patternCleanFlag.FindStringIndex(opt) != nil:
		return CleanFlag, "", 1, nil
	case patternSource.FindStringIndex(opt) != nil:
		return Source, opt, 1, nil
	default:
		return None, "", 0, fmt.Errorf("Unknown option: %s", opt)
	}
}

// ParseArgs take a string slice comprised of sources, includes, flags, switches
// and their values and returns a map of these types to a string slice
// of the values of each type of option.
func ParseArgs(args []string) map[OptionType][]string {
	if len(args) == 0 {
		return map[OptionType][]string{}
	}

	var next string
	if len(args) > 1 {
		next = args[1]
	}

	optionType, optionValue, nextIndex, _ := ArgToOption(args[0], next)

	if len(args) < nextIndex || nextIndex == 0 {
		return map[OptionType][]string{}
	}

	optionMap := ParseArgs(args[nextIndex:])
	optionMap[optionType] = append([]string{optionValue}, optionMap[optionType]...)
	return optionMap
}

// ParseOsArgs takes a string slice representing the full arguments passed to
// the program, including the filename and returns a CLI containing the
// filename and map of option types to their values.
func ParseOsArgs(args []string) CLI {
	return CLI{
		Filename: args[0],
		Options:  ParseArgs(args[1:]),
	}
}

// DisplayHelp takes a filename and prints the help information for the program.
func DisplayHelp(filename string) {
	fmt.Println("Name:")
	fmt.Printf("\t%s - Execute code in many languages with Docker!\n", filename)
	fmt.Println()
	fmt.Println("Usage:")
	fmt.Printf("\t%s [options] <source files...>\n", filename)
	fmt.Println()
	fmt.Println("Options:")
	fmt.Printf("\t%-36s%s\n", "-C <dir>", "Specify source directory")
	fmt.Printf("\t%-36s%s\n", "--arg, -a <argument>", "Pass <argument> to the executing code")
	fmt.Printf("\t%-36s%s\n", "--build-arg, -b <build argument>", "Pass <build argument> to compiler")
	fmt.Printf("\t%-36s%s\n", "--include, -i <file|path>", "Mount local <file|path> in dexec container")
	fmt.Printf("\t%-36s%s\n", "--extension, -e <extension>", "Override the image used by <extension>")
	fmt.Printf("\t%-36s%s\n", "--image, -m <name>", "Override the image used by <name>")
	fmt.Printf("\t%-36s%s\n", "--update, -u", "Force update of image")
	fmt.Printf("\t%-36s%s\n", "--clean", "Remove all local dexec images")
	fmt.Printf("\t%-36s%s\n", "--help, -h", "Show help")
	fmt.Printf("\t%-36s%s\n", "--version, -v", "Display version info")
}

// DisplayVersion prints the version information for the program.
func DisplayVersion(filename string) {
	fmt.Printf("%s 1.0.8-SNAPSHOT\n", filename)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package cli

import(
	`github.com/michaeldv/donna`
	`bufio`
	`fmt`
	`os`
	`strings`
)

// Brain-damaged universal chess interface (UCI) protocol as described at
// http://wbec-ridderkerk.nl/html/UCIProtocol.html
func Uci() {
	var game *donna.Game
	var position *donna.Position

	// "uci" command handler.
	doUci := func(g *donna.Game, args []string) {
		fmt.Println(`Donna v1.0.0 Copyright (c) 2014 by Michael Dvorkin. All Rights Reserved.`)
		fmt.Println(`id author Michael Dvorkin`)
		fmt.Println(`uciok`)
	}

	// "ucinewgame" command handler.
	doUciNewGame := func(g *donna.Game, args []string) {
		game, position = nil, nil
	}

	// "isready" command handler.
	doIsReady := func(g *donna.Game, args []string) {
		fmt.Println(`readyok`)
	}

	// "position [startpos | fen ] [ moves ... ]" command handler.
	doPosition := func(g *donna.Game, args []string) {
		fmt.Printf("%q\n", args)

		// Make sure we've started the game since "ucinewgame" is optional.
		if game == nil || position == nil {
			game = donna.NewGame().Set(`cache`, 64, `movetime`, 5000) // 5s per move.
			position = game.Start()
		}

		switch args[0] {
		case `startpos`:
			args = args[1:]
			position = donna.NewInitialPosition(game)
		case `fen`:
			fen := ``
			for _, token := range args[1:] {
				args = args[1:] // Shift the token.
				if token == `moves` {
					break
				}
				fen += token + ` `
			}
			fmt.Printf("fen: %s\n", fen)
			position = donna.NewPositionFromFEN(game, fen)
		default: return
		}

		fmt.Printf("args: %q\n%s\n", args, position)
		if position != nil && len(args) > 0 && args[0] == `moves` {
			for _, move := range args[1:] {
				args = args[1:] // Shift the move.
				position = position.MakeMove(donna.NewMoveFromString(position, move))
			}
		}
		fmt.Printf("%s\n", position)
	}

	var commands = map[string]func(*donna.Game, []string){
		`isready`: doIsReady,
		`uci`: doUci,
		`ucinewgame`: doUciNewGame,
		`position`: doPosition,
	}

 	bio := bufio.NewReader(os.Stdin)
	for {
		command, _ := bio.ReadString('\n')
		args := strings.Split(command[:len(command)-1], ` `)
		if args[0] == `quit` {
			break
		}
		if handler, found := commands[args[0]]; found {
			handler(game, args[1:])
		}
	}
}
<commit_msg>Convert moves from coordinate notation in UCI position command<commit_after>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package cli

import(
	`github.com/michaeldv/donna`
	`bufio`
	`fmt`
	`os`
	`strings`
)

// Brain-damaged universal chess interface (UCI) protocol as described at
// http://wbec-ridderkerk.nl/html/UCIProtocol.html
func Uci() {
	var game *donna.Game
	var position *donna.Position

	// "uci" command handler.
	doUci := func(args []string) {
		fmt.Println(`Donna v1.0.0 Copyright (c) 2014 by Michael Dvorkin. All Rights Reserved.`)
		fmt.Println(`id author Michael Dvorkin`)
		fmt.Println(`uciok`)
	}

	// "ucinewgame" command handler.
	doUciNewGame := func(args []string) {
		game, position = nil, nil
	}

	// "isready" command handler.
	doIsReady := func(args []string) {
		fmt.Println(`readyok`)
	}

	// "position [startpos | fen ] [ moves ... ]" command handler.
	doPosition := func(args []string) {
		fmt.Printf("%q\n", args)

		// Make sure we've started the game since "ucinewgame" is optional.
		if game == nil || position == nil {
			game = donna.NewGame().Set(`cache`, 64, `movetime`, 5000) // 5s per move.
			position = game.Start()
		}

		switch args[0] {
		case `startpos`:
			args = args[1:]
			position = donna.NewInitialPosition(game)
		case `fen`:
			fen := []string{}
			for _, token := range args[1:] {
				args = args[1:] // Shift the token.
				if token == `moves` {
					break
				}
				fen = append(fen, token)
			}
			fmt.Printf("fen: %s\n", strings.Join(fen, ` `))
			position = donna.NewPositionFromFEN(game, strings.Join(fen, ` `))
		default: return
		}

		fmt.Printf("args: %q\n%s\n", args, position)
		if position != nil && len(args) > 0 && args[0] == `moves` {
			for _, move := range args[1:] {
				args = args[1:] // Shift the move.
				position = position.MakeMove(donna.NewMoveFromNotation(position, move))
			}
		}
		fmt.Printf("%s\n", position)
	}

	var commands = map[string]func([]string){
		`isready`: doIsReady,
		`uci`: doUci,
		`ucinewgame`: doUciNewGame,
		`position`: doPosition,
	}

 	bio := bufio.NewReader(os.Stdin)
	for {
		command, _ := bio.ReadString('\n')
		args := strings.Split(command[:len(command)-1], ` `)
		if args[0] == `quit` {
			break
		}
		if handler, found := commands[args[0]]; found {
			handler(args[1:])
		}
	}
}
<|endoftext|>


<commit_before>/* Client functions */

/*
 * Copyright (c) 2013-2014, Jeremy Bingham (<jbingham@gmail.com>)
 *
 * 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 main

import (
	"net/http"
	"encoding/json"
	"github.com/ctdk/goiardi/actor"
	"github.com/ctdk/goiardi/util"
	"fmt"
	"strings"
)

func actor_handler(w http.ResponseWriter, r *http.Request){
	w.Header().Set("Content-Type", "application/json")
	path := SplitPath(r.URL.Path)
	op := path[0]
	client_name := path[1]
	opUser, oerr := actor.GetReqUser(r.Header.Get("X-OPS-USERID"))
	if oerr != nil {
		JsonErrorReport(w, r, oerr.Error(), oerr.Status())
		return
	}

	chef_type := strings.TrimSuffix(op, "s")
	/* Make sure we aren't trying anything with a user */
	c_chk, _ := actor.Get(client_name)
	if (c_chk != nil && c_chk.ChefType != chef_type){
		var other_actor_type string
		if chef_type == "client" {
			other_actor_type = "user"
		} else {
			other_actor_type = "client"
		}
		err_user := fmt.Errorf("%s is a %s, not a client.", client_name, chef_type, other_actor_type)
		JsonErrorReport(w, r, err_user.Error(), http.StatusBadRequest)
		return
	}
	switch r.Method {
		case "DELETE":
			chef_client, err := actor.Get(client_name)
			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusNotFound)
				return
			}
			if !opUser.IsAdmin() && !opUser.IsSelf(chef_client) {
				JsonErrorReport(w, r, "Deleting that client is forbidden", http.StatusForbidden)
				return
			}
			/* Docs were incorrect. It does want the body of the
			 * deleted object. */
			enc := json.NewEncoder(w)
			if err = enc.Encode(&chef_client); err != nil{
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}
			err = chef_client.Delete()
			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}

		case "GET":
			chef_client, err := actor.Get(client_name)

			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusNotFound)
				return
			}
			if !opUser.IsAdmin() && !opUser.IsSelf(chef_client) {
				JsonErrorReport(w, r, "You are not allowed to perform that action.", http.StatusForbidden)
				return
			}

			/* API docs are wrong here re: public_key vs.
			 * certificate. Also orgname (at least w/ open source)
			 * and clientname, and it wants chef_type and
			 * json_class
			 */
			json_client := map[string]interface{}{
				"name": chef_client.Name, // set same as above
							  // for now
				"chef_type": chef_client.ChefType,
				"admin": chef_client.Admin,
				//"orgname": chef_client.Orgname,
				"public_key": chef_client.PublicKey,
			}
			if op != "users" {
				json_client["validator"] = chef_client.Validator
				json_client["json_class"] = chef_client.JsonClass
			}
			enc := json.NewEncoder(w)
			if err = enc.Encode(&json_client); err != nil{
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}
		case "PUT":
			client_data, jerr := ParseObjJson(r.Body)
			if jerr != nil {
				JsonErrorReport(w, r, jerr.Error(), http.StatusBadRequest)
				return
			}
			chef_client, err := actor.Get(client_name)
			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusNotFound)
				return
			}

			if !opUser.IsAdmin() && !opUser.IsSelf(chef_client) {
				JsonErrorReport(w, r, "You are not allowed to perform that action.", http.StatusForbidden)
				return
			}
			if !opUser.IsAdmin() {
				var verr util.Gerror
				aerr := opUser.CheckPermEdit(client_data, "admin")
				if !opUser.IsValidator() {
					verr = opUser.CheckPermEdit(client_data, "validator")
				}
				if aerr != nil && verr != nil {
					JsonErrorReport(w, r, "Client can be either an admin or a validator, but not both.", http.StatusBadRequest)
					return
				} else if aerr != nil || verr != nil {
					if aerr == nil {
						aerr = verr
					}
					JsonErrorReport(w, r, aerr.Error(), aerr.Status())
					return
				}
			}

			json_name, sterr := util.ValidateAsString(client_data["name"])
			if sterr != nil {
				JsonErrorReport(w, r, sterr.Error(), http.StatusBadRequest)
				return
			}

			/* If client_name and client_data["name"] aren't the
			 * same, we're renaming. Check the new name doesn't
			 * already exist. */
			json_client := make(map[string]interface{})
			if client_name != json_name {
				err := chef_client.Rename(json_name)
				if err != nil {
					JsonErrorReport(w, r, err.Error(), err.Status())
					return
				} else {
					w.WriteHeader(http.StatusCreated)
				}
			}
			if uerr := chef_client.UpdateFromJson(client_data, chef_type); uerr != nil {
				JsonErrorReport(w, r, uerr.Error(), uerr.Status())
				return
			}

			if pk, pkfound := client_data["public_key"]; pkfound {
				switch pk := pk.(type){
					case string:
						if pkok, pkerr := actor.ValidatePublicKey(pk); !pkok {
							JsonErrorReport(w, r, pkerr.Error(), http.StatusBadRequest)
							return
						}
						chef_client.PublicKey = pk
					case nil:
						//show_public_key = false
						;
					default:
						JsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
						return
				}
			}

			if p, pfound := client_data["private_key"]; pfound {
				switch p := p.(type) {
					case bool:
						if p {
							if json_client["private_key"], err = chef_client.GenerateKeys(); err != nil {
								JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
								return
							}
						}
					default:
						JsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
						return
				}
			}

			chef_client.Save()
			json_client["name"] = chef_client.Name
			json_client["admin"] = chef_client.Admin
			if op != "users" {
				json_client["validator"] = chef_client.Validator
				json_client["public_key"] = chef_client.PublicKey
			}
			enc := json.NewEncoder(w)
			if err = enc.Encode(&json_client); err != nil{
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}
		default:
			JsonErrorReport(w, r, "Unrecognized method for client!", http.StatusMethodNotAllowed)
	}
}
<commit_msg>User validation chugging along<commit_after>/* Client functions */

/*
 * Copyright (c) 2013-2014, Jeremy Bingham (<jbingham@gmail.com>)
 *
 * 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 main

import (
	"net/http"
	"encoding/json"
	"github.com/ctdk/goiardi/actor"
	"github.com/ctdk/goiardi/util"
	"fmt"
	"strings"
)

func actor_handler(w http.ResponseWriter, r *http.Request){
	w.Header().Set("Content-Type", "application/json")
	path := SplitPath(r.URL.Path)
	op := path[0]
	client_name := path[1]
	opUser, oerr := actor.GetReqUser(r.Header.Get("X-OPS-USERID"))
	if oerr != nil {
		JsonErrorReport(w, r, oerr.Error(), oerr.Status())
		return
	}

	chef_type := strings.TrimSuffix(op, "s")
	/* Make sure we aren't trying anything with a user */
	c_chk, _ := actor.Get(client_name)
	if (c_chk != nil && c_chk.ChefType != chef_type){
		var other_actor_type string
		if chef_type == "client" {
			other_actor_type = "user"
		} else {
			other_actor_type = "client"
		}
		err_user := fmt.Errorf("%s is a %s, not a client.", client_name, chef_type, other_actor_type)
		JsonErrorReport(w, r, err_user.Error(), http.StatusBadRequest)
		return
	}
	switch r.Method {
		case "DELETE":
			chef_client, err := actor.Get(client_name)
			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusNotFound)
				return
			}
			if !opUser.IsAdmin() && !opUser.IsSelf(chef_client) {
				JsonErrorReport(w, r, "Deleting that client is forbidden", http.StatusForbidden)
				return
			}
			/* Docs were incorrect. It does want the body of the
			 * deleted object. */
			enc := json.NewEncoder(w)
			if err = enc.Encode(&chef_client); err != nil{
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}
			err = chef_client.Delete()
			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}

		case "GET":
			chef_client, err := actor.Get(client_name)

			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusNotFound)
				return
			}
			if !opUser.IsAdmin() && !opUser.IsSelf(chef_client) {
				JsonErrorReport(w, r, "You are not allowed to perform that action.", http.StatusForbidden)
				return
			}

			/* API docs are wrong here re: public_key vs.
			 * certificate. Also orgname (at least w/ open source)
			 * and clientname, and it wants chef_type and
			 * json_class
			 */
			json_client := map[string]interface{}{
				"name": chef_client.Name, // set same as above
							  // for now
				"admin": chef_client.Admin,
				//"orgname": chef_client.Orgname,
				"public_key": chef_client.PublicKey,
			}
			if op != "users" {
				json_client["validator"] = chef_client.Validator
				json_client["json_class"] = chef_client.JsonClass
				json_client["chef_type"] = chef_client.ChefType
			}
			enc := json.NewEncoder(w)
			if err = enc.Encode(&json_client); err != nil{
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}
		case "PUT":
			client_data, jerr := ParseObjJson(r.Body)
			if jerr != nil {
				JsonErrorReport(w, r, jerr.Error(), http.StatusBadRequest)
				return
			}
			chef_client, err := actor.Get(client_name)
			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusNotFound)
				return
			}

			if !opUser.IsAdmin() && !opUser.IsSelf(chef_client) {
				JsonErrorReport(w, r, "You are not allowed to perform that action.", http.StatusForbidden)
				return
			}
			if !opUser.IsAdmin() {
				var verr util.Gerror
				aerr := opUser.CheckPermEdit(client_data, "admin")
				if !opUser.IsValidator() {
					verr = opUser.CheckPermEdit(client_data, "validator")
				}
				if aerr != nil && verr != nil {
					JsonErrorReport(w, r, "Client can be either an admin or a validator, but not both.", http.StatusBadRequest)
					return
				} else if aerr != nil || verr != nil {
					if aerr == nil {
						aerr = verr
					}
					JsonErrorReport(w, r, aerr.Error(), aerr.Status())
					return
				}
			}

			json_name, sterr := util.ValidateAsString(client_data["name"])
			if sterr != nil {
				JsonErrorReport(w, r, sterr.Error(), http.StatusBadRequest)
				return
			}

			/* If client_name and client_data["name"] aren't the
			 * same, we're renaming. Check the new name doesn't
			 * already exist. */
			json_client := make(map[string]interface{})
			if client_name != json_name {
				err := chef_client.Rename(json_name)
				if err != nil {
					JsonErrorReport(w, r, err.Error(), err.Status())
					return
				} else {
					w.WriteHeader(http.StatusCreated)
				}
			}
			if uerr := chef_client.UpdateFromJson(client_data, chef_type); uerr != nil {
				JsonErrorReport(w, r, uerr.Error(), uerr.Status())
				return
			}

			if pk, pkfound := client_data["public_key"]; pkfound {
				switch pk := pk.(type){
					case string:
						if pkok, pkerr := actor.ValidatePublicKey(pk); !pkok {
							JsonErrorReport(w, r, pkerr.Error(), http.StatusBadRequest)
							return
						}
						chef_client.PublicKey = pk
					case nil:
						//show_public_key = false
						;
					default:
						JsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
						return
				}
			}

			if p, pfound := client_data["private_key"]; pfound {
				switch p := p.(type) {
					case bool:
						if p {
							if json_client["private_key"], err = chef_client.GenerateKeys(); err != nil {
								JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
								return
							}
						}
					default:
						JsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
						return
				}
			}

			chef_client.Save()
			json_client["name"] = chef_client.Name
			json_client["admin"] = chef_client.Admin
			if op != "users" {
				json_client["validator"] = chef_client.Validator
				json_client["public_key"] = chef_client.PublicKey
			}
			enc := json.NewEncoder(w)
			if err = enc.Encode(&json_client); err != nil{
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}
		default:
			JsonErrorReport(w, r, "Unrecognized method for client!", http.StatusMethodNotAllowed)
	}
}
<|endoftext|>