initial commit
diff --git a/gotour/goplay.go b/gotour/goplay.go
new file mode 100644
index 0000000..eebc29a
--- /dev/null
+++ b/gotour/goplay.go
@@ -0,0 +1,206 @@
+// Copyright 2010 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.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "http"
+ "template"
+)
+
+func init() {
+ http.HandleFunc("/compile", Compile)
+}
+
+// Compile is an HTTP handler that reads Go source code from the request,
+// compiles and links the code (returning any errors), runs the program,
+// and sends the program's output as the HTTP response.
+func Compile(w http.ResponseWriter, req *http.Request) {
+ out, err := compile(req)
+ if err != nil {
+ w.WriteHeader(404)
+ var s string
+ if out != nil {
+ s = string(out)
+ } else {
+ s = err.String()
+ }
+ output.Execute(w, s)
+ return
+ }
+
+ // write the output of x as the http response
+ if *htmlOutput {
+ w.Write(out)
+ } else if url, ok := isImage(out); ok {
+ fmt.Fprintf(w, `<img src="%s">`, url)
+ } else {
+ output.Execute(w, out)
+ }
+}
+
+func isImage(out []byte) (string, bool) {
+ out = bytes.TrimSpace(out)
+ if !bytes.HasPrefix(out, []byte("IMAGE:")) {
+ return "", false
+ }
+ out = out[6:]
+ for _, c := range out {
+ switch {
+ case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z', '0' <= c && c <= '9',
+ c == '+', c == '-', c == '/', c == '_', c == '=':
+ default:
+ println("bad", c)
+ return "", false
+ }
+ }
+ return "data:image/png;base64," + string(out), true
+}
+
+var frontPage, output *template.Template // HTML templates
+
+func init() {
+ frontPage = template.New(nil)
+ frontPage.SetDelims("«", "»")
+ if err := frontPage.Parse(frontPageText); err != nil {
+ panic(err)
+ }
+ output = template.MustParse(outputText, nil)
+}
+
+var outputText = `<pre>{@|html}</pre>`
+
+var frontPageText = `<!doctype html>
+<html>
+<head>
+<style>
+pre, textarea {
+ font-family: monospace; /* use the user's browser setting */
+ font-size: 100%;
+}
+.hints {
+ font-size: 0.8em;
+ text-align: right;
+}
+#edit, #output, #errors { width: 100%; text-align: left; }
+#edit { height: 500px; }
+#output { color: #00c; }
+#errors { color: #c00; }
+</style>
+<script>
+
+function insertTabs(n) {
+ // find the selection start and end
+ var cont = document.getElementById("edit");
+ var start = cont.selectionStart;
+ var end = cont.selectionEnd;
+ // split the textarea content into two, and insert n tabs
+ var v = cont.value;
+ var u = v.substr(0, start);
+ for (var i=0; i<n; i++) {
+ u += "\t";
+ }
+ u += v.substr(end);
+ // set revised content
+ cont.value = u;
+ // reset caret position after inserted tabs
+ cont.selectionStart = start+n;
+ cont.selectionEnd = start+n;
+}
+
+function autoindent(el) {
+ var curpos = el.selectionStart;
+ var tabs = 0;
+ while (curpos > 0) {
+ curpos--;
+ if (el.value[curpos] == "\t") {
+ tabs++;
+ } else if (tabs > 0 || el.value[curpos] == "\n") {
+ break;
+ }
+ }
+ setTimeout(function() {
+ insertTabs(tabs);
+ }, 1);
+}
+
+function keyHandler(event) {
+ var e = window.event || event;
+ if (e.keyCode == 9) { // tab
+ insertTabs(1);
+ e.preventDefault();
+ return false;
+ }
+ if (e.keyCode == 13) { // enter
+ if (e.shiftKey) { // +shift
+ compile(e.target);
+ e.preventDefault();
+ return false;
+ } else {
+ autoindent(e.target);
+ }
+ }
+ return true;
+}
+
+var xmlreq;
+
+function autocompile() {
+ if(!document.getElementById("autocompile").checked) {
+ return;
+ }
+ compile();
+}
+
+function compile() {
+ var prog = document.getElementById("edit").value;
+ var req = new XMLHttpRequest();
+ xmlreq = req;
+ req.onreadystatechange = function() { compileUpdate(req); }
+ req.open("POST", "/compile", true);
+ req.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
+ req.send(prog);
+ document.getElementById("output").innerHTML = "running...";
+}
+
+function compileUpdate(req) {
+ if(req != xmlreq || !req || req.readyState != 4) {
+ return;
+ }
+ if(req.status == 200) {
+ document.getElementById("output").innerHTML = req.responseText;
+ document.getElementById("errors").innerHTML = "";
+ } else {
+ document.getElementById("errors").innerHTML = req.responseText;
+ document.getElementById("output").innerHTML = "";
+ }
+}
+</script>
+</head>
+<body>
+<table width="100%"><tr><td width="60%" valign="top">
+<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler(event);" onkeyup="autocompile();">«@|html»</textarea>
+<div class="hints">
+(Shift-Enter to compile and run.)
+<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke
+</div>
+<td width="3%">
+<td width="27%" align="right" valign="top">
+<div id="output"></div>
+</table>
+<div id="errors"></div>
+</body>
+</html>
+`
+
+var helloWorld = []byte(`package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("hello, world")
+}
+`)
diff --git a/gotour/local.go b/gotour/local.go
new file mode 100644
index 0000000..271a1ee
--- /dev/null
+++ b/gotour/local.go
@@ -0,0 +1,161 @@
+// 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.
+
+package main
+
+import (
+ "bytes"
+ "exec"
+ "flag"
+ "fmt"
+ "go/build"
+ "http"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "sync"
+
+ // Imports so that goinstall automatically installs them.
+ _ "go-tour.googlecode.com/hg/pic"
+ _ "go-tour.googlecode.com/hg/wc"
+)
+
+const basePkg = "go-tour.googlecode.com/hg"
+
+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")
+)
+
+var (
+ // a source of numbers, for naming temporary files
+ uniq = make(chan int)
+ // the architecture-identifying character of the tool chain, 5, 6, or 8
+ archChar string
+ // where gc and ld should find the go-tour packages
+ pkgDir string
+)
+
+func main() {
+ flag.Parse()
+
+ // source of unique numbers
+ go func() {
+ for i := 0; ; i++ {
+ uniq <- i
+ }
+ }()
+
+ // set archChar
+ var err os.Error
+ archChar, err = build.ArchChar(runtime.GOARCH)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // find and serve the go tour files
+ t, _, err := build.FindTree(basePkg)
+ if err != nil {
+ log.Fatalf("Couldn't find tour files: %v", err)
+ }
+ root := filepath.Join(t.SrcDir(), basePkg, "static")
+ log.Println("Serving content from", root)
+ http.Handle("/", http.FileServer(http.Dir(root)))
+
+ pkgDir = t.PkgDir()
+
+ log.Printf("Serving at http://%s/", *httpListen)
+ log.Fatal(http.ListenAndServe(*httpListen, nil))
+}
+
+var running struct {
+ sync.Mutex
+ cmd *exec.Cmd
+}
+
+func stopRun() {
+ running.Lock()
+ if running.cmd != nil {
+ running.cmd.Process.Kill()
+ running.cmd = nil
+ }
+ running.Unlock()
+}
+
+func compile(req *http.Request) (out []byte, err os.Error) {
+ stopRun()
+
+ // x is the base name for .go, .6, executable files
+ x := os.TempDir() + "/compile" + strconv.Itoa(<-uniq)
+ src := x + ".go"
+ obj := x + "." + archChar
+ bin := x
+ if runtime.GOOS == "windows" {
+ bin += ".exe"
+ }
+
+ // rewrite filename in error output
+ defer func() {
+ out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1)
+ }()
+
+ // write body to x.go
+ body := new(bytes.Buffer)
+ if _, err = body.ReadFrom(req.Body); err != nil {
+ return
+ }
+ if err = ioutil.WriteFile(src, body.Bytes(), 0666); err != nil {
+ return
+ }
+
+ // build x.go, creating x.6
+ out, err = run(archChar+"g", "-I", pkgDir, "-o", obj, src)
+ defer os.Remove(obj)
+ if err != nil {
+ return
+ }
+
+ // link x.6, creating x (the program binary)
+ out, err = run(archChar+"l", "-L", pkgDir, "-o", bin, obj)
+ defer os.Remove(bin)
+ if err != nil {
+ return
+ }
+
+ // run x
+ return run(bin)
+}
+
+// run executes the specified command and returns its output and an error.
+func run(args ...string) ([]byte, os.Error) {
+ var buf bytes.Buffer
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Stdout = &buf
+ cmd.Stderr = cmd.Stdout
+
+ // Start command and leave in 'running'.
+ running.Lock()
+ if running.cmd != nil {
+ defer running.Unlock()
+ return nil, fmt.Errorf("already running %s", running.cmd.Path)
+ }
+ if err := cmd.Start(); err != nil {
+ running.Unlock()
+ return nil, err
+ }
+ running.cmd = cmd
+ running.Unlock()
+
+ // Wait for the command. Clean up,
+ err := cmd.Wait()
+ running.Lock()
+ if running.cmd == cmd {
+ running.cmd = nil
+ }
+ running.Unlock()
+ return buf.Bytes(), err
+}
diff --git a/pic/pic.go b/pic/pic.go
new file mode 100644
index 0000000..dca533b
--- /dev/null
+++ b/pic/pic.go
@@ -0,0 +1,37 @@
+// Copyright 2010 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.
+
+package pic
+
+import (
+ "bytes"
+ "encoding/base64"
+ "image"
+ "image/png"
+ "fmt"
+)
+
+func Show(f func(int, int)[][]uint8) {
+ const (
+ dx = 256
+ dy = 256
+ )
+ data := f(dx, dy)
+ m := image.NewNRGBA(dx, dy)
+ for y := 0; y < dy; y++ {
+ for x := 0; x < dx; x++ {
+ v := data[y][x]
+ m.Pix[y*dy+x] = image.NRGBAColor{v, v, 255, 255}
+ }
+ }
+ ShowImage(m)
+}
+
+func ShowImage(m image.Image) {
+ var buf bytes.Buffer
+ png.Encode(&buf, m)
+ enc := make([]byte, base64.StdEncoding.EncodedLen(buf.Len()))
+ base64.StdEncoding.Encode(enc, buf.Bytes())
+ fmt.Println("IMAGE:" + string(enc))
+}
diff --git a/static/index.html b/static/index.html
new file mode 100644
index 0000000..d418407
--- /dev/null
+++ b/static/index.html
@@ -0,0 +1,1711 @@
+<!--
+TODO
+
+Finish slides.
+Table of contents or some other navigation.
+Fix infinite loop behavior.
+-->
+
+<link href='http://fonts.googleapis.com/css?family=Droid+Serif&v1' rel='stylesheet' type='text/css'>
+<link href='http://fonts.googleapis.com/css?family=Droid+Sans&v1' rel='stylesheet' type='text/css'>
+<link href='http://fonts.googleapis.com/css?family=Droid+Sans+Mono&v1' rel='stylesheet' type='text/css'>
+<link rel="stylesheet" href="tour.css" charset="utf-8">
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
+<script src="tour.js"></script>
+
+<h2 class="slidenum" id="num"></h2>
+<h1>A Tour of Go</h1>
+<div class="slides">
+
+<div class="toc">Introduction</div>
+
+<div class="slide">
+ <h2>Hello, 世界</h2>
+ <p>
+ Welcome to a tour of the Go programming language.
+ <p>
+ To run this program, click the Compile button (or type Shift-Enter).
+ <p>
+ The programs in the tour are meant to be starting points for your own experimentation.
+ Edit the program and run it again.
+<div>
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hello, 世界")
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Hey</h2>
+ <p>
+ Now that the formalities are over, we can look at what's going on.
+ When you type Shift-Enter, your computer compiles and runs the
+ program and displays the result below.
+ <p>
+ Example programs demonstrate different aspects of Go.
+ Play with them to try new things and explore the language.
+ <p>
+ Whenever you're ready to move on, click the Next button or type the PageDown key.
+<div>
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hey")
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Imports</h2>
+ <p>
+ This program shows a factored import statement.
+ You can also write multiple import statements, like:
+ <pre>
+ import "fmt"
+ import "math"
+ </pre>
+ but it's common to use the factored form to eliminate clutter.
+<div>
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+func main() {
+ fmt.Printf("Now you have %g problems.",
+ math.Nextafter(2, 3))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Packages</h2>
+ <p>
+ Every Go program is made up of packages.
+ <p>
+ Programs start running in package <code>main</code>.
+ <p>
+ This program is using the packages with import paths
+ <code>"fmt"</code> and <code>"math"</code>.
+ <p>
+ By convention, the package name is the same as the
+ last element of the import path.
+<div>
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+func main() {
+ fmt.Println("Happy", math.Pi, "Day")
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Exported names</h2>
+ <p>
+ After importing a package, you can refer to the names it exports.
+ <p>
+ In Go, a name is exported if it begins with a capital letter.
+ <p>
+ <code>Pi</code> is an exported name; so is <code>PI</code>; not <code>pi</code>.
+<div>
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+func main() {
+ fmt.Println(math.pi)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Functions</h2>
+ <p>
+ A function can take zero or more arguments.
+ <p>
+ In this example, <code>add</code> takes two parameters of type <code>int</code>.
+ <p>
+ Notice that the type comes <i>after</i> the variable name.
+<div>
+package main
+
+import "fmt"
+
+func add(x int, y int) int {
+ return x + y
+}
+
+func main() {
+ fmt.Println(add(42, 13))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Functions</h2>
+ <p>
+ When two or more consecutive function parameters share a type,
+ you can omit the type from all but the last.
+ <p>
+ In this example, we shortened <code>x int, y int</code> to <code>x, y int</code>.
+<div>
+package main
+
+import "fmt"
+
+func add(x, y int) int {
+ return x + y
+}
+
+func main() {
+ fmt.Println(add(42, 13))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Functions</h2>
+ <p>
+ A function can return zero or more results.
+ <p>
+ This function returns two strings.
+<div>
+package main
+
+import "fmt"
+
+func swap(x, y string) (string, string) {
+ return y, x
+}
+
+func main() {
+ fmt.Println(swap("hello", "world"))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Functions</h2>
+ <p>
+ Function results can be named, in which case a
+ <code>return</code> statement without arguments
+ returns the current values of the results.
+<div>
+package main
+
+import "fmt"
+
+func split(sum int) (x, y int) {
+ x = sum * 4/9
+ y = sum - x
+ return
+}
+
+func main() {
+ fmt.Println(split(17))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Variables</h2>
+ <p>
+ The <code>var</code> statement declares a list of variables;
+ like in function argument lists, the type is last.
+ <p>
+ (For more about why types look the way they do, see <a target="_blank" href="http://blog.golang.org/2010/07/gos-declaration-syntax.html">this blog post</a>.)
+
+<div>
+package main
+
+import "fmt"
+
+var x, y, z int
+var c, python, java bool
+
+func main() {
+ fmt.Println(x, y, z, c, python, java)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Variables</h2>
+ <p>
+ A var declaration can include initializers, one per variable.
+ <p>
+ If an initializer is present, the type can be omitted;
+ the variable will take the type of the initializer.
+<div>
+package main
+
+import "fmt"
+
+var x, y, z int = 1, 2, 3
+var c, python, java = true, false, "no way!"
+
+func main() {
+ fmt.Println(x, y, z, c, python, java)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Variables</h2>
+ <p>
+ Inside a function, the <code>:=</code> short assignment statement
+ can be used in place of the short <code>var</code> declaration.
+<div>
+package main
+
+import "fmt"
+
+func main() {
+ var x, y, z int = 1, 2, 3
+ c, python, java := true, false, "certainly not"
+
+ fmt.Println(x, y, z, c, python, java)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Constants</h2>
+ <p>
+ Constants are declared like variables, but with the <code>const</code> keyword.
+<div>
+package main
+
+import "fmt"
+
+const Beta = 'β'
+
+const (
+ Pi = 3.14
+ World = "世界"
+)
+
+func main() {
+ fmt.Println("Hello", World)
+ fmt.Println("Happy", Pi, "Day")
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Constants</h2>
+ <p>
+ Constants are high-precision <i>values</i>: numbers and strings.
+ <p>
+ An untyped constant takes the type needed by its context.
+ <p>
+ Try printing <code>needInt(Big)</code> too.
+
+<div>
+package main
+
+import "fmt"
+
+const (
+ Big = 1<<100
+ Small = Big>>99
+)
+
+func needInt(x int) int { return x*10 + 1 }
+func needFloat(x float64) float64 { return x*0.1 }
+
+func main() {
+ fmt.Println(needInt(Small),
+ needFloat(Small), needFloat(Big))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>For</h2>
+ <p>
+ Go has a single looping construct, the <code>for</code> loop.
+ <p>
+ The basic <code>for</code> loop looks like it does in C or Java,
+ except that the <code>( )</code> are gone and the <code>{ }</code> are required.
+<div>
+package main
+
+import "fmt"
+
+func main() {
+ sum := 0
+ for i := 0; i < 10; i++ {
+ sum += i
+ }
+ fmt.Println(sum)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>For</h2>
+ <p>
+ Like in C or Java, you can leave the pre and post statements empty.
+<div>
+package main
+
+import "fmt"
+
+func main() {
+ sum := 1
+ for ; sum < 1000; {
+ sum += sum
+ }
+ fmt.Println(sum)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>For</h2>
+ <p>
+ At that point you can drop the semicolons:
+ C's <code>while</code> is spelled <code>for</code> in Go.
+<div>
+package main
+
+import "fmt"
+
+func main() {
+ sum := 1
+ for sum < 1000 {
+ sum += sum
+ }
+ fmt.Println(sum)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>For</h2>
+ <p>
+ If you omit the loop condition, it loops forever.
+<div>
+package main
+
+func main() {
+ for ; ; {
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>For</h2>
+ <p>
+ Like before, you can drop the semicolons.
+<div>
+package main
+
+func main() {
+ for {
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>If</h2>
+ <p>
+ The <code>if</code> statement looks like it does in C or Java,
+ except that the <code>( )</code> are gone and the <code>{ }</code> are required.
+ (Sound familiar?)
+<div>
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+func sqrt(x float64) string {
+ if x < 0 {
+ return sqrt(-x) + "i"
+ }
+ return fmt.Sprint(math.Sqrt(x))
+}
+
+func main() {
+ fmt.Println(sqrt(2), sqrt(-4))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>If</h2>
+ <p>
+ Like <code>for</code>, the <code>if</code> statement can start with a short
+ statement to execute before the condition.
+ <p>
+ Variables declared by the statement are only in scope until the end of the <code>if</code>.
+ (Try adding <code>neg</code> to the <code>fmt.Sprint</code> call.)
+<div>
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+func sqrt(x float64) string {
+ if neg := math.Signbit(x); neg {
+ return sqrt(-x) + "i"
+ }
+ return fmt.Sprint(math.Sqrt(x))
+}
+
+func main() {
+ fmt.Println(sqrt(2), sqrt(-4))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Basic types</h2>
+ <p>
+ Go's basic types are
+ <pre>
+ bool
+ string
+ int int8 int16 int32 int64
+ uint uint8 uint16 uint32 uint64
+ float32 float64
+ complex64 complex128
+ </pre>
+<div>
+package main
+
+import (
+ "cmath"
+ "fmt"
+)
+
+var (
+ ToBe bool = false
+ MaxInt uint64 = 1<<64 - 1
+ z complex128 = cmath.Sqrt(-5+12i)
+)
+
+func main() {
+ fmt.Printf("%T(%v) %T(%v) %T(%v)\n",
+ ToBe, ToBe,
+ MaxInt, MaxInt,
+ z, z,
+ )
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Structs</h2>
+ <p>
+ A <code>struct</code> is a collection of fields.
+ <p>
+ (And a <code>type</code> declaration does what you'd expect.)
+<div>
+package main
+
+import "fmt"
+
+type Point struct {
+ X int
+ Y int
+}
+
+func main() {
+ fmt.Println(Point{1, 2})
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Pointers</h2>
+ <p>
+ Go has pointers, but no pointer arithmetic.
+<div>
+package main
+
+import "fmt"
+
+type Point struct {
+ X int
+ Y int
+}
+
+func main() {
+ p := Point{1, 2}
+ q := &p
+ q.X = 1e9
+ fmt.Println(p)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Struct Literals</h2>
+ <p>
+ A struct literal denotes a struct value by listing the values
+ of its fields.
+ <p>
+ You can list just a few fields by using the <code>Name:</code> syntax.
+ <p>
+ The special prefix <code>&</code> constructs a pointer to a struct literal.
+<div>
+package main
+
+import "fmt"
+
+type Point struct {
+ X, Y int
+}
+
+var (
+ p = Point{1, 2} // has type Point
+ q = &Point{1, 2} // has type *Point
+ r = Point{X: 1} // Y:0 is implicit
+ s = Point{} // X:0 and Y:0 are implicit
+)
+
+func main() {
+ fmt.Println(p, q, r, s)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Maps</h2>
+ <p>
+ A map maps keys to values.
+ <p>
+ <!-- TODO: empty part not true in compilers yet -->
+ Maps must be created with <code>make</code> before use; the <code>nil</code> map is empty
+ and cannot be assigned to.
+<div>
+package main
+
+import "fmt"
+
+type Point struct {
+ Lat, Long float64
+}
+
+var m map[string]Point
+
+func main() {
+ m = make(map[string]Point)
+ m["Bell Labs"] = Point{40.68433, 74.39967}
+ fmt.Println(m["Bell Labs"])
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Maps</h2>
+ <p>
+ Map literals are like struct literals, but the keys are required.
+<div>
+package main
+
+import "fmt"
+
+type Point struct {
+ Lat, Long float64
+}
+
+var m = map[string]Point{
+ "Bell Labs": Point{40.68433, -74.39967},
+ "Google": Point{37.42202, -122.08408},
+}
+
+func main() {
+ fmt.Println(m)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Slices</h2>
+ <p>
+ A slice points at an array of values and also includes a length.
+<div>
+package main
+
+import "fmt"
+
+type Point struct {
+ Lat, Long float64
+}
+
+var places = []Point{
+ Point{40.68433, -74.39967},
+ Point{37.42202, -122.08408},
+}
+
+var empty []Point
+
+var five = make([]Point, 5)
+
+func main() {
+ fmt.Println("Empty: ", len(empty), empty)
+ fmt.Println("Five: ", len(five), five)
+ fmt.Println("Places:", len(places), places)
+
+ primes := []int{2, 3, 5, 7, 11, 13}
+ fmt.Println("Primes:", primes)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Functions</h2>
+ <p>
+ Functions are values too.
+<div>
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+func main() {
+ hypot := func(x, y float64) float64 {
+ return math.Sqrt(x*x + y*y)
+ }
+
+ fmt.Println(hypot(3, 4))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Functions</h2>
+ <p>
+ And functions are full closures.
+<div>
+package main
+
+import "fmt"
+
+func adder() func(int) int {
+ sum := 0
+ return func(x int) int {
+ sum += x
+ return sum
+ }
+}
+
+func main() {
+ pos, neg := adder(), adder()
+
+ for i := 0; i < 10; i++ {
+ fmt.Println(i, pos(i), neg(-2*i))
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Range</h2>
+ <p>
+ The <code>range</code> form of the <code>for</code>
+ loop iterates over a slice or map.
+<div>
+package main
+
+import "fmt"
+
+var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
+
+func main() {
+ for key, value := range pow {
+ fmt.Printf("2^%d = %d\n", key, value)
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Range</h2>
+ <p>
+ You can skip the key or value by assigning to <code>_</code>.
+ <p>
+ You can also drop the “<code>, value</code>” entirely.
+<div>
+package main
+
+import "fmt"
+
+func main() {
+ pow := make([]int, 10)
+ for i := range pow {
+ pow[i] = 1<<uint(i)
+ }
+ for _, value := range pow {
+ fmt.Printf("%d\n", value)
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Switch</h2>
+ <p>
+ You probably knew what <code>switch</code> was going to look like.
+ <p>
+ A case body breaks automatically, unless it ends with a <code>fallthrough</code> statement.
+
+<div>
+package main
+
+import (
+ "fmt"
+ "runtime"
+)
+
+func main() {
+ switch os := runtime.GOOS; os {
+ case "darwin":
+ fmt.Printf("Go runs on OS X.\n")
+ case "freebsd":
+ fmt.Printf("Go runs on FreeBSD.\n")
+ case "linux":
+ fmt.Printf("Go runs on Linux.\n")
+ case "plan9":
+ fmt.Printf("Go runs on Plan 9.\n")
+ case "windows":
+ fmt.Printf("Go runs on Windows.\n")
+ default:
+ fmt.Printf("I forgot %s.\n", os)
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Switch</h2>
+ <p>
+ Switch cases don't have to be constants; the first match wins.
+
+<div>
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func main() {
+ today := time.LocalTime().Weekday
+ switch 6 {
+ case today+0:
+ fmt.Println("It's Saturday.")
+ case today+1:
+ fmt.Println("Tomorrow's Saturday.")
+ case today+2:
+ fmt.Println("Two days to Saturday.")
+ default:
+ fmt.Println("Saturday is too far away.")
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Switch</h2>
+ <p>
+ Switch without a condition is the same as <code>switch true</code>.
+
+<div>
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func main() {
+ t := time.LocalTime()
+ switch {
+ case t.Hour < 12:
+ fmt.Println("Good morning!")
+ case t.Hour < 17:
+ fmt.Println("Good afternoon.")
+ default:
+ fmt.Println("Good evening.")
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Exercise: Loops and Functions</h2>
+ <p>
+ As a simple way to play with functions and loops, implement
+ the square root function using Newton's method.
+ <p>
+ In this case, Newton's method is to approximate <code>Sqrt(x)</code>
+ by picking a starting point <i>z</i> and then repeating:
+ <center>
+ <img src="https://chart.googleapis.com/chart?cht=tx&chl=z=z-\frac{z^2-x}{2x}">
+ </center>
+ <p>
+ To begin with, just repeat that calculation 10 times and see how close you
+ get to the answer for various values (1, 2, 3, ...).
+ <p>
+ Next, change the loop condition to stop once the value has stopped changing.
+ See if that's more or fewer iterations.
+ How close are you to the <a target="_blank" href="http://golang.org/pkg/math/#Sqrt">math.Sqrt</a>?
+ <p>
+ Hint: to declare and initialize a floating point value, give it
+ floating point syntax or use a conversion:
+ <pre>
+ z := float64(0)
+ z := 0.0
+ </pre>
+
+<div>
+package main
+
+import (
+ "fmt"
+)
+
+func Sqrt(x float64) float64 {
+}
+
+func main() {
+ fmt.Println(Sqrt(2))
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Exercise: Maps</h2>
+ <p>
+ Implement <code>WordCount</code>. It should return a map of the
+ counts of each “word” in the string <code>s</code>.
+ With the binary running, visit <a target="_blank" href="http://localhost:4000/">this page</a>
+ to count words interactively.
+ <p>
+ You might find <a target="_blank" href="http://golang.org/pkg/strings/#Fields">strings.Fields</a> helpful.
+
+<div>
+package main
+
+import (
+ "go-tour.googlecode.com/hg/wc"
+)
+
+func WordCount(s string) map[string]int {
+ return map[string]int{"x": 1}
+}
+
+func main() {
+ wc.Serve(WordCount)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Exercise: Slices</h2>
+ <p>
+ Implement <code>Pic</code>. It should return a slice of length <code>dy</code>,
+ each element of which is a slice of <code>dx</code> 8-bit unsigned integers.
+ When you run the program, it will display your picture, interpreting the
+ integers as grayscale (well, bluescale) values.
+ <p>
+ The choice of image is up to you.
+ Interesting functions include <code>x^y</code>, <code>(x+y)/2</code>, and <code>x*y</code>.
+
+<div>
+package main
+
+import "go-tour.googlecode.com/hg/pic"
+
+func Pic(dx, dy int) [][]uint8 {
+}
+
+func main() {
+ pic.Show(Pic)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Advanced Exercise: Complex cube roots</h2>
+ <p>
+ Let's explore Go's built-in support for complex numbers via the
+ <code>complex64</code> and <code>complex128</code> types.
+ For cube roots, Newton's method amounts to repeating:
+ <center>
+ <img src="https://chart.googleapis.com/chart?cht=tx&chl=z=z-\frac{z^3-x}{3x^2}">
+ </center>
+ <p>
+ Find the cube root of 2, just to make sure the algorithm works.
+ There is a <a target="_blank" href="http://golang.org/pkg/cmath/#Pow">cmath.Pow</a> function.
+
+<div>
+package main
+
+import "fmt"
+
+func Cbrt(x complex128) complex128 {
+}
+
+func main() {
+ fmt.Println(Cbrt(2))
+}
+</div>
+</div>
+
+
+<div class="slide">
+ <h2>Advanced Exercise: High Precison</h2>
+ <p>
+ <a target="_blank" href="http://golang.org/pkg/big/">Package big</a>
+ implements arbitrary precision integer arithmetic.
+ Convert your square root program to work in fixed point arithmetic
+ for some number of decimal places <code>P</code> and then compute
+ 50 digits of the square of 2. Double check them against the
+ constant listed in the <a target="_blank" href="http://golang.org/pkg/math/">package math documentation</a>.
+
+<div>
+package main
+
+func main() {
+}
+</div>
+</div>
+
+<div class="toc">Methods and Interfaces</div>
+
+<div class="slide nocode">
+<h2>Methods and Interfaces</h2>
+</div>
+
+<div class="slide">
+ <h2>Methods</h2>
+ <p>
+ Methods can be associated with any named type,
+ but only the package that defines a type can
+ define methods on it.
+
+ <p>
+ The <i>method receiver</i> appears in its own argument list
+ between the <code>func</code> keyword and the method name.
+
+<div>
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+type Point struct {
+ X, Y float64
+}
+
+func (p *Point) Abs() float64 {
+ return math.Sqrt(p.X*p.X + p.Y*p.Y)
+}
+
+func main() {
+ p := &Point{3, 4}
+ fmt.Println(p.Abs())
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Methods</h2>
+ <p>
+ Methods can be associated with <i>any</i> named type.
+
+<div>
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+type MyFloat float64
+
+func (f MyFloat) Abs() float64 {
+ if f < 0 {
+ return float64(-f)
+ }
+ return float64(f)
+}
+
+func main() {
+ f := MyFloat(-math.Sqrt2)
+ fmt.Println(f.Abs())
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Interfaces</h2>
+ <p>
+ An interface type is defined by a set of methods.
+ <p>
+ A value of interface type can hold any value that
+ implements those methods.
+
+<div>
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+type Abser interface {
+ Abs() float64
+}
+
+func main() {
+ var (
+ a Abser
+ f = MyFloat(-math.Sqrt2)
+ p = Point{3, 4}
+ )
+
+ a = f // f, a MyFloat, implements Abser
+ a = &p // &p, a *Point, implements Abser
+ a = p // p, a Point, does NOT implement Abser
+
+ fmt.Println(a.Abs())
+}
+
+
+
+
+
+
+
+
+
+
+
+type MyFloat float64
+
+func (f MyFloat) Abs() float64 {
+ if f < 0 {
+ return float64(-f)
+ }
+ return float64(f)
+}
+
+type Point struct {
+ X, Y float64
+}
+
+func (p *Point) Abs() float64 {
+ return math.Sqrt(p.X*p.X + p.Y*p.Y)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Interfaces</h2>
+ <p>
+ A type implements an interface by implementing the methods.
+ <p>
+ <i>There is no explicit declaration of intent.</i>
+ <p>
+ This decouples implementation packages from the packages that define the interfaces:
+ neither depends on the other.
+ <p>
+ It also encourages the definition of precise interfaces,
+ because you don't have to find every implementation and tag it with the new interface name.
+ <p>
+ <a href="http://golang.org/pkg/io/">Package io</a> defines <code>Reader</code> and <code>Writer</code>; you don't have to.
+
+<div>
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+type Reader interface {
+ Read(b []byte) (n int, err os.Error)
+}
+
+type Writer interface {
+ Write(b []byte) (n int, err os.Error)
+}
+
+type ReadWriter interface {
+ Reader
+ Writer
+}
+
+func main() {
+ var w Writer
+ w = os.Stdout // os.Stdout implements our interface
+ fmt.Fprintf(w, "hello, writer\n")
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Errors</h2>
+ <p>
+ An error is anything that can describe itself:
+ <pre>
+ package os
+
+ type Error interface {
+ String() string
+ }
+ </pre>
+
+<div>
+package main
+
+import (
+ "fmt"
+ "time"
+ "os"
+)
+
+type MyError struct {
+ When *time.Time
+ What string
+}
+
+func (e *MyError) String() string {
+ return "at " + e.When.String() + ", " + e.What
+}
+
+func run() os.Error {
+ return &MyError{time.LocalTime(), "it didn't work"}
+}
+
+func main() {
+ if err := run(); err != nil {
+ fmt.Println(err)
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Web servers</h2>
+ <p>
+ <a href="http://golang.org/pkg/http/">Package http</a> serves HTTP requests using any value
+ that implements <code>http.Handler</code>:
+ <pre>
+ package http
+
+ type Handler interface {
+ ServeHTTP(w ResponseWriter, req *Request)
+ }
+ </pre>
+ <p>
+ In this example, the type <code>MyHandler</code> implements <code>http.Handler</code>.
+ <p>
+ Visit <a href="http://localhost:4000/" target="_blank">http://localhost:4000/</a> to see the greeting.
+<div>
+package main
+
+import (
+ "fmt"
+ "http"
+ "log"
+)
+
+type MyHandler struct{}
+
+func (h MyHandler) ServeHTTP(w http.ResponseWriter,
+ r *http.Request) {
+ fmt.Fprint(w, "Hello!")
+}
+
+func main() {
+ var h MyHandler
+ err := http.ListenAndServe("localhost:4000", h)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Images</h2>
+ <p>
+ <a href="http://golang.org/pkg/image/#Image">Package image</a> defines the <code>Image</code>
+ interface:
+ <pre>
+package image
+
+type Image interface {
+ <span>// ColorModel returns the Image's ColorModel.</span>
+ ColorModel() ColorModel
+
+ <span>// Bounds returns the domain for which At can return non-zero color.</span>
+ <span>// The bounds do not necessarily contain the point (0, 0).</span>
+ Bounds() Rectangle
+
+ <span>// At returns the color of the pixel at (x, y).</span>
+ <span>// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.</span>
+ <span>// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.</span>
+ At(x, y int) Color
+}</pre>
+ <p>
+ <code>Color</code> and <code>ColorModel</code> are interfaces too,
+ but we'll ignore that by using the predefined implementations
+ <code>image.RGBAColor</code> and <code>image.RGBAColorModel</code>.
+
+<div>
+package main
+
+import (
+ "fmt"
+ "image"
+)
+
+func main() {
+ m := image.NewRGBA(100, 100)
+ fmt.Println(m.Bounds())
+ fmt.Println(m.At(0, 0).RGBA())
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Exercise: Hello, world 2.0</h2>
+ <p>
+ Implement an <code>http.Handler</code> that responds to every request by saying
+<pre> Hello, <i>name</i></pre>
+ <p>
+ where <i>name</i> is the value of the request parameter <code>name</code>.
+ <p>
+ For example, <a target="_blank"
+ href="http://localhost:4000/?name=Joe">http://localhost:4000/?name=Joe</a>
+ should display
+<pre> Hello, Joe</pre>
+ <p>
+ Hint: use the <code><a href="http://golang.org/pkg/http/#Request.FormValue"
+ target="_blank">FormValue</a></code> method of
+ <code>*http.Request</code> to access the request parameters.
+<div>
+package main
+
+import (
+ "http"
+)
+
+func main() {
+ var h http.Handler = // your value here
+ http.ListenAndServe("localhost:4000", h)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Exercise: HTTP Handlers</h2>
+ <p>
+ Implement the following types and define ServeHTTP methods on them.
+ Register them to handle specific paths in your web server.
+<pre>type String string
+
+type Struct struct {
+ Greeting string
+ Punct string
+ Who string
+}</pre>
+ <p>
+ For example, you should be able to register handlers using:
+<pre>http.Handle("/string", String("I'm a frayed knot."))
+http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})</pre>
+<div>
+package main
+
+import (
+ "http"
+)
+
+func main() {
+ // your http.Handle calls here
+ http.ListenAndServe("localhost:4000", nil)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Exercise: Images</h2>
+ <p>
+ Remember the picture generator you wrote earlier?
+ Let's write another one, but this time it will return
+ an implementation of <code>image.Image</code> instead of a slice of data.
+ <p>
+ Define your own <code>Image</code> type, implement
+ <a href="http://golang.org/pkg/image/#Image" target="_blank">the necessary methods</a>,
+ and call <code>pic.ShowImage</code>.
+ <p>
+ <code>Bounds</code> should return a <code>image.Rectangle</code>, like
+ <code>image.Rect(0, 0, w, h)</code>.
+ <p>
+ <code>ColorModel</code> should return <code>image.RGBAColorModel</code>.
+ <p>
+ <code>At</code> should return a color;
+ the value <code>v</code> in the last picture generator corresponds to
+ <code>image.RGBAColor{v, v, 255, 255}</code> in this one.
+
+<div>
+package main
+
+import (
+ "image"
+ "go-tour.googlcode.com/hg/pic"
+)
+
+func main() {
+ m := ... my image
+ pic.ShowImage(m)
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Exercise: Images</h2>
+ <p>
+ Let's eliminate some more scaffolding.
+<div>
+</div>
+</div>
+
+
+<div class="toc">Concurrency</div>
+
+<div class="slide nocode">
+<h2>Concurrency</h2>
+</div>
+
+<div class="slide">
+ <h2>Goroutines</h2>
+
+ <p><code>go f(x, y, z)</code> starts a new goroutine running <code>f(x,
+ y, z)</code>. The evaluation
+ of <code>f</code>, <code>x</code>, <code>y</code>, and <code>z</code>
+ happens in the current goroutine. After they are evaluated, a new goroutine
+ is created and it calls <code>f</code> with those arguments.
+
+ <p>Goroutines share memory, so access to shared memory must be
+ synchronized. The <code>sync</code> package provides useful primitives.
+<div>
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func say(s string) {
+ for i := 0; i < 5; i++ {
+ time.Sleep(100e6)
+ fmt.Println(s)
+ }
+}
+
+func main() {
+ go say("world")
+ say("hello")
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Channels</h2>
+
+<p>
+Channels are typed message buffers with send and receive.
+
+<p>Like maps and slices, channels must be created before use:
+<pre>
+ch := make(chan int, 100)
+</pre>
+
+<p>This channel has room for 100 ints in its buffer. Sends block when the
+buffer is full. Receives block when there's nothing available. This allows
+goroutines to synchronize without explicit locks or condition variables.
+
+<p>If the second arg to <code>make</code> is omitted or zero, the channel is
+ unbuffered. Sends to an unbuffered channel block until another goroutine
+ receives from that channel, and receives block until a value is sent.
+
+<p>The built-in function <code>cap(ch)</code> returns the size
+of <code>ch</code>'s buffer; <code>len(ch)</code> returns the number of elements
+in the buffer ready to be received.
+
+<div>
+package main
+
+import (
+ "fmt"
+)
+
+func sum(a []int, c chan int) {
+ res := 0
+ for _, v := range a {
+ res += v
+ }
+ c <- res
+}
+
+func main() {
+ a := []int{7, 2, 8, -9, 4, 0}
+
+ c := make(chan int)
+ go sum(a[:len(a)/2], c)
+ go sum(a[len(a)/2:], c)
+ x, y := <-c, <-c
+
+ fmt.Println(x, y, x + y)
+}
+</div>
+</div>
+
+
+<div class="slide">
+ <h2>Range and Close</h2>
+
+<p>A sender can <code>close</code> a channel to indicate that no more values
+will be sent. Receivers can test whether a channel has been closed by assigning
+ a second parameter to the receive expression: in <code>v, ok :=
+ <-ch</code>, <code>ok</code> is <code>false</code> if <code>ch</code> is closed.
+
+<p>The loop <code>for i := range c</code> receives values from the channel
+repeatedly until it is closed.
+
+<p>Note: Only the sender should close a channel, never the receiver.
+<div>
+package main
+
+import (
+ "fmt"
+)
+
+func fibonacci(n int, c chan int) {
+ x, y := 1, 1
+ for i := 0; i < n; i++ {
+ c <- x
+ x, y = y, x + y
+ }
+ close(c)
+}
+
+func main() {
+ c := make(chan int, 10)
+ go fibonacci(cap(c), c)
+ for i := range c {
+ fmt.Println(i)
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Select</h2>
+
+<p>The <code>select</code> statement lets a goroutine wait on multiple send or
+receive operations.
+
+<p>A <code>select</code> blocks until one of its cases can run, then it executes
+ that case. It chooses one at random if multiple are ready.
+
+<div>
+package main
+
+import (
+ "fmt"
+)
+
+func fibonacci(c, quit chan int) {
+ x, y := 1, 1
+ for {
+ select {
+ case c <- x:
+ x, y = y, x + y
+ case <-quit:
+ return
+ }
+ }
+}
+
+func main() {
+ c, quit := make(chan int), make(chan int)
+ go fibonacci(c, quit)
+ for i := 0; i < 10; i++ {
+ fmt.Println(<-c)
+ }
+ quit <- 0
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Default Selection</h2>
+
+<p>A <code>default</code> case in a <code>select</code> can always run.
+
+<p>Use a <code>default</code> case to try a send or receive without blocking:
+<pre>
+select {
+case i := <-c:
+ // use i
+default:
+ // receiving from c would block
+}
+</pre>
+
+<div>
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func main() {
+ tick := time.Tick(1e8)
+ boom := time.After(5e8)
+ for {
+ select {
+ case <-tick:
+ fmt.Println("tick.")
+ case <-boom:
+ fmt.Println("BOOM!")
+ return
+ default:
+ fmt.Println(" .")
+ time.Sleep(5e7)
+ }
+ }
+}
+</div>
+</div>
+
+<div class="slide">
+ <h2>Exercise: Web Crawler</h2>
+ <p>
+
+<p>Change <code>Crawl</code> to run each call to <code>fetcher.Fetch</code> in
+its own goroutine and avoid fetching the same URL twice.
+<div>
+package main
+
+import (
+ "os"
+ "fmt"
+)
+
+type Fetcher interface {
+ // Fetch returns the contents of url and a slice
+ // of URLs on that page that may be crawled.
+ // It returns an error if url was not found or the fetch failed.
+ Fetch(url string) (contents string, urls []string, err os.Error)
+}
+
+// Crawl fetches pages recursively starting from url to depth using fetcher.
+func Crawl(url string, depth int, fetcher Fetcher) {
+ // TODO(you): Run each call to fetcher.Fetch in its own goroutine.
+ // TODO(you): Don't fetch the same URL twice.
+ // This implementation doesn't do either:
+ if depth <= 0 {
+ return
+ }
+ contents, urls, err := fetcher.Fetch(url)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ fmt.Println(contents)
+ for _, u := range urls {
+ Crawl(u, depth-1, fetcher)
+ }
+ return
+}
+
+// Fake web of URLs for testing.
+type fakeResult struct {
+ contents string
+ urls []string
+}
+
+type fakeFetcher map[string]*fakeResult
+
+func (f *fakeFetcher) Fetch(url string) (contents string, urls []string, err os.Error) {
+ if res, ok := (*f)[url]; ok {
+ return res.contents, res.urls, nil
+ }
+ return "", nil, fmt.Errorf("not found: %s", url)
+}
+
+func main() {
+ fetcher := &fakeFetcher{
+ "http://golang.org": &fakeResult{
+ "The Go Programming Language",
+ []string{
+ "http://golang.org/pkg",
+ "http://golang.org/cmd",
+ },
+ },
+ "http://golang.org/pkg": &fakeResult{
+ "Packages",
+ []string{
+ "http://golang.org",
+ "http://golang.org/cmd",
+ "http://golang.org/pkg/fmt",
+ "http://golang.org/pkg/os",
+ },
+ },
+ "http://golang.org/pkg/fmt": &fakeResult{
+ "Package fmt",
+ []string{},
+ },
+ "http://golang.org/pkg/os": &fakeResult{
+ "Package os",
+ []string{},
+ },
+ }
+ Crawl("http://golang.org", 3, fetcher)
+}
+</div>
+</div>
+
+<div class="slide nocode">
+<h2>More here...</h2>
+</div>
+
+</div>
diff --git a/static/tour.css b/static/tour.css
new file mode 100644
index 0000000..1f82b18
--- /dev/null
+++ b/static/tour.css
@@ -0,0 +1,119 @@
+body {
+ font-family: 'Droid Serif', serif;
+ margin-left: 0px;
+ margin-right: 0px;
+ margin-top: 0px;
+ font-size: 120%;
+}
+.slides {
+ margin-left: 1em;
+ margin-right: 1em;
+ margin-top: 0px;
+}
+.slidenum {
+ float: right;
+ color: white;
+ padding: 5px;
+ margin: 0;
+}
+
+pre {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+pre span {
+ font-family: 'Droid Serif', serif;
+}
+
+h1, h2, h3 {
+ font-family: 'Droid Sans', sans-serif;
+ margin-top: 20px;
+}
+h1 {
+ color: #fff;
+ background-color: #444;
+ margin: 0px;
+ padding: 5px;
+}
+
+code, pre, textarea {
+ font-family: 'Droid Sans Mono', monospace;
+ font-size: 100%;
+}
+
+div.code {
+ border: 1px solid black;
+ float: left;
+ width: 45%;
+ height: 80%;
+ margin: 0px 1em 0px 0px;
+}
+
+textarea {
+ border: 0px;
+ display: block;
+ padding: 5px;
+
+ width: 100%;
+ height: 95%;
+ margin-top: 0px;
+}
+
+textarea:focus {
+ border: 0px;
+ outline: 0px;
+}
+
+.programoutput {
+ color: #0000cc;
+}
+
+.compileerrors {
+ color: #cc0000;
+}
+
+hr {
+ border: 1px solid #ccc;
+}
+
+button {
+ display: inline;
+ font-size: 60%;
+ font-family: 'Droid Sans', sans-serif;
+ color: #000;
+ background-color: #eee;
+ border-color: #000;
+ border-width: 1px;
+ padding: 3px;
+ margin: 3px;
+}
+
+button.next {
+ margin-left: 1em;
+}
+
+button:hover {
+ background-color: #fff;
+}
+
+div.nav {
+ display: block;
+ text-align: right;
+ float: right;
+}
+
+div.clear {
+ clear: right;
+}
+
+h2.nocode {
+ text-align: center;
+ font-size: 300%;
+ margin-bottom: 1em;
+}
+
+div.toc {
+ display: none;
+ visibility: hidden;
+}
diff --git a/static/tour.js b/static/tour.js
new file mode 100644
index 0000000..e39e2cd
--- /dev/null
+++ b/static/tour.js
@@ -0,0 +1,283 @@
+window.onload = init;
+
+var slides;
+var slide = null;
+var slidenum = 0;
+var codebox = null;
+var output = null;
+var errors = null;
+
+function findclass(el, name) {
+ var x = el.getElementsByClassName(name);
+ if (x.length == 0)
+ return null;
+ return x[0];
+}
+
+function initSlides() {
+ var $slides = $("div.slide");
+ $slides.each(function(i, slide) {
+ var $s = $(slide).hide();
+
+ var $code = null;
+ var $sdiv = $s.find("div");
+ if (!$s.hasClass("nocode") && $sdiv.length > 0) {
+ $code = $sdiv.last();
+ $code.remove();
+ }
+
+ var $h2 = $s.find("h2").first();
+ if ($h2.length > 0) {
+ $("<div/>").addClass("clear").insertAfter($h2);
+ var $nav = $("<div/>").addClass("nav")
+ if (i > 0) {
+ $nav.append($("<button>").click(function() {
+ show(i-1);
+ }).text("PREV").addClass("prev"));
+ }
+ if (i+1 < $slides.length) {
+ $nav.append($("<button>").click(function() {
+ show(i+1);
+ }).text("NEXT").addClass("next"));
+ }
+ $nav.insertBefore($h2);
+ }
+ if ($s.hasClass("nocode"))
+ $h2.addClass("nocode");
+
+ if ($code == null)
+ return;
+
+ var $codebox = $("<textarea/>").html($code.html().trim());
+ var $codenav = $("<div/>").addClass("nav");
+ $codenav.append($("<button>").click(function() {
+ compile($codebox[0]);
+ }).text("COMPILE").addClass("compile"));
+ $code.empty().addClass("code");
+ $code.append($codenav).append($codebox);
+ $s.prepend($code);
+
+ $s.append("<hr/>");
+ $s.append('<div class="compileerrors"/>')
+ $s.append('<div class="programoutput"/>')
+ });
+ return $slides;
+}
+
+function show(i) {
+ console.log("show", i);
+ if(i < 0 || i >= slides.length)
+ return;
+ if(slide != null) {
+ $(slide).hide();
+ }
+ document.onkeydown = null;
+ if(codebox != null) {
+ codebox.onkeydown = null;
+ codebox.onkeyup = null;
+ }
+ slidenum = i;
+
+ $("#num").text(i+1);
+
+ var url = location.href;
+ var j = url.indexOf("#");
+ if(j >= 0)
+ url = url.substr(0, j);
+ url += "#" + (slidenum+1).toString();
+ location.href = url;
+
+ slide = slides[i];
+ $(slide).show();
+ if ($(slide).hasClass("nocode")) {
+ setTimeout(function() {
+ document.onkeydown = pageUpDown;
+ }, 1);
+ return;
+ }
+ var $code = $("div.code", slide);
+ if ($code.length == 0)
+ return;
+ codebox = $code.find("textarea")[0];
+ if (codebox != null) {
+ codebox.spellcheck = false;
+ codebox.onkeydown = keyDown;
+ codebox.onkeyup = keyUp;
+ codebox.focus();
+ document.onclick = null;
+ }
+ output = $("div.programoutput", slide)[0];
+ errors = $("div.compileerrors", slide)[0];
+ document.onclick = function() { codebox.focus(); }
+}
+
+function urlSlideNumber(url) {
+ var i = url.indexOf("#");
+ if(i < 0)
+ return 0;
+ var frag = unescape(url.substr(i+1));
+ if(/^\d+$/.test(frag)) {
+ i = parseInt(frag);
+ if(i-1 < 0 || i-1 >= slides.length)
+ return 0;
+ return i-1;
+ }
+ return 0;
+}
+
+function insertTabs(cont, n) {
+ // find the selection start and end
+ var start = cont.selectionStart;
+ var end = cont.selectionEnd;
+ // split the textarea content into two, and insert n tabs
+ var v = cont.value;
+ var u = v.substr(0, start);
+ for (var i=0; i<n; i++) {
+ u += "\t";
+ }
+ u += v.substr(end);
+ // set revised content
+ cont.value = u;
+ // reset caret position after inserted tabs
+ cont.selectionStart = start+n;
+ cont.selectionEnd = start+n;
+}
+
+function autoindent(el) {
+ var curpos = el.selectionStart;
+ var tabs = 0;
+ while (curpos > 0) {
+ curpos--;
+ if (el.value[curpos] == "\t") {
+ tabs++;
+ } else if (tabs > 0 || el.value[curpos] == "\n") {
+ break;
+ }
+ }
+ setTimeout(function() {
+ insertTabs(el, tabs);
+ }, 1);
+}
+
+var keySeq = 0;
+var keyWaiting = false;
+
+function keyDown(event) {
+ var e = window.event || event;
+ if (e.keyCode == 9) { // tab
+ insertTabs(e.target, 1);
+ e.preventDefault();
+ return false;
+ }
+ if (e.keyCode == 13) { // enter
+ if (e.shiftKey) {
+ compile(e.target);
+ e.preventDefault();
+ return false;
+ }
+ autoindent(e.target);
+ }
+ if (e.keyCode == 33) { // page up
+ e.preventDefault();
+ show(slidenum-1);
+ return false;
+ }
+ if (e.keyCode == 34) { // page down
+ e.preventDefault();
+ show(slidenum+1);
+ return false;
+ }
+ return true;
+}
+
+function pageUpDown(event) {
+ var e = window.event || event;
+ if (e.keyCode == 33) { // page up
+ e.preventDefault();
+ show(slidenum-1);
+ return false;
+ }
+ if (e.keyCode == 34) { // page down
+ e.preventDefault();
+ show(slidenum+1);
+ return false;
+ }
+ return true;
+}
+
+var autocompile = false;
+
+function keyUp(event) {
+ var e = window.event || event;
+ keySeq++;
+ if(!autocompile || codebox == null)
+ return;
+ if (!keyWaiting) {
+ var seq = keySeq;
+ keyWaiting = true;
+ setTimeout(function() { keyTimeout(seq, 50); }, 50)
+ }
+}
+
+var waitTime = 200; // wait 200 ms before compiling
+
+function keyTimeout(seq, n) {
+ ks1 = seq;
+ ks2 = n;
+ if (keySeq != seq) {
+ seq = keySeq;
+ setTimeout(function() { keyTimeout(seq, 50); }, 50)
+ return;
+ }
+ if (n < waitTime) {
+ setTimeout(function() { keyTimeout(seq, n+50); }, 50)
+ return;
+ }
+ keyWaiting = false;
+ if (codebox != null)
+ compile(codebox);
+}
+
+var compileSeq = 0;
+
+function compile(el) {
+ var prog = $(el).val();
+ var req = new XMLHttpRequest();
+ var seq = compileSeq++;
+ req.onreadystatechange = function() { compileUpdate(req, seq); }
+ req.open("POST", "/compile", true);
+ req.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
+ req.send(prog);
+ if (output) {
+ var seq = compileSeq;
+ if (errors)
+ errors.innerHTML = "";
+ output.innerHTML = "";
+ setTimeout(function() {
+ if (seq == compileSeq) {
+ output.innerHTML = "running...";
+ }
+ }, 1000);
+ }
+}
+
+function compileUpdate(req, seq) {
+ if(!req || req.readyState != 4 || compileSeq != seq)
+ return;
+ var out = req.responseText;
+ var err = "";
+ if(req.status != 200) {
+ err = out;
+ out = "";
+ }
+ if (output)
+ output.innerHTML = out;
+ if (errors)
+ errors.innerHTML = err;
+ compileSeq++;
+}
+
+function init() {
+ slides = initSlides();
+ show(urlSlideNumber(location.href));
+}
diff --git a/wc/wc.go b/wc/wc.go
new file mode 100644
index 0000000..c7755c1
--- /dev/null
+++ b/wc/wc.go
@@ -0,0 +1,161 @@
+// Copyright 2010 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.
+
+package wc
+
+import (
+ "bytes"
+ "fmt"
+ "http"
+ "io"
+ "log"
+ "sort"
+ "template"
+ "runtime/debug"
+)
+
+func frontPageHandler(c http.ResponseWriter, req *http.Request) {
+ frontPage.Execute(c, "a man a plan a canal panama")
+}
+
+var wcFunc func(string)map[string]int
+
+func runwc(s string) (m map[string]int, err string) {
+ defer func() {
+ if v := recover(); v != nil {
+ err = fmt.Sprintln("panic: ", v)
+ err += "\nCall stack:\n" + string(debug.Stack())
+ }
+ }()
+ return wcFunc(s), ""
+}
+
+type wordCount struct {
+ Word string
+ Count int
+}
+
+type wordCounts []wordCount
+
+func (wc wordCounts) Less(i, j int) bool {
+ return wc[i].Count > wc[j].Count ||
+ wc[i].Count == wc[j].Count && wc[i].Word < wc[j].Word
+}
+
+func (wc wordCounts) Swap(i, j int) {
+ wc[i], wc[j] = wc[j], wc[i]
+}
+
+func (wc wordCounts) Len() int {
+ return len(wc)
+}
+
+func wcHandler(c http.ResponseWriter, req *http.Request) {
+ var buf bytes.Buffer
+ io.Copy(&buf, req.Body)
+ m, err := runwc(buf.String())
+ if err != "" {
+ c.WriteHeader(404)
+ c.Write([]byte("<pre>"))
+ template.HTMLEscape(c, []byte(err))
+ c.Write([]byte("</pre>"))
+ return
+ }
+ w := make([]wordCount, len(m))
+ n := 0
+ for word, count := range m {
+ w[n] = wordCount{word, count}
+ n++
+ }
+ sort.Sort(wordCounts(w))
+ table.Execute(c, w)
+}
+
+// Serve runs a web server on port 4000 counting words using f.
+func Serve(f func(string)map[string]int) {
+ wcFunc = f
+ http.HandleFunc("/", frontPageHandler)
+ http.HandleFunc("/wc", wcHandler)
+ err := http.ListenAndServe("127.0.0.1:4000", nil)
+ log.Fatal(err)
+}
+
+var frontPage, table *template.Template
+
+func init() {
+ frontPage = template.New(nil)
+ frontPage.SetDelims("«", "»")
+ err := frontPage.Parse(frontPageText)
+ if err != nil {
+ panic(err)
+ }
+
+ table = template.New(nil)
+ table.SetDelims("«", "»")
+ err = table.Parse(tableText)
+ if err != nil {
+ panic(err)
+ }
+}
+
+var frontPageText = `<!doctype html>
+<html>
+<head>
+<style>
+h1 { font-family: monospace; }
+</style>
+<script>
+var xmlreq;
+
+function runwc() {
+ var prog = document.getElementById("edit").value;
+ var req = new XMLHttpRequest();
+ xmlreq = req;
+ req.onreadystatechange = wcUpdate;
+ req.open("POST", "/wc", true);
+ req.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
+ req.send(prog);
+}
+
+function wcUpdate() {
+ var req = xmlreq;
+ if(!req || req.readyState != 4) {
+ return;
+ }
+ if(req.status == 200) {
+ document.getElementById("output").innerHTML = req.responseText;
+ document.getElementById("errors").innerHTML = "";
+ } else {
+ document.getElementById("errors").innerHTML = req.responseText;
+ document.getElementById("output").innerHTML = "";
+ }
+}
+</script>
+</head>
+<body>
+<h1>Interactive Word Count</h1>
+<table width="100%"><tr><td width="60%" valign="top">
+<textarea autofocus="true" id="edit" style="width: 100%; height: 200px; font-size: 100%;" spellcheck="false" contenteditable="true" onkeyup="runwc();">«@|html»
+</textarea>
+<br/>
+<td width="3%">
+<td width="27%" align="right" valign="top">
+<div id="output" align="left" style="width: 100%; font-size: 100%;">
+</div>
+</table>
+<div id="errors" align="left" style="width: 100%; font-family: monaco; font-size: 100%; color: #800;">
+</div>
+</body>
+</html>
+`
+
+var tableText = `map [
+<table>
+«.repeated section @»
+<tr><td width=20><td>«Word»<td>«Count»</tr>
+«.end»
+</table>
+]
+`
+