summaryrefslogtreecommitdiff
path: root/doc/codelab/wiki
diff options
context:
space:
mode:
Diffstat (limited to 'doc/codelab/wiki')
-rw-r--r--doc/codelab/wiki/Makefile25
-rw-r--r--doc/codelab/wiki/edit.html6
-rw-r--r--doc/codelab/wiki/final-noclosure.go100
-rw-r--r--doc/codelab/wiki/final-noerror.go52
-rw-r--r--doc/codelab/wiki/final-parsetemplate.go90
-rw-r--r--doc/codelab/wiki/final-template.go64
-rw-r--r--doc/codelab/wiki/final.go93
-rw-r--r--doc/codelab/wiki/get.go50
-rw-r--r--doc/codelab/wiki/htmlify.go12
-rw-r--r--doc/codelab/wiki/http-sample.go15
-rw-r--r--doc/codelab/wiki/index.html1003
-rw-r--r--doc/codelab/wiki/notemplate.go55
-rw-r--r--doc/codelab/wiki/part1-noerror.go30
-rw-r--r--doc/codelab/wiki/part1.go33
-rw-r--r--doc/codelab/wiki/part2.go40
-rw-r--r--doc/codelab/wiki/srcextract.go72
-rwxr-xr-xdoc/codelab/wiki/test.sh27
-rw-r--r--doc/codelab/wiki/test_Test.txt.good1
-rw-r--r--doc/codelab/wiki/test_edit.good6
-rw-r--r--doc/codelab/wiki/test_view.good5
-rw-r--r--doc/codelab/wiki/view.html5
-rw-r--r--doc/codelab/wiki/wiki.html781
22 files changed, 0 insertions, 2565 deletions
diff --git a/doc/codelab/wiki/Makefile b/doc/codelab/wiki/Makefile
deleted file mode 100644
index 09c3291a0..000000000
--- a/doc/codelab/wiki/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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.
-
-include ../../../src/Make.inc
-
-all: index.html
-
-include ../../../src/Make.common
-
-CLEANFILES+=index.html srcextract.bin htmlify.bin get.bin
-
-index.html: srcextract.bin htmlify.bin
- PATH=.:$$PATH awk '/^!/{system(substr($$0,2)); next} {print}' < wiki.html | tr -d '\r' > index.html
-
-test: get.bin
- bash ./test.sh
- rm -f get.6 get.bin
-
-%.bin: %.$O
- $(LD) -o $@ $<
-
-%.$O: %.go
- $(GC) $*.go
-
diff --git a/doc/codelab/wiki/edit.html b/doc/codelab/wiki/edit.html
deleted file mode 100644
index 7a5768ce9..000000000
--- a/doc/codelab/wiki/edit.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<h1>Editing {Title}</h1>
-
-<form action="/save/{Title}" method="POST">
-<div><textarea name="body" rows="20" cols="80">{Body|html}</textarea></div>
-<div><input type="submit" value="Save"></div>
-</form>
diff --git a/doc/codelab/wiki/final-noclosure.go b/doc/codelab/wiki/final-noclosure.go
deleted file mode 100644
index d09a0d7ab..000000000
--- a/doc/codelab/wiki/final-noclosure.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package main
-
-import (
- "http"
- "io/ioutil"
- "os"
- "regexp"
- "template"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() os.Error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func loadPage(title string) (*Page, os.Error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title, err := getTitle(w, r)
- if err != nil {
- return
- }
- p, err := loadPage(title)
- if err != nil {
- http.Redirect(w, r, "/edit/"+title, http.StatusFound)
- return
- }
- renderTemplate(w, "view", p)
-}
-
-func editHandler(w http.ResponseWriter, r *http.Request) {
- title, err := getTitle(w, r)
- if err != nil {
- return
- }
- p, err := loadPage(title)
- if err != nil {
- p = &Page{Title: title}
- }
- renderTemplate(w, "edit", p)
-}
-
-func saveHandler(w http.ResponseWriter, r *http.Request) {
- title, err := getTitle(w, r)
- if err != nil {
- return
- }
- body := r.FormValue("body")
- p := &Page{Title: title, Body: []byte(body)}
- err = p.save()
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- http.Redirect(w, r, "/view/"+title, http.StatusFound)
-}
-
-func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
- t, err := template.ParseFile(tmpl+".html", nil)
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- err = t.Execute(w, p)
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- }
-}
-
-const lenPath = len("/view/")
-
-var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
-
-func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
- title = r.URL.Path[lenPath:]
- if !titleValidator.MatchString(title) {
- http.NotFound(w, r)
- err = os.NewError("Invalid Page Title")
- }
- return
-}
-
-func main() {
- http.HandleFunc("/view/", viewHandler)
- http.HandleFunc("/edit/", editHandler)
- http.HandleFunc("/save/", saveHandler)
- http.ListenAndServe(":8080", nil)
-}
diff --git a/doc/codelab/wiki/final-noerror.go b/doc/codelab/wiki/final-noerror.go
deleted file mode 100644
index 5fcf1de76..000000000
--- a/doc/codelab/wiki/final-noerror.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package main
-
-import (
- "http"
- "io/ioutil"
- "os"
- "template"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() os.Error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func loadPage(title string) (*Page, os.Error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-const lenPath = len("/view/")
-
-func editHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, err := loadPage(title)
- if err != nil {
- p = &Page{Title: title}
- }
- t, _ := template.ParseFile("edit.html", nil)
- t.Execute(w, p)
-}
-
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, _ := loadPage(title)
- t, _ := template.ParseFile("view.html", nil)
- t.Execute(w, p)
-}
-
-func main() {
- http.HandleFunc("/view/", viewHandler)
- http.HandleFunc("/edit/", editHandler)
- http.ListenAndServe(":8080", nil)
-}
diff --git a/doc/codelab/wiki/final-parsetemplate.go b/doc/codelab/wiki/final-parsetemplate.go
deleted file mode 100644
index f25012eed..000000000
--- a/doc/codelab/wiki/final-parsetemplate.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package main
-
-import (
- "http"
- "io/ioutil"
- "os"
- "regexp"
- "template"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() os.Error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func loadPage(title string) (*Page, os.Error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
- p, err := loadPage(title)
- if err != nil {
- http.Redirect(w, r, "/edit/"+title, http.StatusFound)
- return
- }
- renderTemplate(w, "view", p)
-}
-
-func editHandler(w http.ResponseWriter, r *http.Request, title string) {
- p, err := loadPage(title)
- if err != nil {
- p = &Page{Title: title}
- }
- renderTemplate(w, "edit", p)
-}
-
-func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
- body := r.FormValue("body")
- p := &Page{Title: title, Body: []byte(body)}
- err := p.save()
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- http.Redirect(w, r, "/view/"+title, http.StatusFound)
-}
-
-func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
- t, err := template.ParseFile(tmpl+".html", nil)
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- err = t.Execute(w, p)
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- }
-}
-
-const lenPath = len("/view/")
-
-var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
-
-func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- if !titleValidator.MatchString(title) {
- http.NotFound(w, r)
- return
- }
- fn(w, r, title)
- }
-}
-
-func main() {
- http.HandleFunc("/view/", makeHandler(viewHandler))
- http.HandleFunc("/edit/", makeHandler(editHandler))
- http.HandleFunc("/save/", makeHandler(saveHandler))
- http.ListenAndServe(":8080", nil)
-}
diff --git a/doc/codelab/wiki/final-template.go b/doc/codelab/wiki/final-template.go
deleted file mode 100644
index aab536ee1..000000000
--- a/doc/codelab/wiki/final-template.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package main
-
-import (
- "http"
- "io/ioutil"
- "os"
- "template"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() os.Error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func loadPage(title string) (*Page, os.Error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-const lenPath = len("/view/")
-
-func editHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, err := loadPage(title)
- if err != nil {
- p = &Page{Title: title}
- }
- renderTemplate(w, "edit", p)
-}
-
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, _ := loadPage(title)
- renderTemplate(w, "view", p)
-}
-
-func saveHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- body := r.FormValue("body")
- p := &Page{Title: title, Body: []byte(body)}
- p.save()
- http.Redirect(w, r, "/view/"+title, http.StatusFound)
-}
-
-func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
- t, _ := template.ParseFile(tmpl+".html", nil)
- t.Execute(w, p)
-}
-
-func main() {
- http.HandleFunc("/view/", viewHandler)
- http.HandleFunc("/edit/", editHandler)
- http.HandleFunc("/save/", saveHandler)
- http.ListenAndServe(":8080", nil)
-}
diff --git a/doc/codelab/wiki/final.go b/doc/codelab/wiki/final.go
deleted file mode 100644
index c97a699d4..000000000
--- a/doc/codelab/wiki/final.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package main
-
-import (
- "http"
- "io/ioutil"
- "os"
- "regexp"
- "template"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() os.Error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func loadPage(title string) (*Page, os.Error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
- p, err := loadPage(title)
- if err != nil {
- http.Redirect(w, r, "/edit/"+title, http.StatusFound)
- return
- }
- renderTemplate(w, "view", p)
-}
-
-func editHandler(w http.ResponseWriter, r *http.Request, title string) {
- p, err := loadPage(title)
- if err != nil {
- p = &Page{Title: title}
- }
- renderTemplate(w, "edit", p)
-}
-
-func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
- body := r.FormValue("body")
- p := &Page{Title: title, Body: []byte(body)}
- err := p.save()
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- http.Redirect(w, r, "/view/"+title, http.StatusFound)
-}
-
-var templates = make(map[string]*template.Template)
-
-func init() {
- for _, tmpl := range []string{"edit", "view"} {
- templates[tmpl] = template.MustParseFile(tmpl+".html", nil)
- }
-}
-
-func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
- err := templates[tmpl].Execute(w, p)
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- }
-}
-
-const lenPath = len("/view/")
-
-var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
-
-func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- if !titleValidator.MatchString(title) {
- http.NotFound(w, r)
- return
- }
- fn(w, r, title)
- }
-}
-
-func main() {
- http.HandleFunc("/view/", makeHandler(viewHandler))
- http.HandleFunc("/edit/", makeHandler(editHandler))
- http.HandleFunc("/save/", makeHandler(saveHandler))
- http.ListenAndServe(":8080", nil)
-}
diff --git a/doc/codelab/wiki/get.go b/doc/codelab/wiki/get.go
deleted file mode 100644
index c36684e3e..000000000
--- a/doc/codelab/wiki/get.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package main
-
-import (
- "http"
- "flag"
- "fmt"
- "io"
- "log"
- "net"
- "os"
- "strings"
-)
-
-var (
- post = flag.String("post", "", "urlencoded form data to POST")
- addr = flag.Bool("addr", false, "find open address and print to stdout")
-)
-
-func main() {
- flag.Parse()
- if *addr {
- l, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- log.Fatal(err)
- }
- defer l.Close()
- fmt.Print(l.Addr())
- return
- }
- url := flag.Arg(0)
- if url == "" {
- log.Fatal("no url supplied")
- }
- var r *http.Response
- var err os.Error
- if *post != "" {
- b := strings.NewReader(*post)
- r, err = http.Post(url, "application/x-www-form-urlencoded", b)
- } else {
- r, err = http.Get(url)
- }
- if err != nil {
- log.Fatal(err)
- }
- defer r.Body.Close()
- _, err = io.Copy(os.Stdout, r.Body)
- if err != nil {
- log.Fatal(err)
- }
-}
diff --git a/doc/codelab/wiki/htmlify.go b/doc/codelab/wiki/htmlify.go
deleted file mode 100644
index 456d06fd5..000000000
--- a/doc/codelab/wiki/htmlify.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package main
-
-import (
- "os"
- "template"
- "io/ioutil"
-)
-
-func main() {
- b, _ := ioutil.ReadAll(os.Stdin)
- template.HTMLFormatter(os.Stdout, "", b)
-}
diff --git a/doc/codelab/wiki/http-sample.go b/doc/codelab/wiki/http-sample.go
deleted file mode 100644
index 33379a1b6..000000000
--- a/doc/codelab/wiki/http-sample.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package main
-
-import (
- "fmt"
- "http"
-)
-
-func handler(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
-}
-
-func main() {
- http.HandleFunc("/", handler)
- http.ListenAndServe(":8080", nil)
-}
diff --git a/doc/codelab/wiki/index.html b/doc/codelab/wiki/index.html
deleted file mode 100644
index cc187ad90..000000000
--- a/doc/codelab/wiki/index.html
+++ /dev/null
@@ -1,1003 +0,0 @@
-<!-- Codelab: Writing Web Applications -->
-<h2>Introduction</h2>
-
-<p>
-Covered in this codelab:
-</p>
-<ul>
-<li>Creating a data structure with load and save methods</li>
-<li>Using the <code>http</code> package to build web applications
-<li>Using the <code>template</code> package to process HTML templates</li>
-<li>Using the <code>regexp</code> package to validate user input</li>
-<li>Using closures</li>
-</ul>
-
-<p>
-Assumed knowledge:
-</p>
-<ul>
-<li>Programming experience</li>
-<li>Understanding of basic web technologies (HTTP, HTML)</li>
-<li>Some UNIX command-line knowledge</li>
-</ul>
-
-<h2>Getting Started</h2>
-
-<p>
-At present, you need to have a Linux, OS X, or FreeBSD machine to run Go. If
-you don't have access to one, you could set up a Linux Virtual Machine (using
-<a href="http://www.virtualbox.org/">VirtualBox</a> or similar) or a
-<a href="http://www.google.com/search?q=virtual+private+server">Virtual
-Private Server</a>.
-</p>
-
-<p>
-Install Go (see the <a href="http://golang.org/doc/install.html">Installation Instructions</a>).
-</p>
-
-<p>
-Make a new directory for this codelab and cd to it:
-</p>
-
-<pre>
-$ mkdir ~/gowiki
-$ cd ~/gowiki
-</pre>
-
-<p>
-Create a file named <code>wiki.go</code>, open it in your favorite editor, and
-add the following lines:
-</p>
-
-<pre>
-package main
-
-import (
- "fmt"
- "io/ioutil"
- "os"
-)
-</pre>
-
-<p>
-We import the <code>fmt</code>, <code>ioutil</code> and <code>os</code>
-packages from the Go standard library. Later, as we implement additional
-functionality, we will add more packages to this <code>import</code>
-declaration.
-</p>
-
-<h2>Data Structures</h2>
-
-<p>
-Let's start by defining the data structures. A wiki consists of a series of
-interconnected pages, each of which has a title and a body (the page content).
-Here, we define <code>Page</code> as a struct with two fields representing
-the title and body.
-</p>
-
-<pre>
-type Page struct {
- Title string
- Body []byte
-}
-</pre>
-
-<p>
-The type <code>[]byte</code> means "a <code>byte</code> slice".
-(See <a href="http://golang.org/doc/effective_go.html#slices">Effective Go</a>
-for more on slices.)
-The <code>Body</code> element is a <code>[]byte</code> rather than
-<code>string</code> because that is the type expected by the <code>io</code>
-libraries we will use, as you'll see below.
-</p>
-
-<p>
-The <code>Page</code> struct describes how page data will be stored in memory.
-But what about persistent storage? We can address that by creating a
-<code>save</code> method on <code>Page</code>:
-</p>
-
-<pre>
-func (p *Page) save() os.Error {
- filename := p.Title + &#34;.txt&#34;
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-</pre>
-
-<p>
-This method's signature reads: "This is a method named <code>save</code> that
-takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes
-no parameters, and returns a value of type <code>os.Error</code>."
-</p>
-
-<p>
-This method will save the <code>Page</code>'s <code>Body</code> to a text
-file. For simplicity, we will use the <code>Title</code> as the file name.
-</p>
-
-<p>
-The <code>save</code> method returns an <code>os.Error</code> value because
-that is the return type of <code>WriteFile</code> (a standard library function
-that writes a byte slice to a file). The <code>save</code> method returns the
-error value, to let the application handle it should anything go wrong while
-writing the file. If all goes well, <code>Page.save()</code> will return
-<code>nil</code> (the zero-value for pointers, interfaces, and some other
-types).
-</p>
-
-<p>
-The octal integer constant <code>0600</code>, passed as the third parameter to
-<code>WriteFile</code>, indicates that the file should be created with
-read-write permissions for the current user only. (See the Unix man page
-<code>open(2)</code> for details.)
-</p>
-
-<p>
-We will want to load pages, too:
-</p>
-
-<pre>
-func loadPage(title string) *Page {
- filename := title + &#34;.txt&#34;
- body, _ := ioutil.ReadFile(filename)
- return &amp;Page{Title: title, Body: body}
-}
-</pre>
-
-<p>
-The function <code>loadPage</code> constructs the file name from
-<code>Title</code>, reads the file's contents into a new
-<code>Page</code>, and returns a pointer to that new <code>page</code>.
-</p>
-
-<p>
-Functions can return multiple values. The standard library function
-<code>io.ReadFile</code> returns <code>[]byte</code> and <code>os.Error</code>.
-In <code>loadPage</code>, error isn't being handled yet; the "blank identifier"
-represented by the underscore (<code>_</code>) symbol is used to throw away the
-error return value (in essence, assigning the value to nothing).
-</p>
-
-<p>
-But what happens if <code>ReadFile</code> encounters an error? For example,
-the file might not exist. We should not ignore such errors. Let's modify the
-function to return <code>*Page</code> and <code>os.Error</code>.
-</p>
-
-<pre>
-func loadPage(title string) (*Page, os.Error) {
- filename := title + &#34;.txt&#34;
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &amp;Page{Title: title, Body: body}, nil
-}
-</pre>
-
-<p>
-Callers of this function can now check the second parameter; if it is
-<code>nil</code> then it has successfully loaded a Page. If not, it will be an
-<code>os.Error</code> that can be handled by the caller (see the <a
-href="http://golang.org/pkg/os/#Error">os package documentation</a> for
-details).
-</p>
-
-<p>
-At this point we have a simple data structure and the ability to save to and
-load from a file. Let's write a <code>main</code> function to test what we've
-written:
-</p>
-
-<pre>
-func main() {
- p1 := &amp;Page{Title: &#34;TestPage&#34;, Body: []byte(&#34;This is a sample Page.&#34;)}
- p1.save()
- p2, _ := loadPage(&#34;TestPage&#34;)
- fmt.Println(string(p2.Body))
-}
-</pre>
-
-<p>
-After compiling and executing this code, a file named <code>TestPage.txt</code>
-would be created, containing the contents of <code>p1</code>. The file would
-then be read into the struct <code>p2</code>, and its <code>Body</code> element
-printed to the screen.
-</p>
-
-<p>
-You can compile and run the program like this:
-</p>
-
-<pre>
-$ 8g wiki.go
-$ 8l wiki.8
-$ ./8.out
-This is a sample page.
-</pre>
-
-<p>
-(The <code>8g</code> and <code>8l</code> commands are applicable to
-<code>GOARCH=386</code>. If you're on an <code>amd64</code> system,
-substitute 6's for the 8's.)
-</p>
-
-<p>
-<a href="part1.go">Click here to view the code we've written so far.</a>
-</p>
-
-<h2>Introducing the <code>http</code> package (an interlude)</h2>
-
-<p>
-Here's a full working example of a simple web server:
-</p>
-
-<pre>
-package main
-
-import (
- &#34;fmt&#34;
- &#34;http&#34;
-)
-
-func handler(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, &#34;Hi there, I love %s!&#34;, r.URL.Path[1:])
-}
-
-func main() {
- http.HandleFunc(&#34;/&#34;, handler)
- http.ListenAndServe(&#34;:8080&#34;, nil)
-}
-</pre>
-
-<p>
-The <code>main</code> function begins with a call to
-<code>http.HandleFunc</code>, which tells the <code>http</code> package to
-handle all requests to the web root (<code>"/"</code>) with
-<code>handler</code>.
-</p>
-
-<p>
-It then calls <code>http.ListenAndServe</code>, specifying that it should
-listen on port 8080 on any interface (<code>":8080"</code>). (Don't
-worry about its second parameter, <code>nil</code>, for now.)
-This function will block until the program is terminated.
-</p>
-
-<p>
-The function <code>handler</code> is of the type <code>http.HandlerFunc</code>.
-It takes an <code>http.ResponseWriter</code> and an <code>http.Request</code> as
-its arguments.
-</p>
-
-<p>
-An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing
-to it, we send data to the HTTP client.
-</p>
-
-<p>
-An <code>http.Request</code> is a data structure that represents the client
-HTTP request. The string <code>r.URL.Path</code> is the path component
-of the request URL. The trailing <code>[1:]</code> means
-"create a sub-slice of <code>Path</code> from the 1st character to the end."
-This drops the leading "/" from the path name.
-</p>
-
-<p>
-If you run this program and access the URL:
-</p>
-<pre>http://localhost:8080/monkeys</pre>
-<p>
-the program would present a page containing:
-</p>
-<pre>Hi there, I love monkeys!</pre>
-
-<h2>Using <code>http</code> to serve wiki pages</h2>
-
-<p>
-To use the <code>http</code> package, it must be imported:
-</p>
-
-<pre>
-import (
- "fmt"
- <b>"http"</b>
- "io/ioutil"
- "os"
-)
-</pre>
-
-<p>
-Let's create a handler to view a wiki page:
-</p>
-
-<pre>
-const lenPath = len(&#34;/view/&#34;)
-
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, _ := loadPage(title)
- fmt.Fprintf(w, &#34;&lt;h1&gt;%s&lt;/h1&gt;&lt;div&gt;%s&lt;/div&gt;&#34;, p.Title, p.Body)
-}
-</pre>
-
-<p>
-First, this function extracts the page title from <code>r.URL.Path</code>,
-the path component of the request URL. The global constant
-<code>lenPath</code> is the length of the leading <code>"/view/"</code>
-component of the request path.
-The <code>Path</code> is re-sliced with <code>[lenPath:]</code> to drop the
-first 6 characters of the string. This is because the path will invariably
-begin with <code>"/view/"</code>, which is not part of the page title.
-</p>
-
-<p>
-The function then loads the page data, formats the page with a string of simple
-HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>.
-</p>
-
-<p>
-Again, note the use of <code>_</code> to ignore the <code>os.Error</code>
-return value from <code>loadPage</code>. This is done here for simplicity
-and generally considered bad practice. We will attend to this later.
-</p>
-
-<p>
-To use this handler, we create a <code>main</code> function that
-initializes <code>http</code> using the <code>viewHandler</code> to handle
-any requests under the path <code>/view/</code>.
-</p>
-
-<pre>
-func main() {
- http.HandleFunc(&#34;/view/&#34;, viewHandler)
- http.ListenAndServe(&#34;:8080&#34;, nil)
-}
-</pre>
-
-<p>
-<a href="part2.go">Click here to view the code we've written so far.</a>
-</p>
-
-<p>
-Let's create some page data (as <code>test.txt</code>), compile our code, and
-try serving a wiki page:
-</p>
-
-<pre>
-$ echo "Hello world" &gt; test.txt
-$ 8g wiki.go
-$ 8l wiki.8
-$ ./8.out
-</pre>
-
-<p>
-With this web server running, a visit to <code><a
-href="http://localhost:8080/view/test">http://localhost:8080/view/test</a></code>
-should show a page titled "test" containing the words "Hello world".
-</p>
-
-<h2>Editing Pages</h2>
-
-<p>
-A wiki is not a wiki without the ability to edit pages. Let's create two new
-handlers: one named <code>editHandler</code> to display an 'edit page' form,
-and the other named <code>saveHandler</code> to save the data entered via the
-form.
-</p>
-
-<p>
-First, we add them to <code>main()</code>:
-</p>
-
-<pre>
-func main() {
- http.HandleFunc(&#34;/view/&#34;, viewHandler)
- http.HandleFunc(&#34;/edit/&#34;, editHandler)
- http.HandleFunc(&#34;/save/&#34;, saveHandler)
- http.ListenAndServe(&#34;:8080&#34;, nil)
-}
-</pre>
-
-<p>
-The function <code>editHandler</code> loads the page
-(or, if it doesn't exist, create an empty <code>Page</code> struct),
-and displays an HTML form.
-</p>
-
-<pre>
-func editHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, err := loadPage(title)
- if err != nil {
- p = &amp;Page{Title: title}
- }
- fmt.Fprintf(w, &#34;&lt;h1&gt;Editing %s&lt;/h1&gt;&#34;+
- &#34;&lt;form action=\&#34;/save/%s\&#34; method=\&#34;POST\&#34;&gt;&#34;+
- &#34;&lt;textarea name=\&#34;body\&#34;&gt;%s&lt;/textarea&gt;&lt;br&gt;&#34;+
- &#34;&lt;input type=\&#34;submit\&#34; value=\&#34;Save\&#34;&gt;&#34;+
- &#34;&lt;/form&gt;&#34;,
- p.Title, p.Title, p.Body)
-}
-</pre>
-
-<p>
-This function will work fine, but all that hard-coded HTML is ugly.
-Of course, there is a better way.
-</p>
-
-<h2>The <code>template</code> package</h2>
-
-<p>
-The <code>template</code> package is part of the Go standard library. We can
-use <code>template</code> to keep the HTML in a separate file, allowing
-us to change the layout of our edit page without modifying the underlying Go
-code.
-</p>
-
-<p>
-First, we must add <code>template</code> to the list of imports:
-</p>
-
-<pre>
-import (
- "http"
- "io/ioutil"
- "os"
- <b>"template"</b>
-)
-</pre>
-
-<p>
-Let's create a template file containing the HTML form.
-Open a new file named <code>edit.html</code>, and add the following lines:
-</p>
-
-<pre>
-&lt;h1&gt;Editing {Title}&lt;/h1&gt;
-
-&lt;form action=&#34;/save/{Title}&#34; method=&#34;POST&#34;&gt;
-&lt;div&gt;&lt;textarea name=&#34;body&#34; rows=&#34;20&#34; cols=&#34;80&#34;&gt;{Body|html}&lt;/textarea&gt;&lt;/div&gt;
-&lt;div&gt;&lt;input type=&#34;submit&#34; value=&#34;Save&#34;&gt;&lt;/div&gt;
-&lt;/form&gt;
-</pre>
-
-<p>
-Modify <code>editHandler</code> to use the template, instead of the hard-coded
-HTML:
-</p>
-
-<pre>
-func editHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, err := loadPage(title)
- if err != nil {
- p = &amp;Page{Title: title}
- }
- t, _ := template.ParseFile(&#34;edit.html&#34;, nil)
- t.Execute(w, p)
-}
-</pre>
-
-<p>
-The function <code>template.ParseFile</code> will read the contents of
-<code>edit.html</code> and return a <code>*template.Template</code>.
-</p>
-
-<p>
-The method <code>t.Execute</code> replaces all occurrences of
-<code>{Title}</code> and <code>{Body}</code> with the values of
-<code>p.Title</code> and <code>p.Body</code>, and writes the resultant
-HTML to the <code>http.ResponseWriter</code>.
-</p>
-
-<p>
-Note that we've used <code>{Body|html}</code> in the above template.
-The <code>|html</code> part asks the template engine to pass the value
-<code>Body</code> through the <code>html</code> formatter before outputting it,
-which escapes HTML characters (such as replacing <code>&gt;</code> with
-<code>&amp;gt;</code>).
-This will prevent user data from corrupting the form HTML.
-</p>
-
-<p>
-Now that we've removed the <code>fmt.Fprintf</code> statement, we can remove
-<code>"fmt"</code> from the <code>import</code> list.
-</p>
-
-<p>
-While we're working with templates, let's create a template for our
-<code>viewHandler</code> called <code>view.html</code>:
-</p>
-
-<pre>
-&lt;h1&gt;{Title}&lt;/h1&gt;
-
-&lt;p&gt;[&lt;a href=&#34;/edit/{Title}&#34;&gt;edit&lt;/a&gt;]&lt;/p&gt;
-
-&lt;div&gt;{Body}&lt;/div&gt;
-</pre>
-
-<p>
-Modify <code>viewHandler</code> accordingly:
-</p>
-
-<pre>
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, _ := loadPage(title)
- t, _ := template.ParseFile(&#34;view.html&#34;, nil)
- t.Execute(w, p)
-}
-</pre>
-
-<p>
-Notice that we've used almost exactly the same templating code in both
-handlers. Let's remove this duplication by moving the templating code
-to its own function:
-</p>
-
-<pre>
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, _ := loadPage(title)
- renderTemplate(w, &#34;view&#34;, p)
-}
-
-func editHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, err := loadPage(title)
- if err != nil {
- p = &amp;Page{Title: title}
- }
- renderTemplate(w, &#34;edit&#34;, p)
-}
-
-func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
- t, _ := template.ParseFile(tmpl+&#34;.html&#34;, nil)
- t.Execute(w, p)
-}
-</pre>
-
-<p>
-The handlers are now shorter and simpler.
-</p>
-
-<h2>Handling non-existent pages</h2>
-
-<p>
-What if you visit <code>/view/APageThatDoesntExist</code>? The program will
-crash. This is because it ignores the error return value from
-<code>loadPage</code>. Instead, if the requested Page doesn't exist, it should
-redirect the client to the edit Page so the content may be created:
-</p>
-
-<pre>
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title, err := getTitle(w, r)
- if err != nil {
- return
- }
- p, err := loadPage(title)
- if err != nil {
- http.Redirect(w, r, &#34;/edit/&#34;+title, http.StatusFound)
- return
- }
- renderTemplate(w, &#34;view&#34;, p)
-}
-</pre>
-
-<p>
-The <code>http.Redirect</code> function adds an HTTP status code of
-<code>http.StatusFound</code> (302) and a <code>Location</code>
-header to the HTTP response.
-</p>
-
-<h2>Saving Pages</h2>
-
-<p>
-The function <code>saveHandler</code> will handle the form submission.
-</p>
-
-<pre>
-func saveHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- body := r.FormValue(&#34;body&#34;)
- p := &amp;Page{Title: title, Body: []byte(body)}
- p.save()
- http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
-}
-</pre>
-
-<p>
-The page title (provided in the URL) and the form's only field,
-<code>Body</code>, are stored in a new <code>Page</code>.
-The <code>save()</code> method is then called to write the data to a file,
-and the client is redirected to the <code>/view/</code> page.
-</p>
-
-<p>
-The value returned by <code>FormValue</code> is of type <code>string</code>.
-We must convert that value to <code>[]byte</code> before it will fit into
-the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform
-the conversion.
-</p>
-
-<h2>Error handling</h2>
-
-<p>
-There are several places in our program where errors are being ignored. This
-is bad practice, not least because when an error does occur the program will
-crash. A better solution is to handle the errors and return an error message
-to the user. That way if something does go wrong, the server will continue to
-function and the user will be notified.
-</p>
-
-<p>
-First, let's handle the errors in <code>renderTemplate</code>:
-</p>
-
-<pre>
-func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
- t, err := template.ParseFile(tmpl+&#34;.html&#34;, nil)
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- err = t.Execute(w, p)
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- }
-}
-</pre>
-
-<p>
-The <code>http.Error</code> function sends a specified HTTP response code
-(in this case "Internal Server Error") and error message.
-Already the decision to put this in a separate function is paying off.
-</p>
-
-<p>
-Now let's fix up <code>saveHandler</code>:
-</p>
-
-<pre>
-func saveHandler(w http.ResponseWriter, r *http.Request) {
- title, err := getTitle(w, r)
- if err != nil {
- return
- }
- body := r.FormValue(&#34;body&#34;)
- p := &amp;Page{Title: title, Body: []byte(body)}
- err = p.save()
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
-}
-</pre>
-
-<p>
-Any errors that occur during <code>p.save()</code> will be reported
-to the user.
-</p>
-
-<h2>Template caching</h2>
-
-<p>
-There is an inefficiency in this code: <code>renderTemplate</code> calls
-<code>ParseFile</code> every time a page is rendered.
-A better approach would be to call <code>ParseFile</code> once for each
-template at program initialization, and store the resultant
-<code>*Template</code> values in a data structure for later use.
-</p>
-
-<p>
-First we create a global map named <code>templates</code> in which to store
-our <code>*Template</code> values, keyed by <code>string</code>
-(the template name):
-</p>
-
-<pre>
-var templates = make(map[string]*template.Template)
-</pre>
-
-<p>
-Then we create an <code>init</code> function, which will be called before
-<code>main</code> at program initialization. The function
-<code>template.MustParseFile</code> is a convenience wrapper around
-<code>ParseFile</code> that does not return an error code; instead, it panics
-if an error is encountered. A panic is appropriate here; if the templates can't
-be loaded the only sensible thing to do is exit the program.
-</p>
-
-<pre>
-func init() {
- for _, tmpl := range []string{&#34;edit&#34;, &#34;view&#34;} {
- templates[tmpl] = template.MustParseFile(tmpl+&#34;.html&#34;, nil)
- }
-}
-</pre>
-
-<p>
-A <code>for</code> loop is used with a <code>range</code> statement to iterate
-over an array constant containing the names of the templates we want parsed.
-If we were to add more templates to our program, we would add their names to
-that array.
-</p>
-
-<p>
-We then modify our <code>renderTemplate</code> function to call
-the <code>Execute</code> method on the appropriate <code>Template</code> from
-<code>templates</code>:
-
-<pre>
-func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
- err := templates[tmpl].Execute(w, p)
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- }
-}
-</pre>
-
-<h2>Validation</h2>
-
-<p>
-As you may have observed, this program has a serious security flaw: a user
-can supply an arbitrary path to be read/written on the server. To mitigate
-this, we can write a function to validate the title with a regular expression.
-</p>
-
-<p>
-First, add <code>"regexp"</code> to the <code>import</code> list.
-Then we can create a global variable to store our validation regexp:
-</p>
-
-<pre>
-var titleValidator = regexp.MustCompile(&#34;^[a-zA-Z0-9]+$&#34;)
-</pre>
-
-<p>
-The function <code>regexp.MustCompile</code> will parse and compile the
-regular expression, and return a <code>regexp.Regexp</code>.
-<code>MustCompile</code>, like <code>template.MustParseFile</code>,
-is distinct from <code>Compile</code> in that it will panic if
-the expression compilation fails, while <code>Compile</code> returns an
-<code>os.Error</code> as a second parameter.
-</p>
-
-<p>
-Now, let's write a function that extracts the title string from the request
-URL, and tests it against our <code>TitleValidator</code> expression:
-</p>
-
-<pre>
-func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
- title = r.URL.Path[lenPath:]
- if !titleValidator.MatchString(title) {
- http.NotFound(w, r)
- err = os.NewError(&#34;Invalid Page Title&#34;)
- }
- return
-}
-</pre>
-
-<p>
-If the title is valid, it will be returned along with a <code>nil</code>
-error value. If the title is invalid, the function will write a
-"404 Not Found" error to the HTTP connection, and return an error to the
-handler.
-</p>
-
-<p>
-Let's put a call to <code>getTitle</code> in each of the handlers:
-</p>
-
-<pre>
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title, err := getTitle(w, r)
- if err != nil {
- return
- }
- p, err := loadPage(title)
- if err != nil {
- http.Redirect(w, r, &#34;/edit/&#34;+title, http.StatusFound)
- return
- }
- renderTemplate(w, &#34;view&#34;, p)
-}
-
-func editHandler(w http.ResponseWriter, r *http.Request) {
- title, err := getTitle(w, r)
- if err != nil {
- return
- }
- p, err := loadPage(title)
- if err != nil {
- p = &amp;Page{Title: title}
- }
- renderTemplate(w, &#34;edit&#34;, p)
-}
-
-func saveHandler(w http.ResponseWriter, r *http.Request) {
- title, err := getTitle(w, r)
- if err != nil {
- return
- }
- body := r.FormValue(&#34;body&#34;)
- p := &amp;Page{Title: title, Body: []byte(body)}
- err = p.save()
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
-}
-</pre>
-
-<h2>Introducing Function Literals and Closures</h2>
-
-<p>
-Catching the error condition in each handler introduces a lot of repeated code.
-What if we could wrap each of the handlers in a function that does this
-validation and error checking? Go's
-<a href="http://golang.org/doc/go_spec.html#Function_declarations">function
-literals</a> provide a powerful means of abstracting functionality
-that can help us here.
-</p>
-
-<p>
-First, we re-write the function definition of each of the handlers to accept
-a title string:
-</p>
-
-<pre>
-func viewHandler(w http.ResponseWriter, r *http.Request, title string)
-func editHandler(w http.ResponseWriter, r *http.Request, title string)
-func saveHandler(w http.ResponseWriter, r *http.Request, title string)
-</pre>
-
-<p>
-Now let's define a wrapper function that <i>takes a function of the above
-type</i>, and returns a function of type <code>http.HandlerFunc</code>
-(suitable to be passed to the function <code>http.HandleFunc</code>):
-</p>
-
-<pre>
-func makeHandler(fn func (http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- // Here we will extract the page title from the Request,
- // and call the provided handler 'fn'
- }
-}
-</pre>
-
-<p>
-The returned function is called a closure because it encloses values defined
-outside of it. In this case, the variable <code>fn</code> (the single argument
-to <code>makeHandler</code>) is enclosed by the closure. The variable
-<code>fn</code> will be one of our save, edit, or view handlers.
-</p>
-
-<p>
-Now we can take the code from <code>getTitle</code> and use it here
-(with some minor modifications):
-</p>
-
-<pre>
-func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- if !titleValidator.MatchString(title) {
- http.NotFound(w, r)
- return
- }
- fn(w, r, title)
- }
-}
-</pre>
-
-<p>
-The closure returned by <code>makeHandler</code> is a function that takes
-an <code>http.ResponseWriter</code> and <code>http.Request</code> (in other
-words, an <code>http.HandlerFunc</code>).
-The closure extracts the <code>title</code> from the request path, and
-validates it with the <code>TitleValidator</code> regexp. If the
-<code>title</code> is invalid, an error will be written to the
-<code>ResponseWriter</code> using the <code>http.NotFound</code> function.
-If the <code>title</code> is valid, the enclosed handler function
-<code>fn</code> will be called with the <code>ResponseWriter</code>,
-<code>Request</code>, and <code>title</code> as arguments.
-</p>
-
-<p>
-Now we can wrap the handler functions with <code>makeHandler</code> in
-<code>main</code>, before they are registered with the <code>http</code>
-package:
-</p>
-
-<pre>
-func main() {
- http.HandleFunc(&#34;/view/&#34;, makeHandler(viewHandler))
- http.HandleFunc(&#34;/edit/&#34;, makeHandler(editHandler))
- http.HandleFunc(&#34;/save/&#34;, makeHandler(saveHandler))
- http.ListenAndServe(&#34;:8080&#34;, nil)
-}
-</pre>
-
-<p>
-Finally we remove the calls to <code>getTitle</code> from the handler functions,
-making them much simpler:
-</p>
-
-<pre>
-func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
- p, err := loadPage(title)
- if err != nil {
- http.Redirect(w, r, &#34;/edit/&#34;+title, http.StatusFound)
- return
- }
- renderTemplate(w, &#34;view&#34;, p)
-}
-
-func editHandler(w http.ResponseWriter, r *http.Request, title string) {
- p, err := loadPage(title)
- if err != nil {
- p = &amp;Page{Title: title}
- }
- renderTemplate(w, &#34;edit&#34;, p)
-}
-
-func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
- body := r.FormValue(&#34;body&#34;)
- p := &amp;Page{Title: title, Body: []byte(body)}
- err := p.save()
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
-}
-</pre>
-
-<h2>Try it out!</h2>
-
-<p>
-<a href="final.go">Click here to view the final code listing.</a>
-</p>
-
-<p>
-Recompile the code, and run the app:
-</p>
-
-<pre>
-$ 8g wiki.go
-$ 8l wiki.8
-$ ./8.out
-</pre>
-
-<p>
-Visiting <a href="http://localhost:8080/view/ANewPage">http://localhost:8080/view/ANewPage</a>
-should present you with the page edit form. You should then be able to
-enter some text, click 'Save', and be redirected to the newly created page.
-</p>
-
-<h2>Other tasks</h2>
-
-<p>
-Here are some simple tasks you might want to tackle on your own:
-</p>
-
-<ul>
-<li>Store templates in <code>tmpl/</code> and page data in <code>data/</code>.
-<li>Add a handler to make the web root redirect to
- <code>/view/FrontPage</code>.</li>
-<li>Spruce up the page templates by making them valid HTML and adding some
- CSS rules.</li>
-<li>Implement inter-page linking by converting instances of
- <code>[PageName]</code> to <br>
- <code>&lt;a href="/view/PageName"&gt;PageName&lt;/a&gt;</code>.
- (hint: you could use <code>regexp.ReplaceAllFunc</code> to do this)
- </li>
-</ul>
diff --git a/doc/codelab/wiki/notemplate.go b/doc/codelab/wiki/notemplate.go
deleted file mode 100644
index 9cbe9ad76..000000000
--- a/doc/codelab/wiki/notemplate.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package main
-
-import (
- "fmt"
- "http"
- "io/ioutil"
- "os"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() os.Error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func loadPage(title string) (*Page, os.Error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-const lenPath = len("/view/")
-
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, _ := loadPage(title)
- fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
-}
-
-func editHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, err := loadPage(title)
- if err != nil {
- p = &Page{Title: title}
- }
- fmt.Fprintf(w, "<h1>Editing %s</h1>"+
- "<form action=\"/save/%s\" method=\"POST\">"+
- "<textarea name=\"body\">%s</textarea><br>"+
- "<input type=\"submit\" value=\"Save\">"+
- "</form>",
- p.Title, p.Title, p.Body)
-}
-
-func main() {
- http.HandleFunc("/view/", viewHandler)
- http.HandleFunc("/edit/", editHandler)
- http.ListenAndServe(":8080", nil)
-}
diff --git a/doc/codelab/wiki/part1-noerror.go b/doc/codelab/wiki/part1-noerror.go
deleted file mode 100644
index 14cfc321a..000000000
--- a/doc/codelab/wiki/part1-noerror.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package main
-
-import (
- "fmt"
- "io/ioutil"
- "os"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() os.Error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func loadPage(title string) *Page {
- filename := title + ".txt"
- body, _ := ioutil.ReadFile(filename)
- return &Page{Title: title, Body: body}
-}
-
-func main() {
- p1 := &Page{Title: "TestPage", Body: []byte("This is a sample page.")}
- p1.save()
- p2 := loadPage("TestPage")
- fmt.Println(string(p2.Body))
-}
diff --git a/doc/codelab/wiki/part1.go b/doc/codelab/wiki/part1.go
deleted file mode 100644
index 4b0654f8b..000000000
--- a/doc/codelab/wiki/part1.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package main
-
-import (
- "fmt"
- "io/ioutil"
- "os"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() os.Error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func loadPage(title string) (*Page, os.Error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-func main() {
- p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
- p1.save()
- p2, _ := loadPage("TestPage")
- fmt.Println(string(p2.Body))
-}
diff --git a/doc/codelab/wiki/part2.go b/doc/codelab/wiki/part2.go
deleted file mode 100644
index d57c3a01f..000000000
--- a/doc/codelab/wiki/part2.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package main
-
-import (
- "fmt"
- "http"
- "io/ioutil"
- "os"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() os.Error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func loadPage(title string) (*Page, os.Error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-const lenPath = len("/view/")
-
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, _ := loadPage(title)
- fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
-}
-
-func main() {
- http.HandleFunc("/view/", viewHandler)
- http.ListenAndServe(":8080", nil)
-}
diff --git a/doc/codelab/wiki/srcextract.go b/doc/codelab/wiki/srcextract.go
deleted file mode 100644
index 67294784e..000000000
--- a/doc/codelab/wiki/srcextract.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package main
-
-import (
- "bytes"
- "flag"
- "go/parser"
- "go/printer"
- "go/ast"
- "go/token"
- "log"
- "os"
- "template"
-)
-
-var (
- srcFn = flag.String("src", "", "source filename")
- getName = flag.String("name", "", "func/type name to output")
- html = flag.Bool("html", true, "output HTML")
- showPkg = flag.Bool("pkg", false, "show package in output")
-)
-
-func main() {
- // handle input
- flag.Parse()
- if *srcFn == "" || *getName == "" {
- flag.Usage()
- os.Exit(2)
- }
- // load file
- fs := token.NewFileSet()
- file, err := parser.ParseFile(fs, *srcFn, nil, 0)
- if err != nil {
- log.Fatal(err)
- }
- // create filter
- filter := func(name string) bool {
- return name == *getName
- }
- // filter
- if !ast.FilterFile(file, filter) {
- os.Exit(1)
- }
- // print the AST
- var b bytes.Buffer
- printer.Fprint(&b, fs, file)
- // drop package declaration
- if !*showPkg {
- for {
- c, err := b.ReadByte()
- if c == '\n' || err != nil {
- break
- }
- }
- }
- // drop leading newlines
- for {
- b, err := b.ReadByte()
- if err != nil {
- break
- }
- if b != '\n' {
- os.Stdout.Write([]byte{b})
- break
- }
- }
- // output
- if *html {
- template.HTMLEscape(os.Stdout, b.Bytes())
- } else {
- b.WriteTo(os.Stdout)
- }
-}
diff --git a/doc/codelab/wiki/test.sh b/doc/codelab/wiki/test.sh
deleted file mode 100755
index ed63ff20f..000000000
--- a/doc/codelab/wiki/test.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-wiki_pid=
-cleanup() {
- kill $wiki_pid
- rm -f test_*.out Test.txt final-test.bin final-test.go
-}
-trap cleanup 0 INT
-
-gomake get.bin
-addr=$(./get.bin -addr)
-sed s/:8080/$addr/ < final.go > final-test.go
-gomake final-test.bin
-(./final-test.bin) &
-wiki_pid=$!
-
-sleep 1
-
-./get.bin http://$addr/edit/Test > test_edit.out
-diff -u test_edit.out test_edit.good
-./get.bin -post=body=some%20content http://$addr/save/Test
-diff -u Test.txt test_Test.txt.good
-./get.bin http://$addr/view/Test > test_view.out
-diff -u test_view.out test_view.good
-
-echo PASS
diff --git a/doc/codelab/wiki/test_Test.txt.good b/doc/codelab/wiki/test_Test.txt.good
deleted file mode 100644
index f0eec86f6..000000000
--- a/doc/codelab/wiki/test_Test.txt.good
+++ /dev/null
@@ -1 +0,0 @@
-some content \ No newline at end of file
diff --git a/doc/codelab/wiki/test_edit.good b/doc/codelab/wiki/test_edit.good
deleted file mode 100644
index 36c6dbb73..000000000
--- a/doc/codelab/wiki/test_edit.good
+++ /dev/null
@@ -1,6 +0,0 @@
-<h1>Editing Test</h1>
-
-<form action="/save/Test" method="POST">
-<div><textarea name="body" rows="20" cols="80"></textarea></div>
-<div><input type="submit" value="Save"></div>
-</form>
diff --git a/doc/codelab/wiki/test_view.good b/doc/codelab/wiki/test_view.good
deleted file mode 100644
index 07e8edb22..000000000
--- a/doc/codelab/wiki/test_view.good
+++ /dev/null
@@ -1,5 +0,0 @@
-<h1>Test</h1>
-
-<p>[<a href="/edit/Test">edit</a>]</p>
-
-<div>some content</div>
diff --git a/doc/codelab/wiki/view.html b/doc/codelab/wiki/view.html
deleted file mode 100644
index ca2ffc20b..000000000
--- a/doc/codelab/wiki/view.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<h1>{Title}</h1>
-
-<p>[<a href="/edit/{Title}">edit</a>]</p>
-
-<div>{Body}</div>
diff --git a/doc/codelab/wiki/wiki.html b/doc/codelab/wiki/wiki.html
deleted file mode 100644
index 4db880b9d..000000000
--- a/doc/codelab/wiki/wiki.html
+++ /dev/null
@@ -1,781 +0,0 @@
-<!-- Codelab: Writing Web Applications -->
-<h2>Introduction</h2>
-
-<p>
-Covered in this codelab:
-</p>
-<ul>
-<li>Creating a data structure with load and save methods</li>
-<li>Using the <code>http</code> package to build web applications
-<li>Using the <code>template</code> package to process HTML templates</li>
-<li>Using the <code>regexp</code> package to validate user input</li>
-<li>Using closures</li>
-</ul>
-
-<p>
-Assumed knowledge:
-</p>
-<ul>
-<li>Programming experience</li>
-<li>Understanding of basic web technologies (HTTP, HTML)</li>
-<li>Some UNIX command-line knowledge</li>
-</ul>
-
-<h2>Getting Started</h2>
-
-<p>
-At present, you need to have a Linux, OS X, or FreeBSD machine to run Go. If
-you don't have access to one, you could set up a Linux Virtual Machine (using
-<a href="http://www.virtualbox.org/">VirtualBox</a> or similar) or a
-<a href="http://www.google.com/search?q=virtual+private+server">Virtual
-Private Server</a>.
-</p>
-
-<p>
-Install Go (see the <a href="http://golang.org/doc/install.html">Installation Instructions</a>).
-</p>
-
-<p>
-Make a new directory for this codelab and cd to it:
-</p>
-
-<pre>
-$ mkdir ~/gowiki
-$ cd ~/gowiki
-</pre>
-
-<p>
-Create a file named <code>wiki.go</code>, open it in your favorite editor, and
-add the following lines:
-</p>
-
-<pre>
-package main
-
-import (
- "fmt"
- "io/ioutil"
- "os"
-)
-</pre>
-
-<p>
-We import the <code>fmt</code>, <code>ioutil</code> and <code>os</code>
-packages from the Go standard library. Later, as we implement additional
-functionality, we will add more packages to this <code>import</code>
-declaration.
-</p>
-
-<h2>Data Structures</h2>
-
-<p>
-Let's start by defining the data structures. A wiki consists of a series of
-interconnected pages, each of which has a title and a body (the page content).
-Here, we define <code>Page</code> as a struct with two fields representing
-the title and body.
-</p>
-
-<pre>
-!srcextract.bin -src=part1.go -name=Page
-</pre>
-
-<p>
-The type <code>[]byte</code> means "a <code>byte</code> slice".
-(See <a href="http://golang.org/doc/effective_go.html#slices">Effective Go</a>
-for more on slices.)
-The <code>Body</code> element is a <code>[]byte</code> rather than
-<code>string</code> because that is the type expected by the <code>io</code>
-libraries we will use, as you'll see below.
-</p>
-
-<p>
-The <code>Page</code> struct describes how page data will be stored in memory.
-But what about persistent storage? We can address that by creating a
-<code>save</code> method on <code>Page</code>:
-</p>
-
-<pre>
-!srcextract.bin -src=part1.go -name=save
-</pre>
-
-<p>
-This method's signature reads: "This is a method named <code>save</code> that
-takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes
-no parameters, and returns a value of type <code>os.Error</code>."
-</p>
-
-<p>
-This method will save the <code>Page</code>'s <code>Body</code> to a text
-file. For simplicity, we will use the <code>Title</code> as the file name.
-</p>
-
-<p>
-The <code>save</code> method returns an <code>os.Error</code> value because
-that is the return type of <code>WriteFile</code> (a standard library function
-that writes a byte slice to a file). The <code>save</code> method returns the
-error value, to let the application handle it should anything go wrong while
-writing the file. If all goes well, <code>Page.save()</code> will return
-<code>nil</code> (the zero-value for pointers, interfaces, and some other
-types).
-</p>
-
-<p>
-The octal integer constant <code>0600</code>, passed as the third parameter to
-<code>WriteFile</code>, indicates that the file should be created with
-read-write permissions for the current user only. (See the Unix man page
-<code>open(2)</code> for details.)
-</p>
-
-<p>
-We will want to load pages, too:
-</p>
-
-<pre>
-!srcextract.bin -src=part1-noerror.go -name=loadPage
-</pre>
-
-<p>
-The function <code>loadPage</code> constructs the file name from
-<code>Title</code>, reads the file's contents into a new
-<code>Page</code>, and returns a pointer to that new <code>page</code>.
-</p>
-
-<p>
-Functions can return multiple values. The standard library function
-<code>io.ReadFile</code> returns <code>[]byte</code> and <code>os.Error</code>.
-In <code>loadPage</code>, error isn't being handled yet; the "blank identifier"
-represented by the underscore (<code>_</code>) symbol is used to throw away the
-error return value (in essence, assigning the value to nothing).
-</p>
-
-<p>
-But what happens if <code>ReadFile</code> encounters an error? For example,
-the file might not exist. We should not ignore such errors. Let's modify the
-function to return <code>*Page</code> and <code>os.Error</code>.
-</p>
-
-<pre>
-!srcextract.bin -src=part1.go -name=loadPage
-</pre>
-
-<p>
-Callers of this function can now check the second parameter; if it is
-<code>nil</code> then it has successfully loaded a Page. If not, it will be an
-<code>os.Error</code> that can be handled by the caller (see the <a
-href="http://golang.org/pkg/os/#Error">os package documentation</a> for
-details).
-</p>
-
-<p>
-At this point we have a simple data structure and the ability to save to and
-load from a file. Let's write a <code>main</code> function to test what we've
-written:
-</p>
-
-<pre>
-!srcextract.bin -src=part1.go -name=main
-</pre>
-
-<p>
-After compiling and executing this code, a file named <code>TestPage.txt</code>
-would be created, containing the contents of <code>p1</code>. The file would
-then be read into the struct <code>p2</code>, and its <code>Body</code> element
-printed to the screen.
-</p>
-
-<p>
-You can compile and run the program like this:
-</p>
-
-<pre>
-$ 8g wiki.go
-$ 8l wiki.8
-$ ./8.out
-This is a sample page.
-</pre>
-
-<p>
-(The <code>8g</code> and <code>8l</code> commands are applicable to
-<code>GOARCH=386</code>. If you're on an <code>amd64</code> system,
-substitute 6's for the 8's.)
-</p>
-
-<p>
-<a href="part1.go">Click here to view the code we've written so far.</a>
-</p>
-
-<h2>Introducing the <code>http</code> package (an interlude)</h2>
-
-<p>
-Here's a full working example of a simple web server:
-</p>
-
-<pre>
-!htmlify.bin < http-sample.go
-</pre>
-
-<p>
-The <code>main</code> function begins with a call to
-<code>http.HandleFunc</code>, which tells the <code>http</code> package to
-handle all requests to the web root (<code>"/"</code>) with
-<code>handler</code>.
-</p>
-
-<p>
-It then calls <code>http.ListenAndServe</code>, specifying that it should
-listen on port 8080 on any interface (<code>":8080"</code>). (Don't
-worry about its second parameter, <code>nil</code>, for now.)
-This function will block until the program is terminated.
-</p>
-
-<p>
-The function <code>handler</code> is of the type <code>http.HandlerFunc</code>.
-It takes an <code>http.ResponseWriter</code> and an <code>http.Request</code> as
-its arguments.
-</p>
-
-<p>
-An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing
-to it, we send data to the HTTP client.
-</p>
-
-<p>
-An <code>http.Request</code> is a data structure that represents the client
-HTTP request. The string <code>r.URL.Path</code> is the path component
-of the request URL. The trailing <code>[1:]</code> means
-"create a sub-slice of <code>Path</code> from the 1st character to the end."
-This drops the leading "/" from the path name.
-</p>
-
-<p>
-If you run this program and access the URL:
-</p>
-<pre>http://localhost:8080/monkeys</pre>
-<p>
-the program would present a page containing:
-</p>
-<pre>Hi there, I love monkeys!</pre>
-
-<h2>Using <code>http</code> to serve wiki pages</h2>
-
-<p>
-To use the <code>http</code> package, it must be imported:
-</p>
-
-<pre>
-import (
- "fmt"
- <b>"http"</b>
- "io/ioutil"
- "os"
-)
-</pre>
-
-<p>
-Let's create a handler to view a wiki page:
-</p>
-
-<pre>
-!srcextract.bin -src=part2.go -name=lenPath
-
-!srcextract.bin -src=part2.go -name=viewHandler
-</pre>
-
-<p>
-First, this function extracts the page title from <code>r.URL.Path</code>,
-the path component of the request URL. The global constant
-<code>lenPath</code> is the length of the leading <code>"/view/"</code>
-component of the request path.
-The <code>Path</code> is re-sliced with <code>[lenPath:]</code> to drop the
-first 6 characters of the string. This is because the path will invariably
-begin with <code>"/view/"</code>, which is not part of the page title.
-</p>
-
-<p>
-The function then loads the page data, formats the page with a string of simple
-HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>.
-</p>
-
-<p>
-Again, note the use of <code>_</code> to ignore the <code>os.Error</code>
-return value from <code>loadPage</code>. This is done here for simplicity
-and generally considered bad practice. We will attend to this later.
-</p>
-
-<p>
-To use this handler, we create a <code>main</code> function that
-initializes <code>http</code> using the <code>viewHandler</code> to handle
-any requests under the path <code>/view/</code>.
-</p>
-
-<pre>
-!srcextract.bin -src=part2.go -name=main
-</pre>
-
-<p>
-<a href="part2.go">Click here to view the code we've written so far.</a>
-</p>
-
-<p>
-Let's create some page data (as <code>test.txt</code>), compile our code, and
-try serving a wiki page:
-</p>
-
-<pre>
-$ echo "Hello world" &gt; test.txt
-$ 8g wiki.go
-$ 8l wiki.8
-$ ./8.out
-</pre>
-
-<p>
-With this web server running, a visit to <code><a
-href="http://localhost:8080/view/test">http://localhost:8080/view/test</a></code>
-should show a page titled "test" containing the words "Hello world".
-</p>
-
-<h2>Editing Pages</h2>
-
-<p>
-A wiki is not a wiki without the ability to edit pages. Let's create two new
-handlers: one named <code>editHandler</code> to display an 'edit page' form,
-and the other named <code>saveHandler</code> to save the data entered via the
-form.
-</p>
-
-<p>
-First, we add them to <code>main()</code>:
-</p>
-
-<pre>
-!srcextract.bin -src=final-noclosure.go -name=main
-</pre>
-
-<p>
-The function <code>editHandler</code> loads the page
-(or, if it doesn't exist, create an empty <code>Page</code> struct),
-and displays an HTML form.
-</p>
-
-<pre>
-!srcextract.bin -src=notemplate.go -name=editHandler
-</pre>
-
-<p>
-This function will work fine, but all that hard-coded HTML is ugly.
-Of course, there is a better way.
-</p>
-
-<h2>The <code>template</code> package</h2>
-
-<p>
-The <code>template</code> package is part of the Go standard library. We can
-use <code>template</code> to keep the HTML in a separate file, allowing
-us to change the layout of our edit page without modifying the underlying Go
-code.
-</p>
-
-<p>
-First, we must add <code>template</code> to the list of imports:
-</p>
-
-<pre>
-import (
- "http"
- "io/ioutil"
- "os"
- <b>"template"</b>
-)
-</pre>
-
-<p>
-Let's create a template file containing the HTML form.
-Open a new file named <code>edit.html</code>, and add the following lines:
-</p>
-
-<pre>
-!htmlify.bin < edit.html
-</pre>
-
-<p>
-Modify <code>editHandler</code> to use the template, instead of the hard-coded
-HTML:
-</p>
-
-<pre>
-!srcextract.bin -src=final-noerror.go -name=editHandler
-</pre>
-
-<p>
-The function <code>template.ParseFile</code> will read the contents of
-<code>edit.html</code> and return a <code>*template.Template</code>.
-</p>
-
-<p>
-The method <code>t.Execute</code> replaces all occurrences of
-<code>{Title}</code> and <code>{Body}</code> with the values of
-<code>p.Title</code> and <code>p.Body</code>, and writes the resultant
-HTML to the <code>http.ResponseWriter</code>.
-</p>
-
-<p>
-Note that we've used <code>{Body|html}</code> in the above template.
-The <code>|html</code> part asks the template engine to pass the value
-<code>Body</code> through the <code>html</code> formatter before outputting it,
-which escapes HTML characters (such as replacing <code>&gt;</code> with
-<code>&amp;gt;</code>).
-This will prevent user data from corrupting the form HTML.
-</p>
-
-<p>
-Now that we've removed the <code>fmt.Fprintf</code> statement, we can remove
-<code>"fmt"</code> from the <code>import</code> list.
-</p>
-
-<p>
-While we're working with templates, let's create a template for our
-<code>viewHandler</code> called <code>view.html</code>:
-</p>
-
-<pre>
-!htmlify.bin < view.html
-</pre>
-
-<p>
-Modify <code>viewHandler</code> accordingly:
-</p>
-
-<pre>
-!srcextract.bin -src=final-noerror.go -name=viewHandler
-</pre>
-
-<p>
-Notice that we've used almost exactly the same templating code in both
-handlers. Let's remove this duplication by moving the templating code
-to its own function:
-</p>
-
-<pre>
-!srcextract.bin -src=final-template.go -name=viewHandler
-
-!srcextract.bin -src=final-template.go -name=editHandler
-
-!srcextract.bin -src=final-template.go -name=renderTemplate
-</pre>
-
-<p>
-The handlers are now shorter and simpler.
-</p>
-
-<h2>Handling non-existent pages</h2>
-
-<p>
-What if you visit <code>/view/APageThatDoesntExist</code>? The program will
-crash. This is because it ignores the error return value from
-<code>loadPage</code>. Instead, if the requested Page doesn't exist, it should
-redirect the client to the edit Page so the content may be created:
-</p>
-
-<pre>
-!srcextract.bin -src=final-noclosure.go -name=viewHandler
-</pre>
-
-<p>
-The <code>http.Redirect</code> function adds an HTTP status code of
-<code>http.StatusFound</code> (302) and a <code>Location</code>
-header to the HTTP response.
-</p>
-
-<h2>Saving Pages</h2>
-
-<p>
-The function <code>saveHandler</code> will handle the form submission.
-</p>
-
-<pre>
-!srcextract.bin -src=final-template.go -name=saveHandler
-</pre>
-
-<p>
-The page title (provided in the URL) and the form's only field,
-<code>Body</code>, are stored in a new <code>Page</code>.
-The <code>save()</code> method is then called to write the data to a file,
-and the client is redirected to the <code>/view/</code> page.
-</p>
-
-<p>
-The value returned by <code>FormValue</code> is of type <code>string</code>.
-We must convert that value to <code>[]byte</code> before it will fit into
-the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform
-the conversion.
-</p>
-
-<h2>Error handling</h2>
-
-<p>
-There are several places in our program where errors are being ignored. This
-is bad practice, not least because when an error does occur the program will
-crash. A better solution is to handle the errors and return an error message
-to the user. That way if something does go wrong, the server will continue to
-function and the user will be notified.
-</p>
-
-<p>
-First, let's handle the errors in <code>renderTemplate</code>:
-</p>
-
-<pre>
-!srcextract.bin -src=final-parsetemplate.go -name=renderTemplate
-</pre>
-
-<p>
-The <code>http.Error</code> function sends a specified HTTP response code
-(in this case "Internal Server Error") and error message.
-Already the decision to put this in a separate function is paying off.
-</p>
-
-<p>
-Now let's fix up <code>saveHandler</code>:
-</p>
-
-<pre>
-!srcextract.bin -src=final-noclosure.go -name=saveHandler
-</pre>
-
-<p>
-Any errors that occur during <code>p.save()</code> will be reported
-to the user.
-</p>
-
-<h2>Template caching</h2>
-
-<p>
-There is an inefficiency in this code: <code>renderTemplate</code> calls
-<code>ParseFile</code> every time a page is rendered.
-A better approach would be to call <code>ParseFile</code> once for each
-template at program initialization, and store the resultant
-<code>*Template</code> values in a data structure for later use.
-</p>
-
-<p>
-First we create a global map named <code>templates</code> in which to store
-our <code>*Template</code> values, keyed by <code>string</code>
-(the template name):
-</p>
-
-<pre>
-!srcextract.bin -src=final.go -name=templates
-</pre>
-
-<p>
-Then we create an <code>init</code> function, which will be called before
-<code>main</code> at program initialization. The function
-<code>template.MustParseFile</code> is a convenience wrapper around
-<code>ParseFile</code> that does not return an error code; instead, it panics
-if an error is encountered. A panic is appropriate here; if the templates can't
-be loaded the only sensible thing to do is exit the program.
-</p>
-
-<pre>
-!srcextract.bin -src=final.go -name=init
-</pre>
-
-<p>
-A <code>for</code> loop is used with a <code>range</code> statement to iterate
-over an array constant containing the names of the templates we want parsed.
-If we were to add more templates to our program, we would add their names to
-that array.
-</p>
-
-<p>
-We then modify our <code>renderTemplate</code> function to call
-the <code>Execute</code> method on the appropriate <code>Template</code> from
-<code>templates</code>:
-
-<pre>
-!srcextract.bin -src=final.go -name=renderTemplate
-</pre>
-
-<h2>Validation</h2>
-
-<p>
-As you may have observed, this program has a serious security flaw: a user
-can supply an arbitrary path to be read/written on the server. To mitigate
-this, we can write a function to validate the title with a regular expression.
-</p>
-
-<p>
-First, add <code>"regexp"</code> to the <code>import</code> list.
-Then we can create a global variable to store our validation regexp:
-</p>
-
-<pre>
-!srcextract.bin -src=final-noclosure.go -name=titleValidator
-</pre>
-
-<p>
-The function <code>regexp.MustCompile</code> will parse and compile the
-regular expression, and return a <code>regexp.Regexp</code>.
-<code>MustCompile</code>, like <code>template.MustParseFile</code>,
-is distinct from <code>Compile</code> in that it will panic if
-the expression compilation fails, while <code>Compile</code> returns an
-<code>os.Error</code> as a second parameter.
-</p>
-
-<p>
-Now, let's write a function that extracts the title string from the request
-URL, and tests it against our <code>TitleValidator</code> expression:
-</p>
-
-<pre>
-!srcextract.bin -src=final-noclosure.go -name=getTitle
-</pre>
-
-<p>
-If the title is valid, it will be returned along with a <code>nil</code>
-error value. If the title is invalid, the function will write a
-"404 Not Found" error to the HTTP connection, and return an error to the
-handler.
-</p>
-
-<p>
-Let's put a call to <code>getTitle</code> in each of the handlers:
-</p>
-
-<pre>
-!srcextract.bin -src=final-noclosure.go -name=viewHandler
-
-!srcextract.bin -src=final-noclosure.go -name=editHandler
-
-!srcextract.bin -src=final-noclosure.go -name=saveHandler
-</pre>
-
-<h2>Introducing Function Literals and Closures</h2>
-
-<p>
-Catching the error condition in each handler introduces a lot of repeated code.
-What if we could wrap each of the handlers in a function that does this
-validation and error checking? Go's
-<a href="http://golang.org/doc/go_spec.html#Function_declarations">function
-literals</a> provide a powerful means of abstracting functionality
-that can help us here.
-</p>
-
-<p>
-First, we re-write the function definition of each of the handlers to accept
-a title string:
-</p>
-
-<pre>
-func viewHandler(w http.ResponseWriter, r *http.Request, title string)
-func editHandler(w http.ResponseWriter, r *http.Request, title string)
-func saveHandler(w http.ResponseWriter, r *http.Request, title string)
-</pre>
-
-<p>
-Now let's define a wrapper function that <i>takes a function of the above
-type</i>, and returns a function of type <code>http.HandlerFunc</code>
-(suitable to be passed to the function <code>http.HandleFunc</code>):
-</p>
-
-<pre>
-func makeHandler(fn func (http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- // Here we will extract the page title from the Request,
- // and call the provided handler 'fn'
- }
-}
-</pre>
-
-<p>
-The returned function is called a closure because it encloses values defined
-outside of it. In this case, the variable <code>fn</code> (the single argument
-to <code>makeHandler</code>) is enclosed by the closure. The variable
-<code>fn</code> will be one of our save, edit, or view handlers.
-</p>
-
-<p>
-Now we can take the code from <code>getTitle</code> and use it here
-(with some minor modifications):
-</p>
-
-<pre>
-!srcextract.bin -src=final.go -name=makeHandler
-</pre>
-
-<p>
-The closure returned by <code>makeHandler</code> is a function that takes
-an <code>http.ResponseWriter</code> and <code>http.Request</code> (in other
-words, an <code>http.HandlerFunc</code>).
-The closure extracts the <code>title</code> from the request path, and
-validates it with the <code>TitleValidator</code> regexp. If the
-<code>title</code> is invalid, an error will be written to the
-<code>ResponseWriter</code> using the <code>http.NotFound</code> function.
-If the <code>title</code> is valid, the enclosed handler function
-<code>fn</code> will be called with the <code>ResponseWriter</code>,
-<code>Request</code>, and <code>title</code> as arguments.
-</p>
-
-<p>
-Now we can wrap the handler functions with <code>makeHandler</code> in
-<code>main</code>, before they are registered with the <code>http</code>
-package:
-</p>
-
-<pre>
-!srcextract.bin -src=final.go -name=main
-</pre>
-
-<p>
-Finally we remove the calls to <code>getTitle</code> from the handler functions,
-making them much simpler:
-</p>
-
-<pre>
-!srcextract.bin -src=final.go -name=viewHandler
-
-!srcextract.bin -src=final.go -name=editHandler
-
-!srcextract.bin -src=final.go -name=saveHandler
-</pre>
-
-<h2>Try it out!</h2>
-
-<p>
-<a href="final.go">Click here to view the final code listing.</a>
-</p>
-
-<p>
-Recompile the code, and run the app:
-</p>
-
-<pre>
-$ 8g wiki.go
-$ 8l wiki.8
-$ ./8.out
-</pre>
-
-<p>
-Visiting <a href="http://localhost:8080/view/ANewPage">http://localhost:8080/view/ANewPage</a>
-should present you with the page edit form. You should then be able to
-enter some text, click 'Save', and be redirected to the newly created page.
-</p>
-
-<h2>Other tasks</h2>
-
-<p>
-Here are some simple tasks you might want to tackle on your own:
-</p>
-
-<ul>
-<li>Store templates in <code>tmpl/</code> and page data in <code>data/</code>.
-<li>Add a handler to make the web root redirect to
- <code>/view/FrontPage</code>.</li>
-<li>Spruce up the page templates by making them valid HTML and adding some
- CSS rules.</li>
-<li>Implement inter-page linking by converting instances of
- <code>[PageName]</code> to <br>
- <code>&lt;a href="/view/PageName"&gt;PageName&lt;/a&gt;</code>.
- (hint: you could use <code>regexp.ReplaceAllFunc</code> to do this)
- </li>
-</ul>