<commit_before>package goyaml_test

import (
	"fmt"
	. "launchpad.net/gocheck"
	"launchpad.net/goyaml"
	"math"
	"strconv"
	"strings"
)

var marshalIntTest = 123

var marshalTests = []struct {
	data  string
	value interface{}
}{
	{"{}\n", &struct{}{}},
	{"v: hi\n", map[string]string{"v": "hi"}},
	{"v: hi\n", map[string]interface{}{"v": "hi"}},
	{"v: \"true\"\n", map[string]string{"v": "true"}},
	{"v: \"false\"\n", map[string]string{"v": "false"}},
	{"v: true\n", map[string]interface{}{"v": true}},
	{"v: false\n", map[string]interface{}{"v": false}},
	{"v: 10\n", map[string]interface{}{"v": 10}},
	{"v: -10\n", map[string]interface{}{"v": -10}},
	{"v: 42\n", map[string]uint{"v": 42}},
	{"v: 4294967296\n", map[string]interface{}{"v": int64(4294967296)}},
	{"v: 4294967296\n", map[string]int64{"v": int64(4294967296)}},
	{"v: 4294967296\n", map[string]uint64{"v": 4294967296}},
	{"v: \"10\"\n", map[string]interface{}{"v": "10"}},
	{"v: 0.1\n", map[string]interface{}{"v": 0.1}},
	{"v: 0.1\n", map[string]interface{}{"v": float64(0.1)}},
	{"v: -0.1\n", map[string]interface{}{"v": -0.1}},
	{"v: .inf\n", map[string]interface{}{"v": math.Inf(+1)}},
	{"v: -.inf\n", map[string]interface{}{"v": math.Inf(-1)}},
	{"v: .nan\n", map[string]interface{}{"v": math.NaN()}},
	{"v: null\n", map[string]interface{}{"v": nil}},
	{"v: \"\"\n", map[string]interface{}{"v": ""}},
	{"v:\n- A\n- B\n", map[string][]string{"v": []string{"A", "B"}}},
	{"v:\n- A\n- 1\n", map[string][]interface{}{"v": []interface{}{"A", 1}}},
	{"a:\n  b: c\n",
		map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}},

	// Simple values.
	{"123\n", &marshalIntTest},

	// Structures
	{"hello: world\n", &struct{ Hello string }{"world"}},
	{"a:\n  b: c\n", &struct {
		A struct {
			B string
		}
	}{struct{ B string }{"c"}}},
	{"a:\n  b: c\n", &struct {
		A *struct {
			B string
		}
	}{&struct{ B string }{"c"}}},
	{"a: null\n", &struct {
		A *struct {
			B string
		}
	}{}},
	{"a: 1\n", &struct{ A int }{1}},
	{"a:\n- 1\n- 2\n", &struct{ A []int }{[]int{1, 2}}},
	{"a: 1\n", &struct {
		B int "a"
	}{1}},
	{"a: true\n", &struct{ A bool }{true}},

	// Conditional flag
	{"a: 1\n", &struct {
		A int "a,omitempty"
		B int "b,omitempty"
	}{1, 0}},
	{"{}\n", &struct {
		A int "a,omitempty"
		B int "b,omitempty"
	}{0, 0}},
	{"{}\n", &struct {
		A *struct{ X int } "a,omitempty"
		B int              "b,omitempty"
	}{nil, 0}},

	// Flow flag
	{"a: [1, 2]\n", &struct {
		A []int "a,flow"
	}{[]int{1, 2}}},
	{"a: {b: c}\n",
		&struct {
			A map[string]string "a,flow"
		}{map[string]string{"b": "c"}}},
	{"a: {b: c}\n",
		&struct {
			A struct {
				B string
			} "a,flow"
		}{struct{ B string }{"c"}}},
}

func (s *S) TestMarshal(c *C) {
	for _, item := range marshalTests {
		data, err := goyaml.Marshal(item.value)
		c.Assert(err, IsNil)
		c.Assert(string(data), Equals, item.data)
	}
}

//var unmarshalErrorTests = []struct{data, error string}{
//    {"v: !!float 'error'", "Can't decode !!str 'error' as a !!float"},
//}
//
//func (s *S) TestUnmarshalErrors(c *C) {
//    for _, item := range unmarshalErrorTests {
//        var value interface{}
//        err := goyaml.Unmarshal([]byte(item.data), &value)
//        c.Assert(err, Matches, item.error)
//    }
//}

var marshalTaggedIfaceTest interface{} = &struct{ A string }{"B"}

var getterTests = []struct {
	data, tag string
	value     interface{}
}{
	{"_:\n  hi: there\n", "", map[interface{}]interface{}{"hi": "there"}},
	{"_:\n- 1\n- A\n", "", []interface{}{1, "A"}},
	{"_: 10\n", "", 10},
	{"_: null\n", "", nil},
	{"_: !foo BAR!\n", "!foo", "BAR!"},
	{"_: !foo 1\n", "!foo", "1"},
	{"_: !foo '\"1\"'\n", "!foo", "\"1\""},
	{"_: !foo 1.1\n", "!foo", 1.1},
	{"_: !foo 1\n", "!foo", 1},
	{"_: !foo 1\n", "!foo", uint(1)},
	{"_: !foo true\n", "!foo", true},
	{"_: !foo\n- A\n- B\n", "!foo", []string{"A", "B"}},
	{"_: !foo\n  A: B\n", "!foo", map[string]string{"A": "B"}},
	{"_: !foo\n  a: B\n", "!foo", &marshalTaggedIfaceTest},
}

type typeWithGetter struct {
	tag   string
	value interface{}
}

func (o typeWithGetter) GetYAML() (tag string, value interface{}) {
	return o.tag, o.value
}

type typeWithGetterField struct {
	Field typeWithGetter "_"
}

func (s *S) TestMashalWithGetter(c *C) {
	for _, item := range getterTests {
		obj := &typeWithGetterField{}
		obj.Field.tag = item.tag
		obj.Field.value = item.value
		data, err := goyaml.Marshal(obj)
		c.Assert(err, IsNil)
		c.Assert(string(data), Equals, string(item.data))
	}
}

func (s *S) TestUnmarshalWholeDocumentWithGetter(c *C) {
	obj := &typeWithGetter{}
	obj.tag = ""
	obj.value = map[string]string{"hello": "world!"}
	data, err := goyaml.Marshal(obj)
	c.Assert(err, IsNil)
	c.Assert(string(data), Equals, "hello: world!\n")
}

func (s *S) TestSortedOutput(c *C) {
	order := []interface{}{
		false,
		true,
		1,
		uint(1),
		1.0,
		1.1,
		1.2,
		2,
		uint(2),
		2.0,
		2.1,
		".1",
		".2",
		".a",
		"1",
		"2",
		"a!10",
		"a/2",
		"a/10",
		"a~10",
		"ab/1",
		"b/1",
		"b/01",
		"b/2",
		"b/02",
		"b/3",
		"b/03",
		"b1",
		"b01",
		"b3",
		"c2.10",
		"c10.2",
		"d1",
		"d12",
		"d12a",
	}
	m := make(map[interface{}]int)
	for _, k := range order {
		m[k] = 1
	}
	data, err := goyaml.Marshal(m)
	c.Assert(err, IsNil)
	out := "\n" + string(data)
	last := 0
	for i, k := range order {
		repr := fmt.Sprint(k)
		if _, ok := k.(string); ok {
			if _, err = strconv.ParseFloat(repr, 32); err == nil {
				repr = `"` + repr + `"`
			}
		}
		index := strings.Index(out, "\n"+repr+":")
		if index == -1 {
			c.Fatalf("%#v is not in the output: %#v", k, out)
		}
		if index < last {
			c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
		}
		last = index
	}
}
<commit_msg>Add empty string to test as well, as suggested by Dave.<commit_after>package goyaml_test

import (
	"fmt"
	. "launchpad.net/gocheck"
	"launchpad.net/goyaml"
	"math"
	"strconv"
	"strings"
)

var marshalIntTest = 123

var marshalTests = []struct {
	data  string
	value interface{}
}{
	{"{}\n", &struct{}{}},
	{"v: hi\n", map[string]string{"v": "hi"}},
	{"v: hi\n", map[string]interface{}{"v": "hi"}},
	{"v: \"true\"\n", map[string]string{"v": "true"}},
	{"v: \"false\"\n", map[string]string{"v": "false"}},
	{"v: true\n", map[string]interface{}{"v": true}},
	{"v: false\n", map[string]interface{}{"v": false}},
	{"v: 10\n", map[string]interface{}{"v": 10}},
	{"v: -10\n", map[string]interface{}{"v": -10}},
	{"v: 42\n", map[string]uint{"v": 42}},
	{"v: 4294967296\n", map[string]interface{}{"v": int64(4294967296)}},
	{"v: 4294967296\n", map[string]int64{"v": int64(4294967296)}},
	{"v: 4294967296\n", map[string]uint64{"v": 4294967296}},
	{"v: \"10\"\n", map[string]interface{}{"v": "10"}},
	{"v: 0.1\n", map[string]interface{}{"v": 0.1}},
	{"v: 0.1\n", map[string]interface{}{"v": float64(0.1)}},
	{"v: -0.1\n", map[string]interface{}{"v": -0.1}},
	{"v: .inf\n", map[string]interface{}{"v": math.Inf(+1)}},
	{"v: -.inf\n", map[string]interface{}{"v": math.Inf(-1)}},
	{"v: .nan\n", map[string]interface{}{"v": math.NaN()}},
	{"v: null\n", map[string]interface{}{"v": nil}},
	{"v: \"\"\n", map[string]interface{}{"v": ""}},
	{"v:\n- A\n- B\n", map[string][]string{"v": []string{"A", "B"}}},
	{"v:\n- A\n- 1\n", map[string][]interface{}{"v": []interface{}{"A", 1}}},
	{"a:\n  b: c\n",
		map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}},

	// Simple values.
	{"123\n", &marshalIntTest},

	// Structures
	{"hello: world\n", &struct{ Hello string }{"world"}},
	{"a:\n  b: c\n", &struct {
		A struct {
			B string
		}
	}{struct{ B string }{"c"}}},
	{"a:\n  b: c\n", &struct {
		A *struct {
			B string
		}
	}{&struct{ B string }{"c"}}},
	{"a: null\n", &struct {
		A *struct {
			B string
		}
	}{}},
	{"a: 1\n", &struct{ A int }{1}},
	{"a:\n- 1\n- 2\n", &struct{ A []int }{[]int{1, 2}}},
	{"a: 1\n", &struct {
		B int "a"
	}{1}},
	{"a: true\n", &struct{ A bool }{true}},

	// Conditional flag
	{"a: 1\n", &struct {
		A int "a,omitempty"
		B int "b,omitempty"
	}{1, 0}},
	{"{}\n", &struct {
		A int "a,omitempty"
		B int "b,omitempty"
	}{0, 0}},
	{"{}\n", &struct {
		A *struct{ X int } "a,omitempty"
		B int              "b,omitempty"
	}{nil, 0}},

	// Flow flag
	{"a: [1, 2]\n", &struct {
		A []int "a,flow"
	}{[]int{1, 2}}},
	{"a: {b: c}\n",
		&struct {
			A map[string]string "a,flow"
		}{map[string]string{"b": "c"}}},
	{"a: {b: c}\n",
		&struct {
			A struct {
				B string
			} "a,flow"
		}{struct{ B string }{"c"}}},
}

func (s *S) TestMarshal(c *C) {
	for _, item := range marshalTests {
		data, err := goyaml.Marshal(item.value)
		c.Assert(err, IsNil)
		c.Assert(string(data), Equals, item.data)
	}
}

//var unmarshalErrorTests = []struct{data, error string}{
//    {"v: !!float 'error'", "Can't decode !!str 'error' as a !!float"},
//}
//
//func (s *S) TestUnmarshalErrors(c *C) {
//    for _, item := range unmarshalErrorTests {
//        var value interface{}
//        err := goyaml.Unmarshal([]byte(item.data), &value)
//        c.Assert(err, Matches, item.error)
//    }
//}

var marshalTaggedIfaceTest interface{} = &struct{ A string }{"B"}

var getterTests = []struct {
	data, tag string
	value     interface{}
}{
	{"_:\n  hi: there\n", "", map[interface{}]interface{}{"hi": "there"}},
	{"_:\n- 1\n- A\n", "", []interface{}{1, "A"}},
	{"_: 10\n", "", 10},
	{"_: null\n", "", nil},
	{"_: !foo BAR!\n", "!foo", "BAR!"},
	{"_: !foo 1\n", "!foo", "1"},
	{"_: !foo '\"1\"'\n", "!foo", "\"1\""},
	{"_: !foo 1.1\n", "!foo", 1.1},
	{"_: !foo 1\n", "!foo", 1},
	{"_: !foo 1\n", "!foo", uint(1)},
	{"_: !foo true\n", "!foo", true},
	{"_: !foo\n- A\n- B\n", "!foo", []string{"A", "B"}},
	{"_: !foo\n  A: B\n", "!foo", map[string]string{"A": "B"}},
	{"_: !foo\n  a: B\n", "!foo", &marshalTaggedIfaceTest},
}

type typeWithGetter struct {
	tag   string
	value interface{}
}

func (o typeWithGetter) GetYAML() (tag string, value interface{}) {
	return o.tag, o.value
}

type typeWithGetterField struct {
	Field typeWithGetter "_"
}

func (s *S) TestMashalWithGetter(c *C) {
	for _, item := range getterTests {
		obj := &typeWithGetterField{}
		obj.Field.tag = item.tag
		obj.Field.value = item.value
		data, err := goyaml.Marshal(obj)
		c.Assert(err, IsNil)
		c.Assert(string(data), Equals, string(item.data))
	}
}

func (s *S) TestUnmarshalWholeDocumentWithGetter(c *C) {
	obj := &typeWithGetter{}
	obj.tag = ""
	obj.value = map[string]string{"hello": "world!"}
	data, err := goyaml.Marshal(obj)
	c.Assert(err, IsNil)
	c.Assert(string(data), Equals, "hello: world!\n")
}

func (s *S) TestSortedOutput(c *C) {
	order := []interface{}{
		false,
		true,
		1,
		uint(1),
		1.0,
		1.1,
		1.2,
		2,
		uint(2),
		2.0,
		2.1,
		"",
		".1",
		".2",
		".a",
		"1",
		"2",
		"a!10",
		"a/2",
		"a/10",
		"a~10",
		"ab/1",
		"b/1",
		"b/01",
		"b/2",
		"b/02",
		"b/3",
		"b/03",
		"b1",
		"b01",
		"b3",
		"c2.10",
		"c10.2",
		"d1",
		"d12",
		"d12a",
	}
	m := make(map[interface{}]int)
	for _, k := range order {
		m[k] = 1
	}
	data, err := goyaml.Marshal(m)
	c.Assert(err, IsNil)
	out := "\n" + string(data)
	last := 0
	for i, k := range order {
		repr := fmt.Sprint(k)
		if s, ok := k.(string); ok {
			if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
				repr = `"` + repr + `"`
			}
		}
		index := strings.Index(out, "\n"+repr+":")
		if index == -1 {
			c.Fatalf("%#v is not in the output: %#v", k, out)
		}
		if index < last {
			c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
		}
		last = index
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	//	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/codegangsta/cli"
	//"github.com/fatih/color"
	"github.com/joho/godotenv"
)

var (
	/*
	 * This map stores some useful global environment variables used
	 * internally by the logic of the tool (we avoid to clutter the source
	 * code with redundant calls to pkg/os functions).
	 */
	ENV = map[string]string{
		"PWD":  "",
		"HOME": "",
	}

	/*
	 * This map stores all the environment variables used by the todo.txt CLI
	 */
	TODOENV = map[string]string{
		"TODO_DIR":             "",
		"TODO_FILE":            "",
		"DONE_FILE":            "",
		"REPORT_FILE":          "",
		"TODO_ACTIONS_DIR":     "",
		"TODOTXT_SORT_COMMAND": "",
		"TODOTXT_FINAL_FILTER": "",
	}

	/* This slice defines all the possible paths for the configuration files.
	 * The slice defines also the exact order at which the conf files should be
	 * loaded by the godotenv library.
	 *
	 * $HOME/todo.cfg
	 * $HOME/.todo.cfg
	 * ./todo.cfg
	 * /etc/todo/config
	 */
	// TODO: transform the slice into a map[string]bool where the boolean value defines if the config file exists
	CFG = []string{
		"$HOME/todo.cfg",
		"$HOME/.todo.cfg",
		"./todo.cfg",
		"/etc/todo/config"}
)

// TODO: this is an ugly and hackish error handler that needs to be improved
func check(e error) {
	if e != nil {
		fmt.Errorf("%v", e)
		panic(e)
	}
}

// Exists returns true if the given path exists.
func Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// Adds a task to a todo.txt file.
func addAction(task string) {
	// TODO: TODOENV["TODO_FILE"] path should be validated somehow
	// before to be stated by os.OpenFile
	//path.Clean(TODOENV["TODO_FILE"])

	// determine the number of tasks in todo.txt
	// TODO: with NewReadWriter the code should be more compact
	//       buf := bufio.NewReadWriter(bufio.NewReader(r), bufio.NewWriter(w))
	fd, err := os.OpenFile(TODOENV["TODO_FILE"], os.O_RDONLY|os.O_CREATE, 0600)
	check(err)
	scanner := bufio.NewScanner(fd)
	ntasks := 1
	for scanner.Scan() {
		ntasks++
	}
	if err := scanner.Err(); err != nil {
		fd.Close()
		check(err)
	}
	//fmt.Printf("n. lines: %d\n", ntasks)
	err = fd.Close()
	check(err)

	// Open todo.txt in append mode only
	fd, err = os.OpenFile(TODOENV["TODO_FILE"], os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	check(err)
	defer fd.Close()

	// use buffered I/O
	writer := bufio.NewWriter(fd)

	// add the task to todo.txt
	_, err = writer.WriteString(task + "\n")
	check(err)
	err = writer.Flush()
	check(err)

	// print summary
	fmt.Printf("%d: %s\n", ntasks, task)
	fmt.Printf("TODO: %d added\n", ntasks)
}

// Create a todo.txt structure at the specified location (default destination is ".")
func initAction(destination string) {

	var (
		FileName = map[string]string{
			"cfg":    "/todo.cfg",
			"todo":   "/todo.txt",
			"done":   "/done.txt",
			"report": "/report.txt",
		}

		FileTemplate = map[string]string{
			"cfg": `
# === EDIT FILE LOCATIONS BELOW ===

# Your todo.txt directory
#export TODO_DIR="$HOME/todo"
export TODO_DIR="."

# Your todo/done/report.txt locations
export TODO_FILE="$TODO_DIR/todo.txt"
export DONE_FILE="$TODO_DIR/done.txt"
export REPORT_FILE="$TODO_DIR/report.txt"

# You can customize your actions directory location
#export TODO_ACTIONS_DIR="$HOME/.todo.actions.d"`,
			"todo":   "",
			"done":   "",
			"report": "",
		}

		initiated = false
		message   = "Initialized a new"
	)

	// try to guess if the destination is an existing and
	// pre-configured todo.txt structure.
	for _, filename := range FileName {
		// sanitize the absolute path of the file
		filePath, err := filepath.Abs(destination + filename)
		//fmt.Printf("absolute path: %s\n", cfgFilePath)
		check(err)

		ret, _ := Exists(filePath)
		if ret {
			initiated = true
			break
		}
	}

	// if the destination is an existing todo.txt structure then
	// change the message accordingly
	if initiated {
		message = "Reinitialized an existing"
	}

	// sanitize the absolute path of the destination
	filePath, err := filepath.Abs(destination)
	check(err)

	// print first line of the action's summary
	fmt.Printf("%s todo.txt structure in %s\n", message, filePath)

	// create the missing files of the todo.txt structure
	for k, filename := range FileName {
		// sanitize the absolute path of the file
		filePath, err := filepath.Abs(destination + FileName[k])
		check(err)
		//fmt.Printf("absolute path: %s\n", filePath)

		// Open file
		file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
		defer file.Close()

		// if there aren't errors, write a new file with default values
		if err == nil {
			size, err := file.WriteString(FileTemplate[k])
			check(err)

			// sync / flush file
			file.Sync()

			// print a small summary
			fmt.Printf("%s [%s] (%d bytes)\n", filename, "new", size)
			continue
		}

		// file exists, there is nothing to write
		if os.IsExist(err) {
			// print a small summary
			fmt.Printf("%s [%s]\n", filename, "exists")
			continue
		}
	}
}

func main() {

	// Retrieve environment variables $HOME and $PWD
	pwd, err := os.Getwd()
	check(err)
	ENV["HOME"] = os.Getenv("HOME")
	ENV["PWD"] = pwd

	// Expand $HOME var inside CFG slice
	if ENV["HOME"] != "" {
		// $HOME isn't empty, we expand $HOME for CFG[0] and CFG[1]
		CFG[0] = strings.Replace(CFG[0], "$HOME", ENV["HOME"], -1)
		CFG[1] = strings.Replace(CFG[1], "$HOME", ENV["HOME"], -1)
	} else {
		// $HOME is empty, we unset CFG[0] and CFG[1]
		CFG[0] = ""
		CFG[1] = ""
	}

	// Load environment variables from all the configuration files
	// specified in the slice 'CFG'
	for _, filepath := range CFG {
		if filepath != "" {
			ret, err := Exists(filepath)
			check(err)
			//fmt.Printf("checking: %s (%t) \n", filepath, ret)

			// if the conf file exists, load it with godotenv
			if ret {
				err := godotenv.Load(filepath)
				check(err)
			}
		}
	}

	// Populate TODOENV map with environment variables
	for k, _ := range TODOENV {
		TODOENV[k] = os.Getenv(k)
	}
	//fmt.Println("map:", TODOENV)

	// Sanitize TODOENV map by expanding bash variables
	for k, v := range TODOENV {
		// expand $HOME var
		v = strings.Replace(v, "$HOME", ENV["HOME"], -1)
		v = strings.Replace(v, "${HOME}", ENV["HOME"], -1)

		// Expand $TODO_DIR var
		v = strings.Replace(v, "$TODO_DIR", TODOENV["TODO_DIR"], -1)
		v = strings.Replace(v, "${TODO_DIR}", TODOENV["TODO_DIR"], -1)

		// save the sanitized value
		TODOENV[k] = v
	}

	envCommand := cli.Command{
		Name:        "env",
		Usage:       "Print `todo` environment information",
		Description: "By default env prints information as a shell script.\n   The environment info will be dumped in straight-forward\n   form suitable for sourcing into a shell script.\n\n   If one or more variable names is given as arguments, env\n   prints the value of each named variable on its own line.",
		Action: func(c *cli.Context) {
			// collect all the user-submitted arguments in an array
			args := c.Args()

			// debugging
			/*fmt.Printf("pwd: %s\n", pwd)
			fmt.Printf("HOME=\"%s\"\n", ENV["HOME"])*/

			switch args.Present() {
			case true:
				// print only the required environment variables
				for _, arg := range args {
					fmt.Printf("%s=\"%s\"\n", arg, TODOENV[arg])
				}
			case false:
				// print all the environment variables
				for k, v := range TODOENV {
					fmt.Printf("%s=\"%s\"\n", k, v)
				}
			}
		},
	}

	initCommand := cli.Command{
		Name:  "init",
		Usage: "Initialize a new todo.txt structure with default values",
		Description: `
   This command creates all the template file required by the todo.txt and
   a configuration files with default values - basically, the values TODO_DIR,
   TODO_FILE, DONE_FILE, REPORT_FILE and TODO_ACTIONS_DIR are exported.

   If the option '--dest' is set then it specifies a path to use instead of
   the working directory as the destination path for the new structure.

   Running 'todo init' in a pre-initialized directory is safe; it will not
   overwrite things that are already there.`,
		Flags: []cli.Flag{
			cli.StringFlag{"dest, d", "/path/to/your/dir", "specifies a different destination path"},
		},
		Action: func(c *cli.Context) {
			destination := "."
			if c.IsSet("dest") {
				//fmt.Println("dest:", c.String("dest"))
				destination = c.String("dest")
			}
			initAction(destination)
		},
	}

	shorthelpCommand := cli.Command{
		Name:  "shorthelp",
		Usage: "Show a usage message briefly summarizing all commands (a synonym for -h)",
		Description: `
   This command prints a summary of the command-line usage of 'todo' and all its
   add-ons, then exit.

   The 'shorthelp' command is supported only for backward-compatibility with the
   original Todo.txt CLI from Gina Trapani, and falls back on the standard
   help command.

   You should use the POSIX-compliant option 'help, -h' instead.
`,
		Action: func(c *cli.Context) {
			cli.ShowAppHelp(c)
		},
	}

	addCommand := cli.Command{
		Name:      "add",
		ShortName: "a",
		Usage:     "Add a task to your todo.txt file",
		Description: `
   This command can be used to add the specified task to your todo.txt file on
   its own line.

   Project and content notation is optional. Quotes are optional too.

EXAMPLES

   Adds a simple task (quotes are optional):

      $ todo add "Move out cardboard boxes from the garage"

   Adds tasks with a project notation (quotes are optional):

      $ todo add "Move out cardboard boxes from the garage +cleaning"
      $ todo add "Do a load of laundry +cleaning"
      $ todo add "Vacuum the house +cleaning"

   Adds tasks with a context notation (quotes are optional):

      $ todo add "Buy eggs and milk @grocery"
      $ todo add "Buy a cake for friday's dinner party with friends @backery"

   Adds tasks with both project and context notation (quotes are optional):

      $ todo add "Feed the kitten +BellyOfTheBeast"
      $ todo add "Buy food with amino acid taurine @petshop +BellyOfTheBeast"
      $ todo add "Buy huge amont of meat @butcher +BellyOfTheBeast"
      $ todo add "Hire a bouncer to protect @kitchen cupboard from the cat +BellyOfTheBeast"
`,
		Action: func(c *cli.Context) {
			// collect all the user-submitted arguments in an array
			args := c.Args()

			// debugging
			fmt.Printf("(add::Action) args (%d): %s\n", len(args), args)
			fmt.Printf("(add::Action) global flag: %s (%t)\n", "-t", c.GlobalBool("t"))

			// check incorrect usage of the command
			switch {
			case len(args) == 0: // no options specified
				fmt.Print("\nIncorrect Usage: missing option with command \"add [task]\"\n\n")
				cli.ShowCommandHelp(c, "add")
				return
			}

			// TODO: validating input as a task

			/* task mangler
			 * - collect all the arguments into a single string
			 * - replace return carriage chars with spaces
			 * - trim the task from leading / ending spaces
			 * - honor the -t/-T global flag if present
			 */
			task := strings.Join(args[0:], " ")
			r := strings.NewReplacer("\n", " ", "\t", " ", "\r", " ")
			task = r.Replace(task)
			task = strings.TrimSpace(task)

			if c.GlobalBool("t") {
				date := time.Now().Format("2006-01-02 ")
				//fmt.Printf("(add::Action) date: %s\n", date)
				task = date + task
			}

			// save the new task
			//fmt.Printf("task: |%s|\n", task)
			addAction(task)
		},
	}

	// Initialize the app CLI
	app := cli.NewApp()
	app.Name = "go-todo"
	app.Usage = "A simple and extensible utility for managing your todo.txt files"
	app.Version = "1.0.0"
	app.Author = "Mauro Toffanin"
	app.Email = "toffanin.mauro@gmail.com"
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{
		cli.BoolFlag{"t", "Prepend the current date to a task automatically when it's added"},
		cli.BoolFlag{"T", "Do not prepend the current date to a task automatically when it's added."},
	}
	app.Commands = []cli.Command{
		envCommand,
		initCommand,
		shorthelpCommand,
		addCommand,
		/*{
			Name:  "status",
			Usage: "Obtain a summary of the todo.txt structure",
			Flags: []cli.Flag{
				cli.StringFlag{"dest, d", "", "specifies a different destination path"},
			},
			Action: func(c *cli.Context) {
				//fmt.Println("status: ", c.Args().First())
			},
		},*/
	}
	err = app.Run(os.Args)
	check(err)
}
<commit_msg>small fix<commit_after>package main

import (
	"bufio"
	//	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/codegangsta/cli"
	//"github.com/fatih/color"
	"github.com/joho/godotenv"
)

var (
	/*
	 * This map stores some useful global environment variables used
	 * internally by the logic of the tool (we avoid to clutter the source
	 * code with redundant calls to pkg/os functions).
	 */
	ENV = map[string]string{
		"PWD":  "",
		"HOME": "",
	}

	/*
	 * This map stores all the environment variables used by the todo.txt CLI
	 */
	TODOENV = map[string]string{
		"TODO_DIR":             "",
		"TODO_FILE":            "",
		"DONE_FILE":            "",
		"REPORT_FILE":          "",
		"TODO_ACTIONS_DIR":     "",
		"TODOTXT_SORT_COMMAND": "",
		"TODOTXT_FINAL_FILTER": "",
	}

	/* This slice defines all the possible paths for the configuration files.
	 * The slice defines also the exact order at which the conf files should be
	 * loaded by the godotenv library.
	 *
	 * $HOME/todo.cfg
	 * $HOME/.todo.cfg
	 * ./todo.cfg
	 * /etc/todo/config
	 */
	// TODO: transform the slice into a map[string]bool where the boolean value defines if the config file exists
	CFG = []string{
		"$HOME/todo.cfg",
		"$HOME/.todo.cfg",
		"./todo.cfg",
		"/etc/todo/config"}
)

// TODO: this is an ugly and hackish error handler that needs to be improved
func check(e error) {
	if e != nil {
		fmt.Errorf("%v", e)
		panic(e)
	}
}

// Exists returns true if the given path exists.
func Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// Adds a task to a todo.txt file.
func addAction(task string) {
	// TODO: TODOENV["TODO_FILE"] path should be validated somehow
	// before to be stated by os.OpenFile
	//path.Clean(TODOENV["TODO_FILE"])

	// determine the number of tasks in todo.txt
	// TODO: with NewReadWriter the code should be more compact
	//       buf := bufio.NewReadWriter(bufio.NewReader(r), bufio.NewWriter(w))
	fd, err := os.OpenFile(TODOENV["TODO_FILE"], os.O_RDONLY|os.O_CREATE, 0600)
	check(err)
	scanner := bufio.NewScanner(fd)
	ntasks := 1
	for scanner.Scan() {
		ntasks++
	}
	if err := scanner.Err(); err != nil {
		fd.Close()
		check(err)
	}
	//fmt.Printf("n. lines: %d\n", ntasks)
	err = fd.Close()
	check(err)

	// Open todo.txt in append mode only
	fd, err = os.OpenFile(TODOENV["TODO_FILE"], os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	check(err)
	defer fd.Close()

	// use buffered I/O
	writer := bufio.NewWriter(fd)

	// add the task to todo.txt
	_, err = writer.WriteString(task + "\n")
	check(err)
	err = writer.Flush()
	check(err)

	// print summary
	fmt.Printf("%d: %s\n", ntasks, task)
	fmt.Printf("TODO: %d added\n", ntasks)
}

// Create a todo.txt structure at the specified location (default destination is ".")
func initAction(destination string) {

	var (
		FileName = map[string]string{
			"cfg":    "/todo.cfg",
			"todo":   "/todo.txt",
			"done":   "/done.txt",
			"report": "/report.txt",
		}

		FileTemplate = map[string]string{
			"cfg": `
# === EDIT FILE LOCATIONS BELOW ===

# Your todo.txt directory
#export TODO_DIR="$HOME/todo"
export TODO_DIR="."

# Your todo/done/report.txt locations
export TODO_FILE="$TODO_DIR/todo.txt"
export DONE_FILE="$TODO_DIR/done.txt"
export REPORT_FILE="$TODO_DIR/report.txt"

# You can customize your actions directory location
#export TODO_ACTIONS_DIR="$HOME/.todo.actions.d"`,
			"todo":   "",
			"done":   "",
			"report": "",
		}

		initiated = false
		message   = "Initialized a new"
	)

	// try to guess if the destination is an existing and
	// pre-configured todo.txt structure.
	for _, filename := range FileName {
		// sanitize the absolute path of the file
		filePath, err := filepath.Abs(destination + filename)
		//fmt.Printf("absolute path: %s\n", cfgFilePath)
		check(err)

		ret, _ := Exists(filePath)
		if ret {
			initiated = true
			break
		}
	}

	// if the destination is an existing todo.txt structure then
	// change the message accordingly
	if initiated {
		message = "Reinitialized an existing"
	}

	// sanitize the absolute path of the destination
	filePath, err := filepath.Abs(destination)
	check(err)

	// print first line of the action's summary
	fmt.Printf("%s todo.txt structure in %s\n", message, filePath)

	// create the missing files of the todo.txt structure
	for k, filename := range FileName {
		// sanitize the absolute path of the file
		filePath, err := filepath.Abs(destination + FileName[k])
		check(err)
		//fmt.Printf("absolute path: %s\n", filePath)

		// Open file
		file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
		defer file.Close()

		// if there aren't errors, write a new file with default values
		if err == nil {
			size, err := file.WriteString(FileTemplate[k])
			check(err)

			// sync / flush file
			file.Sync()

			// print a small summary
			fmt.Printf("%s [%s] (%d bytes)\n", filename, "new", size)
			continue
		}

		// file exists, there is nothing to write
		if os.IsExist(err) {
			// print a small summary
			fmt.Printf("%s [%s]\n", filename, "exists")
			continue
		}
	}
}

func main() {

	// Retrieve environment variables $HOME and $PWD
	pwd, err := os.Getwd()
	check(err)
	ENV["HOME"] = os.Getenv("HOME")
	ENV["PWD"] = pwd

	// Expand $HOME var inside CFG slice
	if ENV["HOME"] != "" {
		// $HOME isn't empty, we expand $HOME for CFG[0] and CFG[1]
		CFG[0] = strings.Replace(CFG[0], "$HOME", ENV["HOME"], -1)
		CFG[1] = strings.Replace(CFG[1], "$HOME", ENV["HOME"], -1)
	} else {
		// $HOME is empty, we unset CFG[0] and CFG[1]
		CFG[0] = ""
		CFG[1] = ""
	}

	// Load environment variables from all the configuration files
	// specified in the slice 'CFG'
	for _, filepath := range CFG {
		if filepath != "" {
			ret, err := Exists(filepath)
			check(err)
			//fmt.Printf("checking: %s (%t) \n", filepath, ret)

			// if the conf file exists, load it with godotenv
			if ret {
				err := godotenv.Load(filepath)
				check(err)
			}
		}
	}

	// Populate TODOENV map with environment variables
	for k := range TODOENV {
		TODOENV[k] = os.Getenv(k)
	}
	//fmt.Println("map:", TODOENV)

	// Sanitize TODOENV map by expanding bash variables
	for k, v := range TODOENV {
		// expand $HOME var
		v = strings.Replace(v, "$HOME", ENV["HOME"], -1)
		v = strings.Replace(v, "${HOME}", ENV["HOME"], -1)

		// Expand $TODO_DIR var
		v = strings.Replace(v, "$TODO_DIR", TODOENV["TODO_DIR"], -1)
		v = strings.Replace(v, "${TODO_DIR}", TODOENV["TODO_DIR"], -1)

		// save the sanitized value
		TODOENV[k] = v
	}

	envCommand := cli.Command{
		Name:        "env",
		Usage:       "Print `todo` environment information",
		Description: "By default env prints information as a shell script.\n   The environment info will be dumped in straight-forward\n   form suitable for sourcing into a shell script.\n\n   If one or more variable names is given as arguments, env\n   prints the value of each named variable on its own line.",
		Action: func(c *cli.Context) {
			// collect all the user-submitted arguments in an array
			args := c.Args()

			// debugging
			/*fmt.Printf("pwd: %s\n", pwd)
			fmt.Printf("HOME=\"%s\"\n", ENV["HOME"])*/

			switch args.Present() {
			case true:
				// print only the required environment variables
				for _, arg := range args {
					fmt.Printf("%s=\"%s\"\n", arg, TODOENV[arg])
				}
			case false:
				// print all the environment variables
				for k, v := range TODOENV {
					fmt.Printf("%s=\"%s\"\n", k, v)
				}
			}
		},
	}

	initCommand := cli.Command{
		Name:  "init",
		Usage: "Initialize a new todo.txt structure with default values",
		Description: `
   This command creates all the template file required by the todo.txt and
   a configuration files with default values - basically, the values TODO_DIR,
   TODO_FILE, DONE_FILE, REPORT_FILE and TODO_ACTIONS_DIR are exported.

   If the option '--dest' is set then it specifies a path to use instead of
   the working directory as the destination path for the new structure.

   Running 'todo init' in a pre-initialized directory is safe; it will not
   overwrite things that are already there.`,
		Flags: []cli.Flag{
			cli.StringFlag{"dest, d", "/path/to/your/dir", "specifies a different destination path"},
		},
		Action: func(c *cli.Context) {
			destination := "."
			if c.IsSet("dest") {
				//fmt.Println("dest:", c.String("dest"))
				destination = c.String("dest")
			}
			initAction(destination)
		},
	}

	shorthelpCommand := cli.Command{
		Name:  "shorthelp",
		Usage: "Show a usage message briefly summarizing all commands (a synonym for -h)",
		Description: `
   This command prints a summary of the command-line usage of 'todo' and all its
   add-ons, then exit.

   The 'shorthelp' command is supported only for backward-compatibility with the
   original Todo.txt CLI from Gina Trapani, and falls back on the standard
   help command.

   You should use the POSIX-compliant option 'help, -h' instead.
`,
		Action: func(c *cli.Context) {
			cli.ShowAppHelp(c)
		},
	}

	addCommand := cli.Command{
		Name:      "add",
		ShortName: "a",
		Usage:     "Add a task to your todo.txt file",
		Description: `
   This command can be used to add the specified task to your todo.txt file on
   its own line.

   Project and content notation is optional. Quotes are optional too.

EXAMPLES

   Adds a simple task (quotes are optional):

      $ todo add "Move out cardboard boxes from the garage"

   Adds tasks with a project notation (quotes are optional):

      $ todo add "Move out cardboard boxes from the garage +cleaning"
      $ todo add "Do a load of laundry +cleaning"
      $ todo add "Vacuum the house +cleaning"

   Adds tasks with a context notation (quotes are optional):

      $ todo add "Buy eggs and milk @grocery"
      $ todo add "Buy a cake for friday's dinner party with friends @backery"

   Adds tasks with both project and context notation (quotes are optional):

      $ todo add "Feed the kitten +BellyOfTheBeast"
      $ todo add "Buy food with amino acid taurine @petshop +BellyOfTheBeast"
      $ todo add "Buy huge amont of meat @butcher +BellyOfTheBeast"
      $ todo add "Hire a bouncer to protect @kitchen cupboard from the cat +BellyOfTheBeast"
`,
		Action: func(c *cli.Context) {
			// collect all the user-submitted arguments in an array
			args := c.Args()

			// debugging
			fmt.Printf("(add::Action) args (%d): %s\n", len(args), args)
			fmt.Printf("(add::Action) global flag: %s (%t)\n", "-t", c.GlobalBool("t"))

			// check incorrect usage of the command
			switch {
			case len(args) == 0: // no options specified
				fmt.Print("\nIncorrect Usage: missing option with command \"add [task]\"\n\n")
				cli.ShowCommandHelp(c, "add")
				return
			}

			// TODO: validating input as a task

			/* task mangler
			 * - collect all the arguments into a single string
			 * - replace return carriage chars with spaces
			 * - trim the task from leading / ending spaces
			 * - honor the -t/-T global flag if present
			 */
			task := strings.Join(args[0:], " ")
			r := strings.NewReplacer("\n", " ", "\t", " ", "\r", " ")
			task = r.Replace(task)
			task = strings.TrimSpace(task)

			if c.GlobalBool("t") {
				date := time.Now().Format("2006-01-02 ")
				//fmt.Printf("(add::Action) date: %s\n", date)
				task = date + task
			}

			// save the new task
			//fmt.Printf("task: |%s|\n", task)
			addAction(task)
		},
	}

	// Initialize the app CLI
	app := cli.NewApp()
	app.Name = "go-todo"
	app.Usage = "A simple and extensible utility for managing your todo.txt files"
	app.Version = "1.0.0"
	app.Author = "Mauro Toffanin"
	app.Email = "toffanin.mauro@gmail.com"
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{
		cli.BoolFlag{"t", "Prepend the current date to a task automatically when it's added"},
		cli.BoolFlag{"T", "Do not prepend the current date to a task automatically when it's added."},
	}
	app.Commands = []cli.Command{
		envCommand,
		initCommand,
		shorthelpCommand,
		addCommand,
		/*{
			Name:  "status",
			Usage: "Obtain a summary of the todo.txt structure",
			Flags: []cli.Flag{
				cli.StringFlag{"dest, d", "", "specifies a different destination path"},
			},
			Action: func(c *cli.Context) {
				//fmt.Println("status: ", c.Args().First())
			},
		},*/
	}
	err = app.Run(os.Args)
	check(err)
}
<|endoftext|>


<commit_before>package hub

import (
	"os"

	"github.com/streadway/amqp"
)

type Stream struct {
	AmqpUri   string `json:"amqp_uri"`
	QueueName string `json:"queue_name"`
}

func (s *Stream) Consume() error {
	conn, err := amqp.Dial(s.AmqpUri)
	defer conn.Close()

	if err != nil {
		return err
	}

	channel, err := conn.Channel()
	defer channel.Close()

	if err != nil {
		return err
	}

	q, err := channel.QueueDeclare(
		s.QueueName, // name
		false,       // durable
		true,        // delete when unused
		false,       // exclusive
		false,       // no-wait
		nil,         // arguments
	)

	if err != nil {
		return err
	}

	msgs, err := channel.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)

	if err != nil {
		return err
	}

	forever := make(chan bool)

	go func() {
		for d := range msgs {
			os.Stdout.Write(d.Body)
		}
	}()

	<-forever

	return nil
}
<commit_msg>bugfix: End stream<commit_after>package hub

import (
	"os"

	"github.com/streadway/amqp"
)

type Stream struct {
	AmqpUri   string `json:"amqp_uri"`
	QueueName string `json:"queue_name"`
}

func (s *Stream) Consume() error {
	conn, err := amqp.Dial(s.AmqpUri)
	defer conn.Close()

	if err != nil {
		return err
	}

	channel, err := conn.Channel()
	defer channel.Close()

	if err != nil {
		return err
	}

	q, err := channel.QueueDeclare(
		s.QueueName, // name
		false,       // durable
		true,        // delete when unused
		false,       // exclusive
		false,       // no-wait
		nil,         // arguments
	)

	if err != nil {
		return err
	}

	msgs, err := channel.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)

	if err != nil {
		return err
	}

	forever := make(chan bool)

	go func() {
		for d := range msgs {
			if string(d.Body) == "kthxbai"{
				forever <- true
				return
			}
			os.Stdout.Write(d.Body)
		}
	}()

	<-forever
	conn.Close()

	return nil
}
<|endoftext|>


<commit_before>/* httpstress is a library for HTTP stress testing.
It launches one goroutine per concurrent connection and does not count successful attempts.

A CLI utility is avaliable at github.com/chillum/httpstress-go */
package httpstress

/* Copyright 2014 Chai Chillum

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. */

import (
	"errors"
	"net/http"
	"regexp"
)

// Library version
const Version = "1.1"

/* httpstress.Test launches {conn} goroutines to fetch HTTP/HTTPS locations in {urls} list.
If {max} is more than {conn}, more goroutines will spawn as other are finished,
resulting in {max} queries (but no more than {conn} in every moment).
Returns map: {url}/{failed} or error (failed URL message). Example:

	urls := []string{"https://google.com", "http://localhost"}

	out, err := httpstress.Test(2, 4, urls) // Makes 4 HTTP requests total, 2 concurrent.

	if err != nil {
		// Invalid arguments
	} else {
		if len(out) == 0 {
			// No failed requests.
		} else {
			// Process failed requests.
			for url, num := range out {
				log.Println(url, "failed", num, "times.")
			}
		}
	} */
func Test(conn int, max int, urls []string) (results map[string]int, err error) {
	for _, i := range urls {
		if m, _ := regexp.MatchString("^https?://", i); !m {
			err = errors.New("Not a HTTP/HTTPS URL: " + i)
			return
		}
	}

	results = make(map[string]int)
	failures := make(chan string)
	finished := make(chan bool)
	total := len(urls) - 1
	trans := &http.Transport{MaxIdleConnsPerHost: conn} // Use persistent connections.
	client := &http.Client{Transport: trans}
	n := 0
	i := 0

	go logger(failures, results)
	for ; i < conn; i++ { // Launch initial workers.
		go worker(&urls[n], failures, finished, client)

		if n < total {
			n++
		} else {
			n = 0
		}
	}
	for ; i < max; i++ { // Launch more workers as initial finish.
		if <-finished {
			go worker(&urls[n], failures, finished, client)

			if n < total {
				n++
			} else {
				n = 0
			}
		}
	}
	for i := 0; i < conn; i++ { // Wait for active workers.
		<-finished
	}
	return
}

func logger(failures <-chan string, results map[string]int) {
	for {
		select {
		case url := <-failures:
			results[url]++
		}
	}
}

func worker(url *string, failures chan<- string, finished chan<- bool, client *http.Client) {
	resp, err := client.Get(*url)
	if err != nil {
		failures <- *url
	}
	if resp != nil {
		resp.Body.Close()
	}
	finished <- true
}
<commit_msg>godoc fixes<commit_after>/* httpstress is a library for HTTP stress testing

It launches one goroutine per concurrent connection and does not count successful attempts.

A CLI utility is avaliable at github.com/chillum/httpstress-go */
package httpstress

/* Copyright 2014 Chai Chillum

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. */

import (
	"errors"
	"net/http"
	"regexp"
)

// Library version
const Version = "1.1"

/* httpstress.Test launches {conn} goroutines to fetch HTTP/HTTPS locations in {urls} list

If {max} is more than {conn}, more goroutines will spawn as other are finished,
resulting in {max} queries (but no more than {conn} in every moment).
Returns map: {url}, {fail count} or error (failed URL message). Example:

	urls := []string{"https://google.com", "http://localhost"}

	out, err := httpstress.Test(2, 4, urls) // Makes 4 HTTP requests total, 2 concurrent.

	if err != nil {
		// Invalid arguments.
	} else {
		if len(out) == 0 {
			// No failed requests.
		} else {
			// Process failed requests.
			for url, num := range out {
				log.Println(url, "failed", num, "times.")
			}
		}
	} */
func Test(conn int, max int, urls []string) (results map[string]int, err error) {
	for _, i := range urls {
		if m, _ := regexp.MatchString("^https?://", i); !m {
			err = errors.New("Not a HTTP/HTTPS URL: " + i)
			return
		}
	}

	results = make(map[string]int)
	failures := make(chan string)
	finished := make(chan bool)
	total := len(urls) - 1
	trans := &http.Transport{MaxIdleConnsPerHost: conn} // Use persistent connections.
	client := &http.Client{Transport: trans}
	n := 0
	i := 0

	go logger(failures, results)
	for ; i < conn; i++ { // Launch initial workers.
		go worker(&urls[n], failures, finished, client)

		if n < total {
			n++
		} else {
			n = 0
		}
	}
	for ; i < max; i++ { // Launch more workers as initial finish.
		if <-finished {
			go worker(&urls[n], failures, finished, client)

			if n < total {
				n++
			} else {
				n = 0
			}
		}
	}
	for i := 0; i < conn; i++ { // Wait for active workers.
		<-finished
	}
	return
}

func logger(failures <-chan string, results map[string]int) {
	for {
		select {
		case url := <-failures:
			results[url]++
		}
	}
}

func worker(url *string, failures chan<- string, finished chan<- bool, client *http.Client) {
	resp, err := client.Get(*url)
	if err != nil {
		failures <- *url
	}
	if resp != nil {
		resp.Body.Close()
	}
	finished <- true
}
<|endoftext|>


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

package zk

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"golang.org/x/net/context"

	log "github.com/golang/glog"
	zookeeper "github.com/samuel/go-zookeeper/zk"

	"github.com/youtube/vitess/go/netutil"
	"github.com/youtube/vitess/go/sync2"
)

// Time returns a time.Time from a ZK int64 milliseconds since Epoch time.
func Time(i int64) time.Time {
	return time.Unix(i/1000, i%1000*1000000)
}

// ZkTime returns a ZK time (int64) from a time.Time
func ZkTime(t time.Time) int64 {
	return t.Unix()*1000 + int64(t.Nanosecond()/1000000)
}

// Every blocking call into CGO causes another thread which blows up
// the virtual memory.  It seems better to solve this here at the
// root of the problem rather than forcing all other apps to take into
// account limiting the number of concurrent operations on a zk
// connection.  Since this applies to any zookeeper connection, this
// is global.
var sem *sync2.Semaphore

// ErrConnectionClosed is returned if we try to access a closed connection.
var ErrConnectionClosed = errors.New("ZkConn: connection is closed")

func init() {
	// The zookeeper C module logs quite a bit of useful information,
	// but much of it does not come back in the error API. To aid
	// debugging, enable the log to stderr for warnings.
	//zookeeper.SetLogLevel(zookeeper.LOG_WARN)

	maxConcurrency := 64
	x := os.Getenv("ZK_CLIENT_MAX_CONCURRENCY")
	if x != "" {
		var err error
		maxConcurrency, err = strconv.Atoi(x)
		if err != nil {
			log.Infof("invalid ZK_CLIENT_MAX_CONCURRENCY: %v", err)
		}
	}

	sem = sync2.NewSemaphore(maxConcurrency, 0)
}

// ZkConn is a client class that implements zk.Conn using a zookeeper.Conn.
// The conn member variable is protected by the mutex.
type ZkConn struct {
	mu   sync.Mutex
	conn *zookeeper.Conn
}

// getConn returns the connection in a thread safe way
func (conn *ZkConn) getConn() *zookeeper.Conn {
	conn.mu.Lock()
	defer conn.mu.Unlock()
	return conn.conn
}

// DialZk dials a ZK server and waits for connection event. Returns a ZkConn
// encapsulating the zookeeper.Conn, and the zookeeper session event
// channel to monitor the connection
//
// The value for baseTimeout is used as a session timeout as well, and
// will be used to negotiate a 'good' value with the server. From
// reading the zookeeper source code, it has to be between 6 and 60
// seconds (2x and 20x the tickTime by default, with default tick time
// being 3 seconds).  min session time, max session time and ticktime
// can all be overwritten on the zookeeper server side, so these
// numbers may vary.
//
// Then this baseTimeout is used to compute other related timeouts:
// - connect timeout is 1/3 of baseTimeout
// - recv timeout is 2/3 of baseTimeout minus a ping time
// - send timeout is 1/3 of baseTimeout
// - we try to send a ping a least every baseTimeout / 3
//
// Note the baseTimeout has *nothing* to do with the time between we
// call Dial and the maximum time before we receive the event on the
// session. The library will actually try to re-connect in the background
// (after each timeout), and may *never* send an event if the TCP connections
// always fail. Use DialZkTimeout to enforce a timeout for the initial connect.
func DialZk(zkAddr string, baseTimeout time.Duration) (*ZkConn, <-chan zookeeper.Event, error) {
	servers, err := resolveZkAddr(zkAddr)
	if err != nil {
		return nil, nil, err
	}

	sem.Acquire()
	defer sem.Release()
	zconn, session, err := zookeeper.Connect(servers, baseTimeout)
	if err == nil {
		// Wait for connection, possibly forever
		event := <-session
		if event.State != zookeeper.StateConnecting {
			err = fmt.Errorf("zk connect failed waiting for connecting state: %v", event.State)
		} else {
			event = <-session
			if event.State != zookeeper.StateConnected {
				err = fmt.Errorf("zk connect failed waiting for connected: %v", event.State)
			}
		}
		if err == nil {
			return &ZkConn{conn: zconn}, session, nil
		}
		zconn.Close()
	}
	return nil, nil, err
}

// DialZkTimeout dial the server, and wait up to timeout until connection
func DialZkTimeout(zkAddr string, baseTimeout time.Duration, connectTimeout time.Duration) (*ZkConn, <-chan zookeeper.Event, error) {
	servers, err := resolveZkAddr(zkAddr)
	if err != nil {
		return nil, nil, err
	}

	sem.Acquire()
	defer sem.Release()
	zconn, session, err := zookeeper.Connect(servers, baseTimeout)
	if err != nil {
		return nil, nil, err
	}

	// Wait for connection, with a timeout
	timer := time.NewTimer(connectTimeout)
	for {
		select {
		case <-timer.C:
			zconn.Close()
			return nil, nil, context.DeadlineExceeded
		case event := <-session:
			if event.State == zookeeper.StateConnected {
				return &ZkConn{conn: zconn}, session, nil
			}
		}
	}
}

// resolveZkAddr takes a comma-separated list of host:post addresses,
// and resolves the host to replace it with the IP address.
// If a resolution fails, the host is skipped.
// If no host can be resolved, an error is returned.
// This is different fromt he zookeeper C library, that insists on resolving
// *all* hosts before it starts.
func resolveZkAddr(zkAddr string) ([]string, error) {
	parts := strings.Split(zkAddr, ",")
	resolved := make([]string, 0, len(parts))
	for _, part := range parts {
		// The zookeeper client cannot handle IPv6 addresses before version 3.4.x.
		if r, err := netutil.ResolveIPv4Addr(part); err != nil {
			log.Infof("cannot resolve %v, will not use it: %v", part, err)
		} else {
			resolved = append(resolved, r)
		}
	}
	if len(resolved) == 0 {
		return nil, fmt.Errorf("no valid address found in %v", zkAddr)
	}
	return resolved, nil
}

// Get is part of the ZkConn interface.
func (conn *ZkConn) Get(path string) (string, *zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return "", nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	data, stat, err := c.Get(path)
	if err != nil {
		return "", nil, err
	}
	return string(data), stat, nil
}

// GetW is part of the ZkConn interface.
func (conn *ZkConn) GetW(path string) (string, *zookeeper.Stat, <-chan zookeeper.Event, error) {
	c := conn.getConn()
	if c == nil {
		return "", nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	data, stat, watch, err := c.GetW(path)
	if err != nil {
		return "", nil, nil, err
	}
	return string(data), stat, watch, nil
}

// Children is part of the ZkConn interface.
func (conn *ZkConn) Children(path string) ([]string, *zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	children, stat, err := c.Children(path)
	if err != nil {
		return nil, nil, err
	}
	return children, stat, nil
}

// ChildrenW is part of the ZkConn interface.
func (conn *ZkConn) ChildrenW(path string) ([]string, *zookeeper.Stat, <-chan zookeeper.Event, error) {
	c := conn.getConn()
	if c == nil {
		return nil, nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	children, stat, watch, err := c.ChildrenW(path)
	if err != nil {
		return nil, nil, nil, err
	}
	return children, stat, watch, nil
}

// Exists is part of the ZkConn interface.
func (conn *ZkConn) Exists(path string) (*zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	exists, stat, err := c.Exists(path)
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, zookeeper.ErrNoNode
	}
	return stat, nil
}

// ExistsW is part of the ZkConn interface.
func (conn *ZkConn) ExistsW(path string) (*zookeeper.Stat, <-chan zookeeper.Event, error) {
	c := conn.getConn()
	if c == nil {
		return nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	exists, stat, watch, err := c.ExistsW(path)
	if err != nil {
		return nil, nil, err
	}
	if !exists {
		return nil, watch, nil
	}
	return stat, watch, nil
}

// Create is part of the ZkConn interface.
func (conn *ZkConn) Create(path, value string, flags int, aclv []zookeeper.ACL) (pathCreated string, err error) {
	c := conn.getConn()
	if c == nil {
		return "", ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	return c.Create(path, []byte(value), int32(flags), aclv)
}

// Set is part of the ZkConn interface.
func (conn *ZkConn) Set(path, value string, version int32) (*zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	stat, err := c.Set(path, []byte(value), version)
	if err != nil {
		return nil, err
	}
	return stat, nil
}

// Delete is part of the ZkConn interface.
func (conn *ZkConn) Delete(path string, version int32) (err error) {
	c := conn.getConn()
	if c == nil {
		return ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	return c.Delete(path, version)
}

// Close will close the connection asynchronously.  It will never
// fail, even though closing the connection might fail in the
// background.  Accessing this ZkConn after Close has been called will
// return ErrConnectionClosed.
func (conn *ZkConn) Close() error {
	conn.mu.Lock()
	defer conn.mu.Unlock()
	if conn.conn == nil {
		return nil
	}
	c := conn.conn
	conn.conn = nil
	go c.Close()
	return nil
}

// ACL is part of the ZkConn interface.
func (conn *ZkConn) ACL(path string) ([]zookeeper.ACL, *zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	acls, stat, err := c.GetACL(path)
	if err != nil {
		return nil, nil, err
	}
	return acls, stat, nil
}

// SetACL is part of the ZkConn interface.
func (conn *ZkConn) SetACL(path string, aclv []zookeeper.ACL, version int32) error {
	c := conn.getConn()
	if c == nil {
		return ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	_, err := c.SetACL(path, aclv, version)
	return err
}
<commit_msg>Fixing zk connect logic to fast fail if possible.<commit_after>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package zk

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"golang.org/x/net/context"

	log "github.com/golang/glog"
	zookeeper "github.com/samuel/go-zookeeper/zk"

	"github.com/youtube/vitess/go/netutil"
	"github.com/youtube/vitess/go/sync2"
)

// Time returns a time.Time from a ZK int64 milliseconds since Epoch time.
func Time(i int64) time.Time {
	return time.Unix(i/1000, i%1000*1000000)
}

// ZkTime returns a ZK time (int64) from a time.Time
func ZkTime(t time.Time) int64 {
	return t.Unix()*1000 + int64(t.Nanosecond()/1000000)
}

// Every blocking call into CGO causes another thread which blows up
// the virtual memory.  It seems better to solve this here at the
// root of the problem rather than forcing all other apps to take into
// account limiting the number of concurrent operations on a zk
// connection.  Since this applies to any zookeeper connection, this
// is global.
var sem *sync2.Semaphore

// ErrConnectionClosed is returned if we try to access a closed connection.
var ErrConnectionClosed = errors.New("ZkConn: connection is closed")

func init() {
	// The zookeeper C module logs quite a bit of useful information,
	// but much of it does not come back in the error API. To aid
	// debugging, enable the log to stderr for warnings.
	//zookeeper.SetLogLevel(zookeeper.LOG_WARN)

	maxConcurrency := 64
	x := os.Getenv("ZK_CLIENT_MAX_CONCURRENCY")
	if x != "" {
		var err error
		maxConcurrency, err = strconv.Atoi(x)
		if err != nil {
			log.Infof("invalid ZK_CLIENT_MAX_CONCURRENCY: %v", err)
		}
	}

	sem = sync2.NewSemaphore(maxConcurrency, 0)
}

// ZkConn is a client class that implements zk.Conn using a zookeeper.Conn.
// The conn member variable is protected by the mutex.
type ZkConn struct {
	mu   sync.Mutex
	conn *zookeeper.Conn
}

// getConn returns the connection in a thread safe way
func (conn *ZkConn) getConn() *zookeeper.Conn {
	conn.mu.Lock()
	defer conn.mu.Unlock()
	return conn.conn
}

// DialZk dials a ZK server and waits for connection event. Returns a ZkConn
// encapsulating the zookeeper.Conn, and the zookeeper session event
// channel to monitor the connection
//
// The value for baseTimeout is used as a session timeout as well, and
// will be used to negotiate a 'good' value with the server. From
// reading the zookeeper source code, it has to be between 6 and 60
// seconds (2x and 20x the tickTime by default, with default tick time
// being 3 seconds).  min session time, max session time and ticktime
// can all be overwritten on the zookeeper server side, so these
// numbers may vary.
//
// Then this baseTimeout is used to compute other related timeouts:
// - connect timeout is 1/3 of baseTimeout
// - recv timeout is 2/3 of baseTimeout minus a ping time
// - send timeout is 1/3 of baseTimeout
// - we try to send a ping a least every baseTimeout / 3
//
// Note the baseTimeout has *nothing* to do with the time between we
// call Dial and the maximum time before we receive the event on the
// session. The library will actually try to re-connect in the background
// (after each timeout), and may *never* send an event if the TCP connections
// always fail. Use DialZkTimeout to enforce a timeout for the initial connect.
func DialZk(zkAddr string, baseTimeout time.Duration) (*ZkConn, <-chan zookeeper.Event, error) {
	servers, err := resolveZkAddr(zkAddr)
	if err != nil {
		return nil, nil, err
	}

	sem.Acquire()
	defer sem.Release()
	zconn, session, err := zookeeper.Connect(servers, baseTimeout)
	if err != nil {
		return nil, nil, err
	}

	// Wait for connection, possibly forever, skipping transition states
	for {
		event := <-session
		switch event.State {
		case zookeeper.StateConnected:
			// success
			return &ZkConn{conn: zconn}, session, nil

		case zookeeper.StateAuthFailed:
			// fast fail this one
			zconn.Close()
			return nil, nil, fmt.Errorf("zk connect failed: StateAuthFailed")
		}
	}
}

// DialZkTimeout dial the server, and wait up to timeout until connection
func DialZkTimeout(zkAddr string, baseTimeout time.Duration, connectTimeout time.Duration) (*ZkConn, <-chan zookeeper.Event, error) {
	servers, err := resolveZkAddr(zkAddr)
	if err != nil {
		return nil, nil, err
	}

	sem.Acquire()
	defer sem.Release()
	zconn, session, err := zookeeper.Connect(servers, baseTimeout)
	if err != nil {
		return nil, nil, err
	}

	// Wait for connection, with a timeout, skipping transition states
	timer := time.NewTimer(connectTimeout)
	for {
		select {
		case <-timer.C:
			zconn.Close()
			return nil, nil, context.DeadlineExceeded
		case event := <-session:
			switch event.State {
			case zookeeper.StateConnected:
				// success
				return &ZkConn{conn: zconn}, session, nil

			case zookeeper.StateAuthFailed:
				// fast fail this one
				zconn.Close()
				return nil, nil, fmt.Errorf("zk connect failed: StateAuthFailed")
			}
		}
	}
}

// resolveZkAddr takes a comma-separated list of host:post addresses,
// and resolves the host to replace it with the IP address.
// If a resolution fails, the host is skipped.
// If no host can be resolved, an error is returned.
// This is different from the zookeeper library, that insists on resolving
// *all* hosts successfully before it starts.
func resolveZkAddr(zkAddr string) ([]string, error) {
	parts := strings.Split(zkAddr, ",")
	resolved := make([]string, 0, len(parts))
	for _, part := range parts {
		// The zookeeper client cannot handle IPv6 addresses before version 3.4.x.
		if r, err := netutil.ResolveIPv4Addr(part); err != nil {
			log.Infof("cannot resolve %v, will not use it: %v", part, err)
		} else {
			resolved = append(resolved, r)
		}
	}
	if len(resolved) == 0 {
		return nil, fmt.Errorf("no valid address found in %v", zkAddr)
	}
	return resolved, nil
}

// Get is part of the ZkConn interface.
func (conn *ZkConn) Get(path string) (string, *zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return "", nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	data, stat, err := c.Get(path)
	if err != nil {
		return "", nil, err
	}
	return string(data), stat, nil
}

// GetW is part of the ZkConn interface.
func (conn *ZkConn) GetW(path string) (string, *zookeeper.Stat, <-chan zookeeper.Event, error) {
	c := conn.getConn()
	if c == nil {
		return "", nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	data, stat, watch, err := c.GetW(path)
	if err != nil {
		return "", nil, nil, err
	}
	return string(data), stat, watch, nil
}

// Children is part of the ZkConn interface.
func (conn *ZkConn) Children(path string) ([]string, *zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	children, stat, err := c.Children(path)
	if err != nil {
		return nil, nil, err
	}
	return children, stat, nil
}

// ChildrenW is part of the ZkConn interface.
func (conn *ZkConn) ChildrenW(path string) ([]string, *zookeeper.Stat, <-chan zookeeper.Event, error) {
	c := conn.getConn()
	if c == nil {
		return nil, nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	children, stat, watch, err := c.ChildrenW(path)
	if err != nil {
		return nil, nil, nil, err
	}
	return children, stat, watch, nil
}

// Exists is part of the ZkConn interface.
func (conn *ZkConn) Exists(path string) (*zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	exists, stat, err := c.Exists(path)
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, zookeeper.ErrNoNode
	}
	return stat, nil
}

// ExistsW is part of the ZkConn interface.
func (conn *ZkConn) ExistsW(path string) (*zookeeper.Stat, <-chan zookeeper.Event, error) {
	c := conn.getConn()
	if c == nil {
		return nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	exists, stat, watch, err := c.ExistsW(path)
	if err != nil {
		return nil, nil, err
	}
	if !exists {
		return nil, watch, nil
	}
	return stat, watch, nil
}

// Create is part of the ZkConn interface.
func (conn *ZkConn) Create(path, value string, flags int, aclv []zookeeper.ACL) (pathCreated string, err error) {
	c := conn.getConn()
	if c == nil {
		return "", ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	return c.Create(path, []byte(value), int32(flags), aclv)
}

// Set is part of the ZkConn interface.
func (conn *ZkConn) Set(path, value string, version int32) (*zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	stat, err := c.Set(path, []byte(value), version)
	if err != nil {
		return nil, err
	}
	return stat, nil
}

// Delete is part of the ZkConn interface.
func (conn *ZkConn) Delete(path string, version int32) (err error) {
	c := conn.getConn()
	if c == nil {
		return ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	return c.Delete(path, version)
}

// Close will close the connection asynchronously.  It will never
// fail, even though closing the connection might fail in the
// background.  Accessing this ZkConn after Close has been called will
// return ErrConnectionClosed.
func (conn *ZkConn) Close() error {
	conn.mu.Lock()
	defer conn.mu.Unlock()
	if conn.conn == nil {
		return nil
	}
	c := conn.conn
	conn.conn = nil
	go c.Close()
	return nil
}

// ACL is part of the ZkConn interface.
func (conn *ZkConn) ACL(path string) ([]zookeeper.ACL, *zookeeper.Stat, error) {
	c := conn.getConn()
	if c == nil {
		return nil, nil, ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	acls, stat, err := c.GetACL(path)
	if err != nil {
		return nil, nil, err
	}
	return acls, stat, nil
}

// SetACL is part of the ZkConn interface.
func (conn *ZkConn) SetACL(path string, aclv []zookeeper.ACL, version int32) error {
	c := conn.getConn()
	if c == nil {
		return ErrConnectionClosed
	}

	sem.Acquire()
	defer sem.Release()
	_, err := c.SetACL(path, aclv, version)
	return err
}
<|endoftext|>


<commit_before>package main
/*
	net/http包的基本使用方法
*/
import (
    "fmt"
    "net/http"
)

/* 自定义路由 */
type CustomRouter struct {
}

/* 实现 Handler 接口 */
func (p *CustomRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "/" {
        helloWorld(w, r)
        return
    }
    http.NotFound(w, r)
    return
}

func helloWorld(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

func main() {
    //router := &CustomRouter{}
    //http.ListenAndServe(":8080", router)
	http.HandleFunc("/", helloWorld)
	http.ListenAndServe(":8000", nil)
}
<commit_msg>param test<commit_after>package main

/*
	net/http包的基本使用方法
*/
import (
	"fmt"
	"net/http"
	"io"
	"os"
	"log"
	"encoding/json"
	"io/ioutil"
)

/* 自定义路由 */
type CustomRouter struct {
}

/* 实现 Handler 接口 */
func (p *CustomRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		helloWorld(w, r)
		return
	}
	http.NotFound(w, r)
	return
}

func helloWorld(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World!")
}

func getParam(w http.ResponseWriter, r *http.Request) {
	//reqGet := r.URL.Query()
	//// get multiple key to array
	//names := reqGet["name"]
	//age := reqGet.Get("age")
	//// get none exist key to ""
	//notExist := reqGet.Get("balabala")
	//if notExist == "" {
	//	fmt.Println("notExist not exist in param")
	//}
	//for _, name := range names {
	//	fmt.Println(name)
	//}
	//fmt.Println(r.URL.Path, r.URL.String(), r.URL.RawPath, r.URL.RawQuery, names, age, notExist == "")
	//
	// 获取GET请求参数
	if err := r.ParseForm(); err != nil {
		log.Fatal(err)
	}
	//fmt.Println(r.Form.Get("age"), r.Form.Get("name"), r.Form["name"], r.Form.Get("EMTPY"))
	//fmt.Fprintf(w, "%s", r.Form)
	fmt.Printf("name: %s, age=%s\n", r.Form["name"], r.Form.Get("age"))
	fmt.Printf("name=%s, age=%s\n", r.FormValue("name"), r.FormValue("age"))
	fmt.Printf("name=%s, age=%s\n", r.PostFormValue("name"), r.PostFormValue("age"))
	fmt.Fprintf(w, "name=%s, age=%s\n", r.FormValue("name"), r.FormValue("age"))
	/*
	name: [pitou miya], age=123
	name=pitou, age=123
	name=, age=
	*/
}

func postFormData(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseMultipartForm(32 << 20); err != nil {
		log.Fatal(err)
	}
	//fmt.Fprintf(w, "Form: %s\n", r.Form)
	//fmt.Fprintf(w, "PostForm: %s\n", r.PostForm)
	//fmt.Fprintf(w, "MultipartForm: %s\n", r.MultipartForm)
	//fmt.Println(r.Form.Get("name"), r.Form.Get("age"))
	//fmt.Println(r.PostForm.Get("name"), r.PostForm.Get("age"))
	fmt.Fprintf(w, "name=%s, age=%s\n", r.PostFormValue("name"), r.PostFormValue("age"))
	fmt.Printf("name=%s, age=%s\n", r.PostFormValue("name"), r.PostFormValue("age"))
	fmt.Printf("name=%s, age=%s\n", r.FormValue("name"), r.FormValue("age"))
	fmt.Printf("name=%s, age=%s\n", r.PostForm["name"], r.PostForm.Get("age"))
	/*
	name=miya, age=12345
	name=miya, age=12345
	name=[miya pitou], age=12345
	*/

	// file upload
	file, handler, err := r.FormFile("test")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	fmt.Fprintf(w, "%v", handler.Header)

	//f, err := os.OpenFile("./"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666) // 此处假设当前目录下已存在test目录
	f, err := os.Create("./" + handler.Filename)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	copySize, ok := io.Copy(f, file)
	fmt.Println(copySize, ok)
}

type Message struct {
	Name string `json:"name"`
	Body string    `json:"body"`
	Time int64    `json:"time,string"`
}

func postJsonData(w http.ResponseWriter, r *http.Request) {
	// dumps
	m := Message{"Alice", "Hello", 1294706395881547000}
	bb, err := json.Marshal(m)
	if err != nil {
		log.Fatal("%s", err)
	}
	fmt.Println(bb)
	//w.Header().Set("Content-Type", "application/json")
	//fmt.Fprintf(w, "%s", b)

	// loads
	//var data Message
	var data map[string]interface{}
	//bb := `{
	//"name":"rsj217@gmail.com",
	//"body":"123",
	//"time":100.5
	//}`
	err = json.Unmarshal([]byte(bb), &data)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(data)

	// read from body and return
	// curl -v -XPOST localhost:8000/json/ -H "Content-Type:application/json" -d '{"name":"miya","body":"body","time":"11234"}'
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal("Read Err: %s", err)
	}

	//err = json.Unmarshal(body, &msg)
	err = json.Unmarshal(body, &data)
	fmt.Println(data, data["name"])
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintf(w, "%s", body)
}

func main() {
	//router := &CustomRouter{}
	//http.ListenAndServe(":8080", router)
	http.HandleFunc("/", helloWorld)
	http.HandleFunc("/get/", getParam)
	//curl -XPOST localhost:8000/post/ -F "name=miya" -F "age=123" -F "test=@test.txt"
	http.HandleFunc("/post/", postFormData)
	http.HandleFunc("/json/", postJsonData)
	http.ListenAndServe(":8000", nil)
}
<|endoftext|>


<commit_before>// Package gohinetradio is to get hichannel radio path and with token to play without flash.
package gohinetradio

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"sort"
	"strconv"
	"sync"
	"text/tabwriter"
)

var nCPU = runtime.NumCPU()

// Init.
func init() {
	runtime.GOMAXPROCS(nCPU)
}

// Base URL.
const (
	PLAYURL  string = "http://hichannel.hinet.net/radio/play.do?id=%s"
	LISTURL  string = "http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=%d"
	LISTPAGE int    = 4
)

// RadioData is the json of `http://hichannel.hinet.net/radio/play.do?id=232`
type RadioData struct {
	ChannelTitle   string `json:"channel_title"`
	PlayRadio      string `json:"playRadio"`
	ProgramName    string `json:"programName"`
	ChannelCollect bool   `json:"channel_collect"`
}

// GetURL is getting radio channel url with token.
func GetURL(No string) (RadioData, error) {
	resp, _ := http.Get(fmt.Sprintf(PLAYURL, No))
	defer resp.Body.Close()
	var r RadioData
	var err error
	data, _ := ioutil.ReadAll(resp.Body)
	jsonData := json.NewDecoder(bytes.NewReader(data))
	jsonData.Decode(&r)
	if len(r.PlayRadio) == 0 {
		err = errors.New("No channel data.")
	}
	return r, err
}

// RadioListData is the json of `http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=1`
type RadioListData struct {
	PageNo   int              `json:"pageNo"`
	PageSize int              `json:"pageSize"`
	List     []RadioListDatas `json:"list"`
}

//RadioListDatas is RadioListData.List type.
type RadioListDatas struct {
	ChannelImage string `json:"channel_image"`
	ChannelTitle string `json:"channel_title"`
	RadioType    string `json:"radio_type"`
	IsChannel    bool   `json:"isChannel"`
	ProgramName  string `json:"program_name"`
	ChannelID    string `json:"channel_id"`
}

func getRadioPageList(page int) RadioListData {
	resp, _ := http.Get(fmt.Sprintf(LISTURL, page))
	defer resp.Body.Close()
	var r RadioListData
	data, _ := ioutil.ReadAll(resp.Body)
	jsonData := json.NewDecoder(bytes.NewReader(data))
	jsonData.Decode(&r)
	return r
}

// GetRadioList is getting all channel list.
func GetRadioList() []RadioListDatas {
	queue := make(chan RadioListData, nCPU)
	var wg sync.WaitGroup
	wg.Add(LISTPAGE * 2)
	for i := 1; i <= LISTPAGE; i++ {
		go func(i int) {
			defer wg.Done()
			runtime.Gosched()
			queue <- getRadioPageList(i)
		}(i)
	}
	var r []RadioListDatas
	go func() {
		for v := range queue {
			for _, data := range v.List {
				r = append(r, data)
			}
			wg.Done()
		}
	}()
	wg.Wait()
	return r
}

type byChannel []RadioListDatas

func (c byChannel) Len() int      { return len(c) }
func (c byChannel) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c byChannel) Less(i, j int) bool {
	a, _ := strconv.Atoi(c[i].ChannelID)
	b, _ := strconv.Atoi(c[j].ChannelID)
	return a < b
}

// GenList is to output table list.
func GenList() {
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 0, 8, 0, '\t', 0)
	var output string
	var no int
	radioList := GetRadioList()
	sort.Sort(byChannel(radioList))
	for _, data := range radioList {
		if data.IsChannel {
			output += fmt.Sprintf("%d. [%v] %s\t", no+1, data.ChannelID, data.ChannelTitle)
			if (no+1)%3 == 0 {
				fmt.Fprintln(w, output)
				output = ""
			}
			no++
		}
	}
	fmt.Fprintln(w, output)
	w.Flush()
}

// PrintChannel is my fav channel XD.
func PrintChannel() {
	fmt.Println("[207] 中廣新聞網")
	fmt.Println("[205] 中廣流行網 i like")
	fmt.Println("[206] 中廣音樂網i radio")
	fmt.Println("[232] 飛碟電台")
	fmt.Println("[222] HitFm聯播網 Taipei 北部")
	fmt.Println("[156] KISS RADIO 大眾廣播電台")
	fmt.Println("[308] KISS RADIO 網路音樂台")
	fmt.Println("[187] NEWS98新聞網")
	fmt.Println("[370] POP Radio 台北流行廣播電台")
}
<commit_msg>Better for wait groups.<commit_after>// Package gohinetradio is to get hichannel radio path and with token to play without flash.
package gohinetradio

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"sort"
	"strconv"
	"sync"
	"text/tabwriter"
)

var nCPU = runtime.NumCPU()

// Init.
func init() {
	runtime.GOMAXPROCS(nCPU)
}

// Base URL.
const (
	PLAYURL  string = "http://hichannel.hinet.net/radio/play.do?id=%s"
	LISTURL  string = "http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=%d"
	LISTPAGE int    = 4
)

// RadioData is the json of `http://hichannel.hinet.net/radio/play.do?id=232`
type RadioData struct {
	ChannelTitle   string `json:"channel_title"`
	PlayRadio      string `json:"playRadio"`
	ProgramName    string `json:"programName"`
	ChannelCollect bool   `json:"channel_collect"`
}

// GetURL is getting radio channel url with token.
func GetURL(No string) (RadioData, error) {
	resp, _ := http.Get(fmt.Sprintf(PLAYURL, No))
	defer resp.Body.Close()
	var r RadioData
	var err error
	data, _ := ioutil.ReadAll(resp.Body)
	jsonData := json.NewDecoder(bytes.NewReader(data))
	jsonData.Decode(&r)
	if len(r.PlayRadio) == 0 {
		err = errors.New("No channel data.")
	}
	return r, err
}

// RadioListData is the json of `http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=1`
type RadioListData struct {
	PageNo   int              `json:"pageNo"`
	PageSize int              `json:"pageSize"`
	List     []RadioListDatas `json:"list"`
}

//RadioListDatas is RadioListData.List type.
type RadioListDatas struct {
	ChannelImage string `json:"channel_image"`
	ChannelTitle string `json:"channel_title"`
	RadioType    string `json:"radio_type"`
	IsChannel    bool   `json:"isChannel"`
	ProgramName  string `json:"program_name"`
	ChannelID    string `json:"channel_id"`
}

func getRadioPageList(page int) RadioListData {
	resp, _ := http.Get(fmt.Sprintf(LISTURL, page))
	defer resp.Body.Close()
	var r RadioListData
	data, _ := ioutil.ReadAll(resp.Body)
	jsonData := json.NewDecoder(bytes.NewReader(data))
	jsonData.Decode(&r)
	return r
}

// GetRadioList is getting all channel list.
func GetRadioList() []RadioListDatas {
	queue := make(chan RadioListData, nCPU)
	var wg sync.WaitGroup
	wg.Add(LISTPAGE)
	for i := 1; i <= LISTPAGE; i++ {
		go func(i int) {
			runtime.Gosched()
			queue <- getRadioPageList(i)
		}(i)
	}
	var r []RadioListDatas
	go func() {
		for v := range queue {
			for _, data := range v.List {
				r = append(r, data)
			}
			wg.Done()
		}
	}()
	wg.Wait()
	return r
}

type byChannel []RadioListDatas

func (c byChannel) Len() int      { return len(c) }
func (c byChannel) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c byChannel) Less(i, j int) bool {
	a, _ := strconv.Atoi(c[i].ChannelID)
	b, _ := strconv.Atoi(c[j].ChannelID)
	return a < b
}

// GenList is to output table list.
func GenList() {
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 0, 8, 0, '\t', 0)
	var output string
	var no int
	radioList := GetRadioList()
	sort.Sort(byChannel(radioList))
	for _, data := range radioList {
		if data.IsChannel {
			output += fmt.Sprintf("%d. [%v] %s\t", no+1, data.ChannelID, data.ChannelTitle)
			if (no+1)%3 == 0 {
				fmt.Fprintln(w, output)
				output = ""
			}
			no++
		}
	}
	fmt.Fprintln(w, output)
	w.Flush()
}

// PrintChannel is my fav channel XD.
func PrintChannel() {
	fmt.Println("[207] 中廣新聞網")
	fmt.Println("[205] 中廣流行網 i like")
	fmt.Println("[206] 中廣音樂網i radio")
	fmt.Println("[232] 飛碟電台")
	fmt.Println("[222] HitFm聯播網 Taipei 北部")
	fmt.Println("[156] KISS RADIO 大眾廣播電台")
	fmt.Println("[308] KISS RADIO 網路音樂台")
	fmt.Println("[187] NEWS98新聞網")
	fmt.Println("[370] POP Radio 台北流行廣播電台")
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"github.com/dghubble/go-twitter/twitter"
	"github.com/dghubble/oauth1"
	"github.com/joho/godotenv"
)

func main() {
	if err := Run(); err != nil {
		log.Fatal(err)
	}
}

func Run() error {
	// .env の読み込み
	if err := godotenv.Load(); err != nil {
		return err
	}

	// カレンダーの作成
	// TODO: ここのハードコードそのうちどうにかする
	cal, err := NewCalendar("../calendar")
	if err != nil {
		return err
	}

	// Twitter Client の作成
	config := oauth1.NewConfig(os.Getenv("CONSUMER_KEY"), os.Getenv("CONSUMER_SECRET"))
	token := oauth1.NewToken(os.Getenv("ACCESS_TOKEN"), os.Getenv("ACCESS_SECRET"))
	httpClient := config.Client(oauth1.NoContext, token)
	client := twitter.NewClient(httpClient)

	RegularTweetServer(client, cal)
	return nil
}
<commit_msg>カレンダーのディレクトリを引数で受け取れるようにした<commit_after>package main

import (
	"log"
	"os"

	"github.com/dghubble/go-twitter/twitter"
	"github.com/dghubble/oauth1"
	"github.com/joho/godotenv"
)

func main() {
	if err := Run(); err != nil {
		log.Fatal(err)
	}
}

func Run() error {
	// .env の読み込み
	if err := godotenv.Load(); err != nil {
		return err
	}

	// カレンダーの作成
	cal, err := NewCalendar(CalDir())
	if err != nil {
		return err
	}

	// Twitter Client の作成
	config := oauth1.NewConfig(os.Getenv("CONSUMER_KEY"), os.Getenv("CONSUMER_SECRET"))
	token := oauth1.NewToken(os.Getenv("ACCESS_TOKEN"), os.Getenv("ACCESS_SECRET"))
	httpClient := config.Client(oauth1.NoContext, token)
	client := twitter.NewClient(httpClient)

	RegularTweetServer(client, cal)
	return nil
}

// TODO: この雑な実装をそのうちどうにかする
func CalDir() string {
	return os.Args[1]
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"
	"net/http"
	"path/filepath"
	"text/template"

	"github.com/olebedev/go-duktape"
)

func loadJSFile(ctx *duktape.Context, file string) error {
	ctx.EvalFile(file)
	result := ctx.GetString(-1)

	if result != "" {
		return errors.New(result)
	}

	ctx.Pop()

	return nil
}

func loadJSFiles(ctx *duktape.Context, files ...string) error {
	for _, file := range files {
		err := loadJSFile(ctx, file)

		if err != nil {
			return err
		}
	}

	return nil
}

func renderServer(ctx *duktape.Context, name string) (string, error) {
	ctx.GetGlobalString("renderServer")

	if ctx.IsUndefined(-1) {
		return "", errors.New("Could not find function 'renderServer'")
	}

	ctx.PushString(name)
	ctx.Call(1)
	result := ctx.GetString(-1)
	ctx.Pop()

	return result, nil
}

func Index(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles(filepath.Join("templates", "index.gohtml"))

	if err != nil {
		log.Fatal(err)
	}

	ctx := duktape.New()

	err = loadJSFiles(ctx,
		"static/duktape-polyfill.js",
		"static/react.js",
		"static/react-dom-server.js",
		"static/components.js",
		"static/server.js",
	)

	if err != nil {
		log.Fatal(err)
	}

	component, err := renderServer(ctx, "Claudemiro")

	if err != nil {
		log.Fatal(err)
	}

	t.Execute(w, component)
}

func main() {
	http.HandleFunc("/", Index)
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Added LICENSE<commit_after>// The MIT License (MIT)

// Copyright (c) 2016 Claudemiro

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package main

import (
	"errors"
	"log"
	"net/http"
	"path/filepath"
	"text/template"

	"github.com/olebedev/go-duktape"
)

func loadJSFile(ctx *duktape.Context, file string) error {
	ctx.EvalFile(file)
	result := ctx.GetString(-1)

	if result != "" {
		return errors.New(result)
	}

	ctx.Pop()

	return nil
}

func loadJSFiles(ctx *duktape.Context, files ...string) error {
	for _, file := range files {
		err := loadJSFile(ctx, file)

		if err != nil {
			return err
		}
	}

	return nil
}

func renderServer(ctx *duktape.Context, name string) (string, error) {
	ctx.GetGlobalString("renderServer")

	if ctx.IsUndefined(-1) {
		return "", errors.New("Could not find function 'renderServer'")
	}

	ctx.PushString(name)
	ctx.Call(1)
	result := ctx.GetString(-1)
	ctx.Pop()

	return result, nil
}

func Index(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles(filepath.Join("templates", "index.gohtml"))

	if err != nil {
		log.Fatal(err)
	}

	ctx := duktape.New()

	err = loadJSFiles(ctx,
		"static/duktape-polyfill.js",
		"static/react.js",
		"static/react-dom-server.js",
		"static/components.js",
		"static/server.js",
	)

	if err != nil {
		log.Fatal(err)
	}

	component, err := renderServer(ctx, "Claudemiro")

	if err != nil {
		log.Fatal(err)
	}

	t.Execute(w, component)
}

func main() {
	http.HandleFunc("/", Index)
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


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

// +build !appengine

package main

import (
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"code.google.com/p/go.talks/pkg/socket"

	// Imports so that go build/install automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const (
	basePkg    = "code.google.com/p/go-tour/"
	socketPath = "/socket"
)

var (
	httpListen  = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput  = flag.Bool("html", false, "render program output as HTML")
	openBrowser = flag.Bool("openbrowser", true, "open browser automatically")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)

	// GOPATH containing the tour packages
	gopath = os.Getenv("GOPATH")

	httpAddr string
)

func isRoot(path string) bool {
	_, err := os.Stat(filepath.Join(path, "tour.article"))
	return err == nil
}

func findRoot() (string, error) {
	ctx := build.Default
	p, err := ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(p.Dir) {
		return p.Dir, nil
	}
	tourRoot := filepath.Join(runtime.GOROOT(), "misc", "tour")
	ctx.GOPATH = tourRoot
	p, err = ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(tourRoot) {
		gopath = tourRoot
		return tourRoot, nil
	}
	return "", fmt.Errorf("could not find go-tour content; check $GOROOT and $GOPATH")
}

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	// find and serve the go tour files
	root, err := findRoot()
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}

	log.Println("Serving content from", root)

	host, port, err := net.SplitHostPort(*httpListen)
	if err != nil {
		log.Fatal(err)
	}
	if host == "" {
		host = "localhost"
	}
	if host != "127.0.0.1" && host != "localhost" {
		log.Print(localhostWarning)
	}
	httpAddr = host + ":" + port

	if err := initTour(root); err != nil {
		log.Fatal(err)
	}

	fs := http.FileServer(http.Dir(root))
	http.Handle("/favicon.ico", fs)
	http.Handle("/static/", fs)
	http.Handle("/talks/", fs)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			if err := renderTour(w); err != nil {
				log.Println(err)
			}
			return
		}
		http.Error(w, "not found", 404)
	})

	http.Handle(socketPath, socket.Handler)

	err = serveScripts(filepath.Join(root, "js"), "SocketTransport")
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		url := "http://" + httpAddr
		if waitServer(url) && *openBrowser && startBrowser(url) {
			log.Printf("A browser window should open. If not, please visit %s", url)
		} else {
			log.Printf("Please open your web browser and visit %s", url)
		}
	}()
	log.Fatal(http.ListenAndServe(httpAddr, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

type response struct {
	Output string `json:"output"`
	Errors string `json:"compile_errors"`
}

func init() {
	socket.Environ = environ
}

// environ returns the original execution environment with GOPATH
// replaced (or added) with the value of the global var gopath.
func environ() (env []string) {
	for _, v := range os.Environ() {
		if !strings.HasPrefix(v, "GOPATH=") {
			env = append(env, v)
		}
	}
	env = append(env, "GOPATH="+gopath)
	return
}

// waitServer waits some time for the http Server to start
// serving url and returns whether it starts
func waitServer(url string) bool {
	tries := 20
	for tries > 0 {
		resp, err := http.Get(url)
		if err == nil {
			resp.Body.Close()
			return true
		}
		time.Sleep(100 * time.Millisecond)
		tries--
	}
	return false
}

// startBrowser tries to open the URL in a browser, and returns
// whether it succeed.
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
}

// prepContent for the local tour simply returns the content as-is.
func prepContent(r io.Reader) io.Reader { return r }

// socketAddr returns the WebSocket handler address.
func socketAddr() string { return "ws://" + httpAddr + socketPath }
<commit_msg>go-tour: remove unnecessary code<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !appengine

package main

import (
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"code.google.com/p/go.talks/pkg/socket"

	// Imports so that go build/install automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const (
	basePkg    = "code.google.com/p/go-tour/"
	socketPath = "/socket"
)

var (
	httpListen  = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput  = flag.Bool("html", false, "render program output as HTML")
	openBrowser = flag.Bool("openbrowser", true, "open browser automatically")
)

var (
	// GOPATH containing the tour packages
	gopath = os.Getenv("GOPATH")

	httpAddr string
)

func isRoot(path string) bool {
	_, err := os.Stat(filepath.Join(path, "tour.article"))
	return err == nil
}

func findRoot() (string, error) {
	ctx := build.Default
	p, err := ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(p.Dir) {
		return p.Dir, nil
	}
	tourRoot := filepath.Join(runtime.GOROOT(), "misc", "tour")
	ctx.GOPATH = tourRoot
	p, err = ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(tourRoot) {
		gopath = tourRoot
		return tourRoot, nil
	}
	return "", fmt.Errorf("could not find go-tour content; check $GOROOT and $GOPATH")
}

func main() {
	flag.Parse()

	// find and serve the go tour files
	root, err := findRoot()
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}

	log.Println("Serving content from", root)

	host, port, err := net.SplitHostPort(*httpListen)
	if err != nil {
		log.Fatal(err)
	}
	if host == "" {
		host = "localhost"
	}
	if host != "127.0.0.1" && host != "localhost" {
		log.Print(localhostWarning)
	}
	httpAddr = host + ":" + port

	if err := initTour(root); err != nil {
		log.Fatal(err)
	}

	fs := http.FileServer(http.Dir(root))
	http.Handle("/favicon.ico", fs)
	http.Handle("/static/", fs)
	http.Handle("/talks/", fs)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			if err := renderTour(w); err != nil {
				log.Println(err)
			}
			return
		}
		http.Error(w, "not found", 404)
	})

	http.Handle(socketPath, socket.Handler)

	err = serveScripts(filepath.Join(root, "js"), "SocketTransport")
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		url := "http://" + httpAddr
		if waitServer(url) && *openBrowser && startBrowser(url) {
			log.Printf("A browser window should open. If not, please visit %s", url)
		} else {
			log.Printf("Please open your web browser and visit %s", url)
		}
	}()
	log.Fatal(http.ListenAndServe(httpAddr, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

type response struct {
	Output string `json:"output"`
	Errors string `json:"compile_errors"`
}

func init() {
	socket.Environ = environ
}

// environ returns the original execution environment with GOPATH
// replaced (or added) with the value of the global var gopath.
func environ() (env []string) {
	for _, v := range os.Environ() {
		if !strings.HasPrefix(v, "GOPATH=") {
			env = append(env, v)
		}
	}
	env = append(env, "GOPATH="+gopath)
	return
}

// waitServer waits some time for the http Server to start
// serving url and returns whether it starts
func waitServer(url string) bool {
	tries := 20
	for tries > 0 {
		resp, err := http.Get(url)
		if err == nil {
			resp.Body.Close()
			return true
		}
		time.Sleep(100 * time.Millisecond)
		tries--
	}
	return false
}

// startBrowser tries to open the URL in a browser, and returns
// whether it succeed.
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
}

// prepContent for the local tour simply returns the content as-is.
func prepContent(r io.Reader) io.Reader { return r }

// socketAddr returns the WebSocket handler address.
func socketAddr() string { return "ws://" + httpAddr + socketPath }
<|endoftext|>